From 1c354e7c1f35c969a96bbdf420b6cc2884b712ba Mon Sep 17 00:00:00 2001 From: Moiz Haidry Date: Mon, 1 Jul 2019 10:38:23 -0700 Subject: [PATCH 1/4] Move grpc async, callback and sync implementation to grpc_impl namespace --- BUILD | 10 + BUILD.gn | 10 + CMakeLists.txt | 40 + Makefile | 40 + build.yaml | 10 + gRPC-C++.podspec | 10 + include/grpcpp/channel_impl.h | 13 +- include/grpcpp/generic/generic_stub_impl.h | 41 +- .../impl/codegen/async_generic_service.h | 28 +- include/grpcpp/impl/codegen/async_stream.h | 1102 +-------------- .../grpcpp/impl/codegen/async_stream_impl.h | 1134 ++++++++++++++++ .../grpcpp/impl/codegen/async_unary_call.h | 291 +--- .../impl/codegen/async_unary_call_impl.h | 315 +++++ include/grpcpp/impl/codegen/byte_buffer.h | 19 +- include/grpcpp/impl/codegen/call_op_set.h | 2 +- .../grpcpp/impl/codegen/channel_interface.h | 47 +- include/grpcpp/impl/codegen/client_callback.h | 1003 +------------- .../impl/codegen/client_callback_impl.h | 1067 +++++++++++++++ .../grpcpp/impl/codegen/client_context_impl.h | 52 +- .../grpcpp/impl/codegen/client_unary_call.h | 4 +- .../impl/codegen/completion_queue_impl.h | 17 +- include/grpcpp/impl/codegen/server_callback.h | 1133 +--------------- .../impl/codegen/server_callback_impl.h | 1186 +++++++++++++++++ .../grpcpp/impl/codegen/server_context_impl.h | 54 +- include/grpcpp/impl/codegen/service_type.h | 20 +- include/grpcpp/impl/codegen/sync_stream.h | 914 +------------ .../grpcpp/impl/codegen/sync_stream_impl.h | 944 +++++++++++++ include/grpcpp/support/async_stream_impl.h | 24 + .../grpcpp/support/async_unary_call_impl.h | 24 + include/grpcpp/support/client_callback_impl.h | 24 + include/grpcpp/support/server_callback_impl.h | 24 + include/grpcpp/support/sync_stream_impl.h | 24 + src/compiler/cpp_generator.cc | 121 +- src/cpp/client/generic_stub.cc | 30 +- src/cpp/server/async_generic_service.cc | 4 +- .../health/default_health_check_service.h | 1 + src/cpp/server/server_builder.cc | 15 +- src/cpp/server/server_context.cc | 11 +- test/cpp/codegen/compiler_test_golden | 37 +- tools/doxygen/Doxyfile.c++ | 10 + tools/doxygen/Doxyfile.c++.internal | 10 + .../generated/sources_and_headers.json | 20 + 42 files changed, 5258 insertions(+), 4627 deletions(-) create mode 100644 include/grpcpp/impl/codegen/async_stream_impl.h create mode 100644 include/grpcpp/impl/codegen/async_unary_call_impl.h create mode 100644 include/grpcpp/impl/codegen/client_callback_impl.h create mode 100644 include/grpcpp/impl/codegen/server_callback_impl.h create mode 100644 include/grpcpp/impl/codegen/sync_stream_impl.h create mode 100644 include/grpcpp/support/async_stream_impl.h create mode 100644 include/grpcpp/support/async_unary_call_impl.h create mode 100644 include/grpcpp/support/client_callback_impl.h create mode 100644 include/grpcpp/support/server_callback_impl.h create mode 100644 include/grpcpp/support/sync_stream_impl.h diff --git a/BUILD b/BUILD index 87d3b978358..b9a47e6e776 100644 --- a/BUILD +++ b/BUILD @@ -268,11 +268,14 @@ GRPCXX_PUBLIC_HDRS = [ "include/grpcpp/server_posix.h", "include/grpcpp/server_posix_impl.h", "include/grpcpp/support/async_stream.h", + "include/grpcpp/support/async_stream_impl.h", "include/grpcpp/support/async_unary_call.h", + "include/grpcpp/support/async_unary_call_impl.h", "include/grpcpp/support/byte_buffer.h", "include/grpcpp/support/channel_arguments.h", "include/grpcpp/support/channel_arguments_impl.h", "include/grpcpp/support/client_callback.h", + "include/grpcpp/support/client_callback_impl.h", "include/grpcpp/support/client_interceptor.h", "include/grpcpp/support/config.h", "include/grpcpp/support/interceptor.h", @@ -280,6 +283,7 @@ GRPCXX_PUBLIC_HDRS = [ "include/grpcpp/support/proto_buffer_reader.h", "include/grpcpp/support/proto_buffer_writer.h", "include/grpcpp/support/server_callback.h", + "include/grpcpp/support/server_callback_impl.h", "include/grpcpp/support/server_interceptor.h", "include/grpcpp/support/slice.h", "include/grpcpp/support/status.h", @@ -287,6 +291,7 @@ GRPCXX_PUBLIC_HDRS = [ "include/grpcpp/support/string_ref.h", "include/grpcpp/support/stub_options.h", "include/grpcpp/support/sync_stream.h", + "include/grpcpp/support/sync_stream_impl.h", "include/grpcpp/support/time.h", "include/grpcpp/support/validate_service_config.h", ] @@ -2155,7 +2160,9 @@ grpc_cc_library( "include/grpc++/impl/codegen/time.h", "include/grpcpp/impl/codegen/async_generic_service.h", "include/grpcpp/impl/codegen/async_stream.h", + "include/grpcpp/impl/codegen/async_stream_impl.h", "include/grpcpp/impl/codegen/async_unary_call.h", + "include/grpcpp/impl/codegen/async_unary_call_impl.h", "include/grpcpp/impl/codegen/byte_buffer.h", "include/grpcpp/impl/codegen/call.h", "include/grpcpp/impl/codegen/call_hook.h", @@ -2164,6 +2171,7 @@ grpc_cc_library( "include/grpcpp/impl/codegen/callback_common.h", "include/grpcpp/impl/codegen/channel_interface.h", "include/grpcpp/impl/codegen/client_callback.h", + "include/grpcpp/impl/codegen/client_callback_impl.h", "include/grpcpp/impl/codegen/client_context.h", "include/grpcpp/impl/codegen/client_context_impl.h", "include/grpcpp/impl/codegen/client_interceptor.h", @@ -2186,6 +2194,7 @@ grpc_cc_library( "include/grpcpp/impl/codegen/security/auth_context.h", "include/grpcpp/impl/codegen/serialization_traits.h", "include/grpcpp/impl/codegen/server_callback.h", + "include/grpcpp/impl/codegen/server_callback_impl.h", "include/grpcpp/impl/codegen/server_context.h", "include/grpcpp/impl/codegen/server_context_impl.h", "include/grpcpp/impl/codegen/server_interceptor.h", @@ -2197,6 +2206,7 @@ grpc_cc_library( "include/grpcpp/impl/codegen/string_ref.h", "include/grpcpp/impl/codegen/stub_options.h", "include/grpcpp/impl/codegen/sync_stream.h", + "include/grpcpp/impl/codegen/sync_stream_impl.h", "include/grpcpp/impl/codegen/time.h", ], deps = [ diff --git a/BUILD.gn b/BUILD.gn index fc9fa8dc3d0..05e4da5561f 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1045,7 +1045,9 @@ config("grpc_config") { "include/grpcpp/impl/client_unary_call.h", "include/grpcpp/impl/codegen/async_generic_service.h", "include/grpcpp/impl/codegen/async_stream.h", + "include/grpcpp/impl/codegen/async_stream_impl.h", "include/grpcpp/impl/codegen/async_unary_call.h", + "include/grpcpp/impl/codegen/async_unary_call_impl.h", "include/grpcpp/impl/codegen/byte_buffer.h", "include/grpcpp/impl/codegen/call.h", "include/grpcpp/impl/codegen/call_hook.h", @@ -1054,6 +1056,7 @@ config("grpc_config") { "include/grpcpp/impl/codegen/callback_common.h", "include/grpcpp/impl/codegen/channel_interface.h", "include/grpcpp/impl/codegen/client_callback.h", + "include/grpcpp/impl/codegen/client_callback_impl.h", "include/grpcpp/impl/codegen/client_context.h", "include/grpcpp/impl/codegen/client_context_impl.h", "include/grpcpp/impl/codegen/client_interceptor.h", @@ -1082,6 +1085,7 @@ config("grpc_config") { "include/grpcpp/impl/codegen/security/auth_context.h", "include/grpcpp/impl/codegen/serialization_traits.h", "include/grpcpp/impl/codegen/server_callback.h", + "include/grpcpp/impl/codegen/server_callback_impl.h", "include/grpcpp/impl/codegen/server_context.h", "include/grpcpp/impl/codegen/server_context_impl.h", "include/grpcpp/impl/codegen/server_interceptor.h", @@ -1094,6 +1098,7 @@ config("grpc_config") { "include/grpcpp/impl/codegen/stub_options.h", "include/grpcpp/impl/codegen/sync.h", "include/grpcpp/impl/codegen/sync_stream.h", + "include/grpcpp/impl/codegen/sync_stream_impl.h", "include/grpcpp/impl/codegen/time.h", "include/grpcpp/impl/grpc_library.h", "include/grpcpp/impl/method_handler_impl.h", @@ -1123,11 +1128,14 @@ config("grpc_config") { "include/grpcpp/server_posix.h", "include/grpcpp/server_posix_impl.h", "include/grpcpp/support/async_stream.h", + "include/grpcpp/support/async_stream_impl.h", "include/grpcpp/support/async_unary_call.h", + "include/grpcpp/support/async_unary_call_impl.h", "include/grpcpp/support/byte_buffer.h", "include/grpcpp/support/channel_arguments.h", "include/grpcpp/support/channel_arguments_impl.h", "include/grpcpp/support/client_callback.h", + "include/grpcpp/support/client_callback_impl.h", "include/grpcpp/support/client_interceptor.h", "include/grpcpp/support/config.h", "include/grpcpp/support/interceptor.h", @@ -1135,6 +1143,7 @@ config("grpc_config") { "include/grpcpp/support/proto_buffer_reader.h", "include/grpcpp/support/proto_buffer_writer.h", "include/grpcpp/support/server_callback.h", + "include/grpcpp/support/server_callback_impl.h", "include/grpcpp/support/server_interceptor.h", "include/grpcpp/support/slice.h", "include/grpcpp/support/status.h", @@ -1142,6 +1151,7 @@ config("grpc_config") { "include/grpcpp/support/string_ref.h", "include/grpcpp/support/stub_options.h", "include/grpcpp/support/sync_stream.h", + "include/grpcpp/support/sync_stream_impl.h", "include/grpcpp/support/time.h", "include/grpcpp/support/validate_service_config.h", "src/core/ext/transport/inproc/inproc_transport.h", diff --git a/CMakeLists.txt b/CMakeLists.txt index 713fc16028f..c47684addac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3205,11 +3205,14 @@ foreach(_hdr include/grpcpp/server_posix.h include/grpcpp/server_posix_impl.h include/grpcpp/support/async_stream.h + include/grpcpp/support/async_stream_impl.h include/grpcpp/support/async_unary_call.h + include/grpcpp/support/async_unary_call_impl.h include/grpcpp/support/byte_buffer.h include/grpcpp/support/channel_arguments.h include/grpcpp/support/channel_arguments_impl.h include/grpcpp/support/client_callback.h + include/grpcpp/support/client_callback_impl.h include/grpcpp/support/client_interceptor.h include/grpcpp/support/config.h include/grpcpp/support/interceptor.h @@ -3217,6 +3220,7 @@ foreach(_hdr include/grpcpp/support/proto_buffer_reader.h include/grpcpp/support/proto_buffer_writer.h include/grpcpp/support/server_callback.h + include/grpcpp/support/server_callback_impl.h include/grpcpp/support/server_interceptor.h include/grpcpp/support/slice.h include/grpcpp/support/status.h @@ -3224,6 +3228,7 @@ foreach(_hdr include/grpcpp/support/string_ref.h include/grpcpp/support/stub_options.h include/grpcpp/support/sync_stream.h + include/grpcpp/support/sync_stream_impl.h include/grpcpp/support/time.h include/grpcpp/support/validate_service_config.h include/grpc/support/alloc.h @@ -3309,7 +3314,9 @@ foreach(_hdr include/grpc++/impl/codegen/time.h include/grpcpp/impl/codegen/async_generic_service.h include/grpcpp/impl/codegen/async_stream.h + include/grpcpp/impl/codegen/async_stream_impl.h include/grpcpp/impl/codegen/async_unary_call.h + include/grpcpp/impl/codegen/async_unary_call_impl.h include/grpcpp/impl/codegen/byte_buffer.h include/grpcpp/impl/codegen/call.h include/grpcpp/impl/codegen/call_hook.h @@ -3318,6 +3325,7 @@ foreach(_hdr include/grpcpp/impl/codegen/callback_common.h include/grpcpp/impl/codegen/channel_interface.h include/grpcpp/impl/codegen/client_callback.h + include/grpcpp/impl/codegen/client_callback_impl.h include/grpcpp/impl/codegen/client_context.h include/grpcpp/impl/codegen/client_context_impl.h include/grpcpp/impl/codegen/client_interceptor.h @@ -3340,6 +3348,7 @@ foreach(_hdr include/grpcpp/impl/codegen/security/auth_context.h include/grpcpp/impl/codegen/serialization_traits.h include/grpcpp/impl/codegen/server_callback.h + include/grpcpp/impl/codegen/server_callback_impl.h include/grpcpp/impl/codegen/server_context.h include/grpcpp/impl/codegen/server_context_impl.h include/grpcpp/impl/codegen/server_interceptor.h @@ -3351,6 +3360,7 @@ foreach(_hdr include/grpcpp/impl/codegen/string_ref.h include/grpcpp/impl/codegen/stub_options.h include/grpcpp/impl/codegen/sync_stream.h + include/grpcpp/impl/codegen/sync_stream_impl.h include/grpcpp/impl/codegen/time.h include/grpcpp/impl/codegen/sync.h include/grpc++/impl/codegen/proto_utils.h @@ -3827,11 +3837,14 @@ foreach(_hdr include/grpcpp/server_posix.h include/grpcpp/server_posix_impl.h include/grpcpp/support/async_stream.h + include/grpcpp/support/async_stream_impl.h include/grpcpp/support/async_unary_call.h + include/grpcpp/support/async_unary_call_impl.h include/grpcpp/support/byte_buffer.h include/grpcpp/support/channel_arguments.h include/grpcpp/support/channel_arguments_impl.h include/grpcpp/support/client_callback.h + include/grpcpp/support/client_callback_impl.h include/grpcpp/support/client_interceptor.h include/grpcpp/support/config.h include/grpcpp/support/interceptor.h @@ -3839,6 +3852,7 @@ foreach(_hdr include/grpcpp/support/proto_buffer_reader.h include/grpcpp/support/proto_buffer_writer.h include/grpcpp/support/server_callback.h + include/grpcpp/support/server_callback_impl.h include/grpcpp/support/server_interceptor.h include/grpcpp/support/slice.h include/grpcpp/support/status.h @@ -3846,6 +3860,7 @@ foreach(_hdr include/grpcpp/support/string_ref.h include/grpcpp/support/stub_options.h include/grpcpp/support/sync_stream.h + include/grpcpp/support/sync_stream_impl.h include/grpcpp/support/time.h include/grpcpp/support/validate_service_config.h include/grpc/support/alloc.h @@ -3931,7 +3946,9 @@ foreach(_hdr include/grpc++/impl/codegen/time.h include/grpcpp/impl/codegen/async_generic_service.h include/grpcpp/impl/codegen/async_stream.h + include/grpcpp/impl/codegen/async_stream_impl.h include/grpcpp/impl/codegen/async_unary_call.h + include/grpcpp/impl/codegen/async_unary_call_impl.h include/grpcpp/impl/codegen/byte_buffer.h include/grpcpp/impl/codegen/call.h include/grpcpp/impl/codegen/call_hook.h @@ -3940,6 +3957,7 @@ foreach(_hdr include/grpcpp/impl/codegen/callback_common.h include/grpcpp/impl/codegen/channel_interface.h include/grpcpp/impl/codegen/client_callback.h + include/grpcpp/impl/codegen/client_callback_impl.h include/grpcpp/impl/codegen/client_context.h include/grpcpp/impl/codegen/client_context_impl.h include/grpcpp/impl/codegen/client_interceptor.h @@ -3962,6 +3980,7 @@ foreach(_hdr include/grpcpp/impl/codegen/security/auth_context.h include/grpcpp/impl/codegen/serialization_traits.h include/grpcpp/impl/codegen/server_callback.h + include/grpcpp/impl/codegen/server_callback_impl.h include/grpcpp/impl/codegen/server_context.h include/grpcpp/impl/codegen/server_context_impl.h include/grpcpp/impl/codegen/server_interceptor.h @@ -3973,6 +3992,7 @@ foreach(_hdr include/grpcpp/impl/codegen/string_ref.h include/grpcpp/impl/codegen/stub_options.h include/grpcpp/impl/codegen/sync_stream.h + include/grpcpp/impl/codegen/sync_stream_impl.h include/grpcpp/impl/codegen/time.h include/grpcpp/impl/codegen/sync.h include/grpc/census.h @@ -4368,7 +4388,9 @@ foreach(_hdr include/grpc++/impl/codegen/time.h include/grpcpp/impl/codegen/async_generic_service.h include/grpcpp/impl/codegen/async_stream.h + include/grpcpp/impl/codegen/async_stream_impl.h include/grpcpp/impl/codegen/async_unary_call.h + include/grpcpp/impl/codegen/async_unary_call_impl.h include/grpcpp/impl/codegen/byte_buffer.h include/grpcpp/impl/codegen/call.h include/grpcpp/impl/codegen/call_hook.h @@ -4377,6 +4399,7 @@ foreach(_hdr include/grpcpp/impl/codegen/callback_common.h include/grpcpp/impl/codegen/channel_interface.h include/grpcpp/impl/codegen/client_callback.h + include/grpcpp/impl/codegen/client_callback_impl.h include/grpcpp/impl/codegen/client_context.h include/grpcpp/impl/codegen/client_context_impl.h include/grpcpp/impl/codegen/client_interceptor.h @@ -4399,6 +4422,7 @@ foreach(_hdr include/grpcpp/impl/codegen/security/auth_context.h include/grpcpp/impl/codegen/serialization_traits.h include/grpcpp/impl/codegen/server_callback.h + include/grpcpp/impl/codegen/server_callback_impl.h include/grpcpp/impl/codegen/server_context.h include/grpcpp/impl/codegen/server_context_impl.h include/grpcpp/impl/codegen/server_interceptor.h @@ -4410,6 +4434,7 @@ foreach(_hdr include/grpcpp/impl/codegen/string_ref.h include/grpcpp/impl/codegen/stub_options.h include/grpcpp/impl/codegen/sync_stream.h + include/grpcpp/impl/codegen/sync_stream_impl.h include/grpcpp/impl/codegen/time.h include/grpc/impl/codegen/byte_buffer.h include/grpc/impl/codegen/byte_buffer_reader.h @@ -4569,7 +4594,9 @@ foreach(_hdr include/grpc++/impl/codegen/time.h include/grpcpp/impl/codegen/async_generic_service.h include/grpcpp/impl/codegen/async_stream.h + include/grpcpp/impl/codegen/async_stream_impl.h include/grpcpp/impl/codegen/async_unary_call.h + include/grpcpp/impl/codegen/async_unary_call_impl.h include/grpcpp/impl/codegen/byte_buffer.h include/grpcpp/impl/codegen/call.h include/grpcpp/impl/codegen/call_hook.h @@ -4578,6 +4605,7 @@ foreach(_hdr include/grpcpp/impl/codegen/callback_common.h include/grpcpp/impl/codegen/channel_interface.h include/grpcpp/impl/codegen/client_callback.h + include/grpcpp/impl/codegen/client_callback_impl.h include/grpcpp/impl/codegen/client_context.h include/grpcpp/impl/codegen/client_context_impl.h include/grpcpp/impl/codegen/client_interceptor.h @@ -4600,6 +4628,7 @@ foreach(_hdr include/grpcpp/impl/codegen/security/auth_context.h include/grpcpp/impl/codegen/serialization_traits.h include/grpcpp/impl/codegen/server_callback.h + include/grpcpp/impl/codegen/server_callback_impl.h include/grpcpp/impl/codegen/server_context.h include/grpcpp/impl/codegen/server_context_impl.h include/grpcpp/impl/codegen/server_interceptor.h @@ -4611,6 +4640,7 @@ foreach(_hdr include/grpcpp/impl/codegen/string_ref.h include/grpcpp/impl/codegen/stub_options.h include/grpcpp/impl/codegen/sync_stream.h + include/grpcpp/impl/codegen/sync_stream_impl.h include/grpcpp/impl/codegen/time.h include/grpc/impl/codegen/byte_buffer.h include/grpc/impl/codegen/byte_buffer_reader.h @@ -4827,11 +4857,14 @@ foreach(_hdr include/grpcpp/server_posix.h include/grpcpp/server_posix_impl.h include/grpcpp/support/async_stream.h + include/grpcpp/support/async_stream_impl.h include/grpcpp/support/async_unary_call.h + include/grpcpp/support/async_unary_call_impl.h include/grpcpp/support/byte_buffer.h include/grpcpp/support/channel_arguments.h include/grpcpp/support/channel_arguments_impl.h include/grpcpp/support/client_callback.h + include/grpcpp/support/client_callback_impl.h include/grpcpp/support/client_interceptor.h include/grpcpp/support/config.h include/grpcpp/support/interceptor.h @@ -4839,6 +4872,7 @@ foreach(_hdr include/grpcpp/support/proto_buffer_reader.h include/grpcpp/support/proto_buffer_writer.h include/grpcpp/support/server_callback.h + include/grpcpp/support/server_callback_impl.h include/grpcpp/support/server_interceptor.h include/grpcpp/support/slice.h include/grpcpp/support/status.h @@ -4846,6 +4880,7 @@ foreach(_hdr include/grpcpp/support/string_ref.h include/grpcpp/support/stub_options.h include/grpcpp/support/sync_stream.h + include/grpcpp/support/sync_stream_impl.h include/grpcpp/support/time.h include/grpcpp/support/validate_service_config.h include/grpc/support/alloc.h @@ -4931,7 +4966,9 @@ foreach(_hdr include/grpc++/impl/codegen/time.h include/grpcpp/impl/codegen/async_generic_service.h include/grpcpp/impl/codegen/async_stream.h + include/grpcpp/impl/codegen/async_stream_impl.h include/grpcpp/impl/codegen/async_unary_call.h + include/grpcpp/impl/codegen/async_unary_call_impl.h include/grpcpp/impl/codegen/byte_buffer.h include/grpcpp/impl/codegen/call.h include/grpcpp/impl/codegen/call_hook.h @@ -4940,6 +4977,7 @@ foreach(_hdr include/grpcpp/impl/codegen/callback_common.h include/grpcpp/impl/codegen/channel_interface.h include/grpcpp/impl/codegen/client_callback.h + include/grpcpp/impl/codegen/client_callback_impl.h include/grpcpp/impl/codegen/client_context.h include/grpcpp/impl/codegen/client_context_impl.h include/grpcpp/impl/codegen/client_interceptor.h @@ -4962,6 +5000,7 @@ foreach(_hdr include/grpcpp/impl/codegen/security/auth_context.h include/grpcpp/impl/codegen/serialization_traits.h include/grpcpp/impl/codegen/server_callback.h + include/grpcpp/impl/codegen/server_callback_impl.h include/grpcpp/impl/codegen/server_context.h include/grpcpp/impl/codegen/server_context_impl.h include/grpcpp/impl/codegen/server_interceptor.h @@ -4973,6 +5012,7 @@ foreach(_hdr include/grpcpp/impl/codegen/string_ref.h include/grpcpp/impl/codegen/stub_options.h include/grpcpp/impl/codegen/sync_stream.h + include/grpcpp/impl/codegen/sync_stream_impl.h include/grpcpp/impl/codegen/time.h include/grpcpp/impl/codegen/sync.h ) diff --git a/Makefile b/Makefile index 15d4ede0670..44c428afdb1 100644 --- a/Makefile +++ b/Makefile @@ -5582,11 +5582,14 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/server_posix.h \ include/grpcpp/server_posix_impl.h \ include/grpcpp/support/async_stream.h \ + include/grpcpp/support/async_stream_impl.h \ include/grpcpp/support/async_unary_call.h \ + include/grpcpp/support/async_unary_call_impl.h \ include/grpcpp/support/byte_buffer.h \ include/grpcpp/support/channel_arguments.h \ include/grpcpp/support/channel_arguments_impl.h \ include/grpcpp/support/client_callback.h \ + include/grpcpp/support/client_callback_impl.h \ include/grpcpp/support/client_interceptor.h \ include/grpcpp/support/config.h \ include/grpcpp/support/interceptor.h \ @@ -5594,6 +5597,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/support/proto_buffer_reader.h \ include/grpcpp/support/proto_buffer_writer.h \ include/grpcpp/support/server_callback.h \ + include/grpcpp/support/server_callback_impl.h \ include/grpcpp/support/server_interceptor.h \ include/grpcpp/support/slice.h \ include/grpcpp/support/status.h \ @@ -5601,6 +5605,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/support/string_ref.h \ include/grpcpp/support/stub_options.h \ include/grpcpp/support/sync_stream.h \ + include/grpcpp/support/sync_stream_impl.h \ include/grpcpp/support/time.h \ include/grpcpp/support/validate_service_config.h \ include/grpc/support/alloc.h \ @@ -5686,7 +5691,9 @@ PUBLIC_HEADERS_CXX += \ include/grpc++/impl/codegen/time.h \ include/grpcpp/impl/codegen/async_generic_service.h \ include/grpcpp/impl/codegen/async_stream.h \ + include/grpcpp/impl/codegen/async_stream_impl.h \ include/grpcpp/impl/codegen/async_unary_call.h \ + include/grpcpp/impl/codegen/async_unary_call_impl.h \ include/grpcpp/impl/codegen/byte_buffer.h \ include/grpcpp/impl/codegen/call.h \ include/grpcpp/impl/codegen/call_hook.h \ @@ -5695,6 +5702,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/callback_common.h \ include/grpcpp/impl/codegen/channel_interface.h \ include/grpcpp/impl/codegen/client_callback.h \ + include/grpcpp/impl/codegen/client_callback_impl.h \ include/grpcpp/impl/codegen/client_context.h \ include/grpcpp/impl/codegen/client_context_impl.h \ include/grpcpp/impl/codegen/client_interceptor.h \ @@ -5717,6 +5725,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/security/auth_context.h \ include/grpcpp/impl/codegen/serialization_traits.h \ include/grpcpp/impl/codegen/server_callback.h \ + include/grpcpp/impl/codegen/server_callback_impl.h \ include/grpcpp/impl/codegen/server_context.h \ include/grpcpp/impl/codegen/server_context_impl.h \ include/grpcpp/impl/codegen/server_interceptor.h \ @@ -5728,6 +5737,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/string_ref.h \ include/grpcpp/impl/codegen/stub_options.h \ include/grpcpp/impl/codegen/sync_stream.h \ + include/grpcpp/impl/codegen/sync_stream_impl.h \ include/grpcpp/impl/codegen/time.h \ include/grpcpp/impl/codegen/sync.h \ include/grpc++/impl/codegen/proto_utils.h \ @@ -6212,11 +6222,14 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/server_posix.h \ include/grpcpp/server_posix_impl.h \ include/grpcpp/support/async_stream.h \ + include/grpcpp/support/async_stream_impl.h \ include/grpcpp/support/async_unary_call.h \ + include/grpcpp/support/async_unary_call_impl.h \ include/grpcpp/support/byte_buffer.h \ include/grpcpp/support/channel_arguments.h \ include/grpcpp/support/channel_arguments_impl.h \ include/grpcpp/support/client_callback.h \ + include/grpcpp/support/client_callback_impl.h \ include/grpcpp/support/client_interceptor.h \ include/grpcpp/support/config.h \ include/grpcpp/support/interceptor.h \ @@ -6224,6 +6237,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/support/proto_buffer_reader.h \ include/grpcpp/support/proto_buffer_writer.h \ include/grpcpp/support/server_callback.h \ + include/grpcpp/support/server_callback_impl.h \ include/grpcpp/support/server_interceptor.h \ include/grpcpp/support/slice.h \ include/grpcpp/support/status.h \ @@ -6231,6 +6245,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/support/string_ref.h \ include/grpcpp/support/stub_options.h \ include/grpcpp/support/sync_stream.h \ + include/grpcpp/support/sync_stream_impl.h \ include/grpcpp/support/time.h \ include/grpcpp/support/validate_service_config.h \ include/grpc/support/alloc.h \ @@ -6316,7 +6331,9 @@ PUBLIC_HEADERS_CXX += \ include/grpc++/impl/codegen/time.h \ include/grpcpp/impl/codegen/async_generic_service.h \ include/grpcpp/impl/codegen/async_stream.h \ + include/grpcpp/impl/codegen/async_stream_impl.h \ include/grpcpp/impl/codegen/async_unary_call.h \ + include/grpcpp/impl/codegen/async_unary_call_impl.h \ include/grpcpp/impl/codegen/byte_buffer.h \ include/grpcpp/impl/codegen/call.h \ include/grpcpp/impl/codegen/call_hook.h \ @@ -6325,6 +6342,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/callback_common.h \ include/grpcpp/impl/codegen/channel_interface.h \ include/grpcpp/impl/codegen/client_callback.h \ + include/grpcpp/impl/codegen/client_callback_impl.h \ include/grpcpp/impl/codegen/client_context.h \ include/grpcpp/impl/codegen/client_context_impl.h \ include/grpcpp/impl/codegen/client_interceptor.h \ @@ -6347,6 +6365,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/security/auth_context.h \ include/grpcpp/impl/codegen/serialization_traits.h \ include/grpcpp/impl/codegen/server_callback.h \ + include/grpcpp/impl/codegen/server_callback_impl.h \ include/grpcpp/impl/codegen/server_context.h \ include/grpcpp/impl/codegen/server_context_impl.h \ include/grpcpp/impl/codegen/server_interceptor.h \ @@ -6358,6 +6377,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/string_ref.h \ include/grpcpp/impl/codegen/stub_options.h \ include/grpcpp/impl/codegen/sync_stream.h \ + include/grpcpp/impl/codegen/sync_stream_impl.h \ include/grpcpp/impl/codegen/time.h \ include/grpcpp/impl/codegen/sync.h \ include/grpc/census.h \ @@ -6725,7 +6745,9 @@ PUBLIC_HEADERS_CXX += \ include/grpc++/impl/codegen/time.h \ include/grpcpp/impl/codegen/async_generic_service.h \ include/grpcpp/impl/codegen/async_stream.h \ + include/grpcpp/impl/codegen/async_stream_impl.h \ include/grpcpp/impl/codegen/async_unary_call.h \ + include/grpcpp/impl/codegen/async_unary_call_impl.h \ include/grpcpp/impl/codegen/byte_buffer.h \ include/grpcpp/impl/codegen/call.h \ include/grpcpp/impl/codegen/call_hook.h \ @@ -6734,6 +6756,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/callback_common.h \ include/grpcpp/impl/codegen/channel_interface.h \ include/grpcpp/impl/codegen/client_callback.h \ + include/grpcpp/impl/codegen/client_callback_impl.h \ include/grpcpp/impl/codegen/client_context.h \ include/grpcpp/impl/codegen/client_context_impl.h \ include/grpcpp/impl/codegen/client_interceptor.h \ @@ -6756,6 +6779,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/security/auth_context.h \ include/grpcpp/impl/codegen/serialization_traits.h \ include/grpcpp/impl/codegen/server_callback.h \ + include/grpcpp/impl/codegen/server_callback_impl.h \ include/grpcpp/impl/codegen/server_context.h \ include/grpcpp/impl/codegen/server_context_impl.h \ include/grpcpp/impl/codegen/server_interceptor.h \ @@ -6767,6 +6791,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/string_ref.h \ include/grpcpp/impl/codegen/stub_options.h \ include/grpcpp/impl/codegen/sync_stream.h \ + include/grpcpp/impl/codegen/sync_stream_impl.h \ include/grpcpp/impl/codegen/time.h \ include/grpc/impl/codegen/byte_buffer.h \ include/grpc/impl/codegen/byte_buffer_reader.h \ @@ -6897,7 +6922,9 @@ PUBLIC_HEADERS_CXX += \ include/grpc++/impl/codegen/time.h \ include/grpcpp/impl/codegen/async_generic_service.h \ include/grpcpp/impl/codegen/async_stream.h \ + include/grpcpp/impl/codegen/async_stream_impl.h \ include/grpcpp/impl/codegen/async_unary_call.h \ + include/grpcpp/impl/codegen/async_unary_call_impl.h \ include/grpcpp/impl/codegen/byte_buffer.h \ include/grpcpp/impl/codegen/call.h \ include/grpcpp/impl/codegen/call_hook.h \ @@ -6906,6 +6933,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/callback_common.h \ include/grpcpp/impl/codegen/channel_interface.h \ include/grpcpp/impl/codegen/client_callback.h \ + include/grpcpp/impl/codegen/client_callback_impl.h \ include/grpcpp/impl/codegen/client_context.h \ include/grpcpp/impl/codegen/client_context_impl.h \ include/grpcpp/impl/codegen/client_interceptor.h \ @@ -6928,6 +6956,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/security/auth_context.h \ include/grpcpp/impl/codegen/serialization_traits.h \ include/grpcpp/impl/codegen/server_callback.h \ + include/grpcpp/impl/codegen/server_callback_impl.h \ include/grpcpp/impl/codegen/server_context.h \ include/grpcpp/impl/codegen/server_context_impl.h \ include/grpcpp/impl/codegen/server_interceptor.h \ @@ -6939,6 +6968,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/string_ref.h \ include/grpcpp/impl/codegen/stub_options.h \ include/grpcpp/impl/codegen/sync_stream.h \ + include/grpcpp/impl/codegen/sync_stream_impl.h \ include/grpcpp/impl/codegen/time.h \ include/grpc/impl/codegen/byte_buffer.h \ include/grpc/impl/codegen/byte_buffer_reader.h \ @@ -7161,11 +7191,14 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/server_posix.h \ include/grpcpp/server_posix_impl.h \ include/grpcpp/support/async_stream.h \ + include/grpcpp/support/async_stream_impl.h \ include/grpcpp/support/async_unary_call.h \ + include/grpcpp/support/async_unary_call_impl.h \ include/grpcpp/support/byte_buffer.h \ include/grpcpp/support/channel_arguments.h \ include/grpcpp/support/channel_arguments_impl.h \ include/grpcpp/support/client_callback.h \ + include/grpcpp/support/client_callback_impl.h \ include/grpcpp/support/client_interceptor.h \ include/grpcpp/support/config.h \ include/grpcpp/support/interceptor.h \ @@ -7173,6 +7206,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/support/proto_buffer_reader.h \ include/grpcpp/support/proto_buffer_writer.h \ include/grpcpp/support/server_callback.h \ + include/grpcpp/support/server_callback_impl.h \ include/grpcpp/support/server_interceptor.h \ include/grpcpp/support/slice.h \ include/grpcpp/support/status.h \ @@ -7180,6 +7214,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/support/string_ref.h \ include/grpcpp/support/stub_options.h \ include/grpcpp/support/sync_stream.h \ + include/grpcpp/support/sync_stream_impl.h \ include/grpcpp/support/time.h \ include/grpcpp/support/validate_service_config.h \ include/grpc/support/alloc.h \ @@ -7265,7 +7300,9 @@ PUBLIC_HEADERS_CXX += \ include/grpc++/impl/codegen/time.h \ include/grpcpp/impl/codegen/async_generic_service.h \ include/grpcpp/impl/codegen/async_stream.h \ + include/grpcpp/impl/codegen/async_stream_impl.h \ include/grpcpp/impl/codegen/async_unary_call.h \ + include/grpcpp/impl/codegen/async_unary_call_impl.h \ include/grpcpp/impl/codegen/byte_buffer.h \ include/grpcpp/impl/codegen/call.h \ include/grpcpp/impl/codegen/call_hook.h \ @@ -7274,6 +7311,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/callback_common.h \ include/grpcpp/impl/codegen/channel_interface.h \ include/grpcpp/impl/codegen/client_callback.h \ + include/grpcpp/impl/codegen/client_callback_impl.h \ include/grpcpp/impl/codegen/client_context.h \ include/grpcpp/impl/codegen/client_context_impl.h \ include/grpcpp/impl/codegen/client_interceptor.h \ @@ -7296,6 +7334,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/security/auth_context.h \ include/grpcpp/impl/codegen/serialization_traits.h \ include/grpcpp/impl/codegen/server_callback.h \ + include/grpcpp/impl/codegen/server_callback_impl.h \ include/grpcpp/impl/codegen/server_context.h \ include/grpcpp/impl/codegen/server_context_impl.h \ include/grpcpp/impl/codegen/server_interceptor.h \ @@ -7307,6 +7346,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/string_ref.h \ include/grpcpp/impl/codegen/stub_options.h \ include/grpcpp/impl/codegen/sync_stream.h \ + include/grpcpp/impl/codegen/sync_stream_impl.h \ include/grpcpp/impl/codegen/time.h \ include/grpcpp/impl/codegen/sync.h \ diff --git a/build.yaml b/build.yaml index d342e88d24c..8e769ed9923 100644 --- a/build.yaml +++ b/build.yaml @@ -1250,7 +1250,9 @@ filegroups: - include/grpc++/impl/codegen/time.h - include/grpcpp/impl/codegen/async_generic_service.h - include/grpcpp/impl/codegen/async_stream.h + - include/grpcpp/impl/codegen/async_stream_impl.h - include/grpcpp/impl/codegen/async_unary_call.h + - include/grpcpp/impl/codegen/async_unary_call_impl.h - include/grpcpp/impl/codegen/byte_buffer.h - include/grpcpp/impl/codegen/call.h - include/grpcpp/impl/codegen/call_hook.h @@ -1259,6 +1261,7 @@ filegroups: - include/grpcpp/impl/codegen/callback_common.h - include/grpcpp/impl/codegen/channel_interface.h - include/grpcpp/impl/codegen/client_callback.h + - include/grpcpp/impl/codegen/client_callback_impl.h - include/grpcpp/impl/codegen/client_context.h - include/grpcpp/impl/codegen/client_context_impl.h - include/grpcpp/impl/codegen/client_interceptor.h @@ -1281,6 +1284,7 @@ filegroups: - include/grpcpp/impl/codegen/security/auth_context.h - include/grpcpp/impl/codegen/serialization_traits.h - include/grpcpp/impl/codegen/server_callback.h + - include/grpcpp/impl/codegen/server_callback_impl.h - include/grpcpp/impl/codegen/server_context.h - include/grpcpp/impl/codegen/server_context_impl.h - include/grpcpp/impl/codegen/server_interceptor.h @@ -1292,6 +1296,7 @@ filegroups: - include/grpcpp/impl/codegen/string_ref.h - include/grpcpp/impl/codegen/stub_options.h - include/grpcpp/impl/codegen/sync_stream.h + - include/grpcpp/impl/codegen/sync_stream_impl.h - include/grpcpp/impl/codegen/time.h uses: - grpc_codegen @@ -1410,11 +1415,14 @@ filegroups: - include/grpcpp/server_posix.h - include/grpcpp/server_posix_impl.h - include/grpcpp/support/async_stream.h + - include/grpcpp/support/async_stream_impl.h - include/grpcpp/support/async_unary_call.h + - include/grpcpp/support/async_unary_call_impl.h - include/grpcpp/support/byte_buffer.h - include/grpcpp/support/channel_arguments.h - include/grpcpp/support/channel_arguments_impl.h - include/grpcpp/support/client_callback.h + - include/grpcpp/support/client_callback_impl.h - include/grpcpp/support/client_interceptor.h - include/grpcpp/support/config.h - include/grpcpp/support/interceptor.h @@ -1422,6 +1430,7 @@ filegroups: - include/grpcpp/support/proto_buffer_reader.h - include/grpcpp/support/proto_buffer_writer.h - include/grpcpp/support/server_callback.h + - include/grpcpp/support/server_callback_impl.h - include/grpcpp/support/server_interceptor.h - include/grpcpp/support/slice.h - include/grpcpp/support/status.h @@ -1429,6 +1438,7 @@ filegroups: - include/grpcpp/support/string_ref.h - include/grpcpp/support/stub_options.h - include/grpcpp/support/sync_stream.h + - include/grpcpp/support/sync_stream_impl.h - include/grpcpp/support/time.h - include/grpcpp/support/validate_service_config.h headers: diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index 6fc97c6135e..ad396396843 100644 --- a/gRPC-C++.podspec +++ b/gRPC-C++.podspec @@ -129,11 +129,14 @@ Pod::Spec.new do |s| 'include/grpcpp/server_posix.h', 'include/grpcpp/server_posix_impl.h', 'include/grpcpp/support/async_stream.h', + 'include/grpcpp/support/async_stream_impl.h', 'include/grpcpp/support/async_unary_call.h', + 'include/grpcpp/support/async_unary_call_impl.h', 'include/grpcpp/support/byte_buffer.h', 'include/grpcpp/support/channel_arguments.h', 'include/grpcpp/support/channel_arguments_impl.h', 'include/grpcpp/support/client_callback.h', + 'include/grpcpp/support/client_callback_impl.h', 'include/grpcpp/support/client_interceptor.h', 'include/grpcpp/support/config.h', 'include/grpcpp/support/interceptor.h', @@ -141,6 +144,7 @@ Pod::Spec.new do |s| 'include/grpcpp/support/proto_buffer_reader.h', 'include/grpcpp/support/proto_buffer_writer.h', 'include/grpcpp/support/server_callback.h', + 'include/grpcpp/support/server_callback_impl.h', 'include/grpcpp/support/server_interceptor.h', 'include/grpcpp/support/slice.h', 'include/grpcpp/support/status.h', @@ -148,11 +152,14 @@ Pod::Spec.new do |s| 'include/grpcpp/support/string_ref.h', 'include/grpcpp/support/stub_options.h', 'include/grpcpp/support/sync_stream.h', + 'include/grpcpp/support/sync_stream_impl.h', 'include/grpcpp/support/time.h', 'include/grpcpp/support/validate_service_config.h', 'include/grpcpp/impl/codegen/async_generic_service.h', 'include/grpcpp/impl/codegen/async_stream.h', + 'include/grpcpp/impl/codegen/async_stream_impl.h', 'include/grpcpp/impl/codegen/async_unary_call.h', + 'include/grpcpp/impl/codegen/async_unary_call_impl.h', 'include/grpcpp/impl/codegen/byte_buffer.h', 'include/grpcpp/impl/codegen/call.h', 'include/grpcpp/impl/codegen/call_hook.h', @@ -161,6 +168,7 @@ Pod::Spec.new do |s| 'include/grpcpp/impl/codegen/callback_common.h', 'include/grpcpp/impl/codegen/channel_interface.h', 'include/grpcpp/impl/codegen/client_callback.h', + 'include/grpcpp/impl/codegen/client_callback_impl.h', 'include/grpcpp/impl/codegen/client_context.h', 'include/grpcpp/impl/codegen/client_context_impl.h', 'include/grpcpp/impl/codegen/client_interceptor.h', @@ -183,6 +191,7 @@ Pod::Spec.new do |s| 'include/grpcpp/impl/codegen/security/auth_context.h', 'include/grpcpp/impl/codegen/serialization_traits.h', 'include/grpcpp/impl/codegen/server_callback.h', + 'include/grpcpp/impl/codegen/server_callback_impl.h', 'include/grpcpp/impl/codegen/server_context.h', 'include/grpcpp/impl/codegen/server_context_impl.h', 'include/grpcpp/impl/codegen/server_interceptor.h', @@ -194,6 +203,7 @@ Pod::Spec.new do |s| 'include/grpcpp/impl/codegen/string_ref.h', 'include/grpcpp/impl/codegen/stub_options.h', 'include/grpcpp/impl/codegen/sync_stream.h', + 'include/grpcpp/impl/codegen/sync_stream_impl.h', 'include/grpcpp/impl/codegen/time.h', 'include/grpcpp/impl/codegen/sync.h' end diff --git a/include/grpcpp/channel_impl.h b/include/grpcpp/channel_impl.h index a7eee2b8981..9ff3118645f 100644 --- a/include/grpcpp/channel_impl.h +++ b/include/grpcpp/channel_impl.h @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include @@ -86,22 +86,23 @@ class Channel final : public ::grpc::ChannelInterface, ::grpc::internal::Call CreateCall(const ::grpc::internal::RpcMethod& method, ::grpc_impl::ClientContext* context, - ::grpc::CompletionQueue* cq) override; + ::grpc_impl::CompletionQueue* cq) override; void PerformOpsOnCall(::grpc::internal::CallOpSetInterface* ops, ::grpc::internal::Call* call) override; void* RegisterMethod(const char* method) override; void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed, gpr_timespec deadline, - ::grpc::CompletionQueue* cq, void* tag) override; + ::grpc_impl::CompletionQueue* cq, + void* tag) override; bool WaitForStateChangeImpl(grpc_connectivity_state last_observed, gpr_timespec deadline) override; - ::grpc::CompletionQueue* CallbackCQ() override; + ::grpc_impl::CompletionQueue* CallbackCQ() override; ::grpc::internal::Call CreateCallInternal( const ::grpc::internal::RpcMethod& method, - ::grpc_impl::ClientContext* context, ::grpc::CompletionQueue* cq, + ::grpc_impl::ClientContext* context, ::grpc_impl::CompletionQueue* cq, size_t interceptor_pos) override; const grpc::string host_; @@ -114,7 +115,7 @@ class Channel final : public ::grpc::ChannelInterface, // with this channel (if any). It is set on the first call to CallbackCQ(). // It is _not owned_ by the channel; ownership belongs with its internal // shutdown callback tag (invoked when the CQ is fully shutdown). - ::grpc::CompletionQueue* callback_cq_ = nullptr; + ::grpc_impl::CompletionQueue* callback_cq_ = nullptr; std::vector< std::unique_ptr<::grpc::experimental::ClientInterceptorFactoryInterface>> diff --git a/include/grpcpp/generic/generic_stub_impl.h b/include/grpcpp/generic/generic_stub_impl.h index fdbc0d0a272..e670fcaa654 100644 --- a/include/grpcpp/generic/generic_stub_impl.h +++ b/include/grpcpp/generic/generic_stub_impl.h @@ -22,17 +22,20 @@ #include #include -#include -#include +#include +#include #include -#include +#include #include +#include + namespace grpc { -typedef ClientAsyncReaderWriter +typedef ::grpc_impl::ClientAsyncReaderWriter GenericClientAsyncReaderWriter; -typedef ClientAsyncResponseReader GenericClientAsyncResponseReader; +typedef ::grpc_impl::ClientAsyncResponseReader + GenericClientAsyncResponseReader; } // namespace grpc namespace grpc_impl { class CompletionQueue; @@ -50,15 +53,15 @@ class GenericStub final { /// succeeded (i.e. the call won't proceed if the return value is nullptr). std::unique_ptr PrepareCall( grpc::ClientContext* context, const grpc::string& method, - grpc::CompletionQueue* cq); + CompletionQueue* cq); /// Setup a unary call to a named method \a method using \a context, and don't /// start it. Let it be started explicitly with StartCall. /// The return value only indicates whether or not registration of the call /// succeeded (i.e. the call won't proceed if the return value is nullptr). std::unique_ptr PrepareUnaryCall( - grpc::ClientContext* context, const grpc::string& method, - const grpc::ByteBuffer& request, grpc::CompletionQueue* cq); + grpc_impl::ClientContext* context, const grpc::string& method, + const grpc::ByteBuffer& request, CompletionQueue* cq); /// DEPRECATED for multi-threaded use /// Begin a call to a named method \a method using \a context. @@ -67,8 +70,8 @@ class GenericStub final { /// The return value only indicates whether or not registration of the call /// succeeded (i.e. the call won't proceed if the return value is nullptr). std::unique_ptr Call( - grpc::ClientContext* context, const grpc::string& method, - grpc::CompletionQueue* cq, void* tag); + grpc_impl::ClientContext* context, const grpc::string& method, + CompletionQueue* cq, void* tag); /// NOTE: class experimental_type is not part of the public API of this class /// TODO(vjpai): Move these contents to the public API of GenericStub when @@ -79,23 +82,25 @@ class GenericStub final { /// 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, + void UnaryCall(grpc_impl::ClientContext* context, + const grpc::string& method, const grpc::ByteBuffer* request, + grpc::ByteBuffer* response, std::function 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); + void UnaryCall(grpc_impl::ClientContext* context, + const grpc::string& method, const grpc::ByteBuffer* request, + grpc::ByteBuffer* response, + grpc_impl::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. void PrepareBidiStreamingCall( - grpc::ClientContext* context, const grpc::string& method, - grpc::experimental::ClientBidiReactor* reactor); + grpc_impl::ClientContext* context, const grpc::string& method, + grpc_impl::experimental::ClientBidiReactor* reactor); private: GenericStub* stub_; diff --git a/include/grpcpp/impl/codegen/async_generic_service.h b/include/grpcpp/impl/codegen/async_generic_service.h index d8e6f49b2f3..7c720ce3c23 100644 --- a/include/grpcpp/impl/codegen/async_generic_service.h +++ b/include/grpcpp/impl/codegen/async_generic_service.h @@ -19,19 +19,21 @@ #ifndef GRPCPP_IMPL_CODEGEN_ASYNC_GENERIC_SERVICE_H #define GRPCPP_IMPL_CODEGEN_ASYNC_GENERIC_SERVICE_H -#include +#include #include -#include +#include struct grpc_server; namespace grpc { -typedef ServerAsyncReaderWriter +typedef ::grpc_impl::ServerAsyncReaderWriter GenericServerAsyncReaderWriter; -typedef ServerAsyncResponseWriter GenericServerAsyncResponseWriter; -typedef ServerAsyncReader GenericServerAsyncReader; -typedef ServerAsyncWriter GenericServerAsyncWriter; +typedef ::grpc_impl::ServerAsyncResponseWriter + GenericServerAsyncResponseWriter; +typedef ::grpc_impl::ServerAsyncReader + GenericServerAsyncReader; +typedef ::grpc_impl::ServerAsyncWriter GenericServerAsyncWriter; class GenericServerContext final : public ::grpc_impl::ServerContext { public: @@ -75,8 +77,9 @@ class AsyncGenericService final { void RequestCall(GenericServerContext* ctx, GenericServerAsyncReaderWriter* reader_writer, - CompletionQueue* call_cq, - ServerCompletionQueue* notification_cq, void* tag); + ::grpc_impl::CompletionQueue* call_cq, + ::grpc_impl::ServerCompletionQueue* notification_cq, + void* tag); private: friend class grpc_impl::Server; @@ -91,7 +94,8 @@ namespace experimental { /// GenericServerContext rather than a ServerContext. All other reaction and /// operation initiation APIs are the same as ServerBidiReactor. class ServerGenericBidiReactor - : public ServerBidiReactor { + : public ::grpc_impl::experimental::ServerBidiReactor { public: /// Similar to ServerBidiReactor::OnStarted except for argument type. /// @@ -137,8 +141,10 @@ class CallbackGenericService { private: friend class ::grpc_impl::Server; - internal::CallbackBidiHandler* Handler() { - return new internal::CallbackBidiHandler( + ::grpc_impl::internal::CallbackBidiHandler* + Handler() { + return new ::grpc_impl::internal::CallbackBidiHandler( [this] { return CreateReactor(); }); } diff --git a/include/grpcpp/impl/codegen/async_stream.h b/include/grpcpp/impl/codegen/async_stream.h index 417dceb587f..14dfe67962e 100644 --- a/include/grpcpp/impl/codegen/async_stream.h +++ b/include/grpcpp/impl/codegen/async_stream.h @@ -19,1117 +19,47 @@ #ifndef GRPCPP_IMPL_CODEGEN_ASYNC_STREAM_H #define GRPCPP_IMPL_CODEGEN_ASYNC_STREAM_H -#include -#include -#include -#include -#include -#include +#include namespace grpc { - -namespace internal { -/// Common interface for all client side asynchronous streaming. -class ClientAsyncStreamingInterface { - public: - virtual ~ClientAsyncStreamingInterface() {} - - /// Start the call that was set up by the constructor, but only if the - /// constructor was invoked through the "Prepare" API which doesn't actually - /// start the call - virtual void StartCall(void* tag) = 0; - - /// Request notification of the reading of the initial metadata. Completion - /// will be notified by \a tag on the associated completion queue. - /// This call is optional, but if it is used, it cannot be used concurrently - /// with or after the \a AsyncReaderInterface::Read method. - /// - /// \param[in] tag Tag identifying this request. - virtual void ReadInitialMetadata(void* tag) = 0; - - /// Indicate that the stream is to be finished and request notification for - /// when the call has been ended. - /// Should not be used concurrently with other operations. - /// - /// It is appropriate to call this method when both: - /// * the client side has no more message to send - /// (this can be declared implicitly by calling this method, or - /// explicitly through an earlier call to the WritesDone method - /// of the class in use, e.g. \a ClientAsyncWriterInterface::WritesDone or - /// \a ClientAsyncReaderWriterInterface::WritesDone). - /// * there are no more messages to be received from the server (this can - /// be known implicitly by the calling code, or explicitly from an - /// earlier call to \a AsyncReaderInterface::Read that yielded a failed - /// result, e.g. cq->Next(&read_tag, &ok) filled in 'ok' with 'false'). - /// - /// The tag will be returned when either: - /// - all incoming messages have been read and the server has returned - /// a status. - /// - the server has returned a non-OK status. - /// - the call failed for some reason and the library generated a - /// status. - /// - /// Note that implementations of this method attempt to receive initial - /// metadata from the server if initial metadata hasn't yet been received. - /// - /// \param[in] tag Tag identifying this request. - /// \param[out] status To be updated with the operation status. - virtual void Finish(Status* status, void* tag) = 0; -}; - -/// An interface that yields a sequence of messages of type \a R. -template -class AsyncReaderInterface { - public: - virtual ~AsyncReaderInterface() {} - - /// Read a message of type \a R into \a msg. Completion will be notified by \a - /// tag on the associated completion queue. - /// This is thread-safe with respect to \a Write or \a WritesDone methods. It - /// should not be called concurrently with other streaming APIs - /// on the same stream. It is not meaningful to call it concurrently - /// with another \a AsyncReaderInterface::Read on the same stream since reads - /// on the same stream are delivered in order. - /// - /// \param[out] msg Where to eventually store the read message. - /// \param[in] tag The tag identifying the operation. - /// - /// Side effect: note that this method attempt to receive initial metadata for - /// a stream if it hasn't yet been received. - virtual void Read(R* msg, void* tag) = 0; -}; - -/// An interface that can be fed a sequence of messages of type \a W. -template -class AsyncWriterInterface { - public: - virtual ~AsyncWriterInterface() {} - - /// Request the writing of \a msg with identifying tag \a tag. - /// - /// Only one write may be outstanding at any given time. This means that - /// after calling Write, one must wait to receive \a tag from the completion - /// queue BEFORE calling Write again. - /// This is thread-safe with respect to \a AsyncReaderInterface::Read - /// - /// gRPC doesn't take ownership or a reference to \a msg, so it is safe to - /// to deallocate once Write returns. - /// - /// \param[in] msg The message to be written. - /// \param[in] tag The tag identifying the operation. - virtual void Write(const W& msg, void* tag) = 0; - - /// Request the writing of \a msg using WriteOptions \a options with - /// identifying tag \a tag. - /// - /// Only one write may be outstanding at any given time. This means that - /// after calling Write, one must wait to receive \a tag from the completion - /// queue BEFORE calling Write again. - /// WriteOptions \a options is used to set the write options of this message. - /// This is thread-safe with respect to \a AsyncReaderInterface::Read - /// - /// gRPC doesn't take ownership or a reference to \a msg, so it is safe to - /// to deallocate once Write returns. - /// - /// \param[in] msg The message to be written. - /// \param[in] options The WriteOptions to be used to write this message. - /// \param[in] tag The tag identifying the operation. - virtual void Write(const W& msg, WriteOptions options, void* tag) = 0; - - /// Request the writing of \a msg and coalesce it with the writing - /// of trailing metadata, using WriteOptions \a options with - /// identifying tag \a tag. - /// - /// For client, WriteLast is equivalent of performing Write and - /// WritesDone in a single step. - /// For server, WriteLast buffers the \a msg. The writing of \a msg is held - /// until Finish is called, where \a msg and trailing metadata are coalesced - /// and write is initiated. Note that WriteLast can only buffer \a msg up to - /// the flow control window size. If \a msg size is larger than the window - /// size, it will be sent on wire without buffering. - /// - /// gRPC doesn't take ownership or a reference to \a msg, so it is safe to - /// to deallocate once Write returns. - /// - /// \param[in] msg The message to be written. - /// \param[in] options The WriteOptions to be used to write this message. - /// \param[in] tag The tag identifying the operation. - void WriteLast(const W& msg, WriteOptions options, void* tag) { - Write(msg, options.set_last_message(), tag); - } -}; - -} // namespace internal - template -class ClientAsyncReaderInterface - : public internal::ClientAsyncStreamingInterface, - public internal::AsyncReaderInterface {}; +using ClientAsyncReaderInterface = ::grpc_impl::ClientAsyncReaderInterface; -namespace internal { template -class ClientAsyncReaderFactory { - public: - /// Create a stream object. - /// Write the first request out if \a start is set. - /// \a tag will be notified on \a cq when the call has been started and - /// \a request has been written out. If \a start is not set, \a tag must be - /// nullptr and the actual call must be initiated by StartCall - /// Note that \a context will be used to fill in custom initial metadata - /// used to send to the server when starting the call. - template - static ClientAsyncReader* Create(ChannelInterface* channel, - CompletionQueue* cq, - const ::grpc::internal::RpcMethod& method, - ::grpc_impl::ClientContext* context, - const W& request, bool start, void* tag) { - ::grpc::internal::Call call = channel->CreateCall(method, context, cq); - return new (g_core_codegen_interface->grpc_call_arena_alloc( - call.call(), sizeof(ClientAsyncReader))) - ClientAsyncReader(call, context, request, start, tag); - } -}; -} // namespace internal - -/// Async client-side API for doing server-streaming RPCs, -/// where the incoming message stream coming from the server has -/// messages of type \a R. -template -class ClientAsyncReader final : public ClientAsyncReaderInterface { - public: - // always allocated against a call arena, no memory free required - static void operator delete(void* ptr, std::size_t size) { - assert(size == sizeof(ClientAsyncReader)); - } - - // 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(void* tag) override { - assert(!started_); - started_ = true; - StartCallInternal(tag); - } - - /// See the \a ClientAsyncStreamingInterface.ReadInitialMetadata - /// method for semantics. - /// - /// Side effect: - /// - upon receiving initial metadata from the server, - /// the \a ClientContext associated with this call is updated, and the - /// calling code can access the received metadata through the - /// \a ClientContext. - void ReadInitialMetadata(void* tag) override { - assert(started_); - GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); - - meta_ops_.set_output_tag(tag); - meta_ops_.RecvInitialMetadata(context_); - call_.PerformOps(&meta_ops_); - } - - void Read(R* msg, void* tag) override { - assert(started_); - read_ops_.set_output_tag(tag); - if (!context_->initial_metadata_received_) { - read_ops_.RecvInitialMetadata(context_); - } - read_ops_.RecvMessage(msg); - call_.PerformOps(&read_ops_); - } - - /// See the \a ClientAsyncStreamingInterface.Finish method for semantics. - /// - /// Side effect: - /// - the \a ClientContext associated with this call is updated with - /// possible initial and trailing metadata received from the server. - void Finish(Status* status, void* tag) override { - assert(started_); - finish_ops_.set_output_tag(tag); - if (!context_->initial_metadata_received_) { - finish_ops_.RecvInitialMetadata(context_); - } - finish_ops_.ClientRecvStatus(context_, status); - call_.PerformOps(&finish_ops_); - } +using ClientAsyncReader = ::grpc_impl::ClientAsyncReader; - private: - friend class internal::ClientAsyncReaderFactory; - template - ClientAsyncReader(::grpc::internal::Call call, - ::grpc_impl::ClientContext* context, const W& request, - bool start, void* tag) - : context_(context), call_(call), started_(start) { - // TODO(ctiller): don't assert - GPR_CODEGEN_ASSERT(init_ops_.SendMessage(request).ok()); - init_ops_.ClientSendClose(); - if (start) { - StartCallInternal(tag); - } else { - assert(tag == nullptr); - } - } - - void StartCallInternal(void* tag) { - init_ops_.SendInitialMetadata(&context_->send_initial_metadata_, - context_->initial_metadata_flags()); - init_ops_.set_output_tag(tag); - call_.PerformOps(&init_ops_); - } - - ::grpc_impl::ClientContext* context_; - ::grpc::internal::Call call_; - bool started_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpClientSendClose> - init_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> - meta_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpRecvMessage> - read_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpClientRecvStatus> - finish_ops_; -}; - -/// Common interface for client side asynchronous writing. template -class ClientAsyncWriterInterface - : public internal::ClientAsyncStreamingInterface, - public internal::AsyncWriterInterface { - public: - /// Signal the client is done with the writes (half-close the client stream). - /// Thread-safe with respect to \a AsyncReaderInterface::Read - /// - /// \param[in] tag The tag identifying the operation. - virtual void WritesDone(void* tag) = 0; -}; +using ClientAsyncWriterInterface = ::grpc_impl::ClientAsyncWriterInterface; -namespace internal { template -class ClientAsyncWriterFactory { - public: - /// Create a stream object. - /// Start the RPC if \a start is set - /// \a tag will be notified on \a cq when the call has been started (i.e. - /// intitial metadata sent) and \a request has been written out. - /// If \a start is not set, \a tag must be nullptr and the actual call - /// must be initiated by StartCall - /// Note that \a context will be used to fill in custom initial metadata - /// used to send to the server when starting the call. - /// \a response will be filled in with the single expected response - /// message from the server upon a successful call to the \a Finish - /// method of this instance. - template - static ClientAsyncWriter* Create(ChannelInterface* channel, - CompletionQueue* cq, - const ::grpc::internal::RpcMethod& method, - ::grpc_impl::ClientContext* context, - R* response, bool start, void* tag) { - ::grpc::internal::Call call = channel->CreateCall(method, context, cq); - return new (g_core_codegen_interface->grpc_call_arena_alloc( - call.call(), sizeof(ClientAsyncWriter))) - ClientAsyncWriter(call, context, response, start, tag); - } -}; -} // namespace internal - -/// Async API on the client side for doing client-streaming RPCs, -/// where the outgoing message stream going to the server contains -/// messages of type \a W. -template -class ClientAsyncWriter final : public ClientAsyncWriterInterface { - public: - // always allocated against a call arena, no memory free required - static void operator delete(void* ptr, std::size_t size) { - assert(size == sizeof(ClientAsyncWriter)); - } - - // 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(void* tag) override { - assert(!started_); - started_ = true; - StartCallInternal(tag); - } - - /// See the \a ClientAsyncStreamingInterface.ReadInitialMetadata method for - /// semantics. - /// - /// Side effect: - /// - upon receiving initial metadata from the server, the \a ClientContext - /// associated with this call is updated, and the calling code can access - /// the received metadata through the \a ClientContext. - void ReadInitialMetadata(void* tag) override { - assert(started_); - GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); - - meta_ops_.set_output_tag(tag); - meta_ops_.RecvInitialMetadata(context_); - call_.PerformOps(&meta_ops_); - } - - void Write(const W& msg, void* tag) override { - assert(started_); - write_ops_.set_output_tag(tag); - // TODO(ctiller): don't assert - GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok()); - call_.PerformOps(&write_ops_); - } - - void Write(const W& msg, WriteOptions options, void* tag) override { - assert(started_); - write_ops_.set_output_tag(tag); - if (options.is_last_message()) { - options.set_buffer_hint(); - write_ops_.ClientSendClose(); - } - // TODO(ctiller): don't assert - GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok()); - call_.PerformOps(&write_ops_); - } +using ClientAsyncWriter = ::grpc_impl::ClientAsyncWriter; - void WritesDone(void* tag) override { - assert(started_); - write_ops_.set_output_tag(tag); - write_ops_.ClientSendClose(); - call_.PerformOps(&write_ops_); - } - - /// See the \a ClientAsyncStreamingInterface.Finish method for semantics. - /// - /// Side effect: - /// - the \a ClientContext associated with this call is updated with - /// possible initial and trailing metadata received from the server. - /// - attempts to fill in the \a response parameter passed to this class's - /// constructor with the server's response message. - void Finish(Status* status, void* tag) override { - assert(started_); - finish_ops_.set_output_tag(tag); - if (!context_->initial_metadata_received_) { - finish_ops_.RecvInitialMetadata(context_); - } - finish_ops_.ClientRecvStatus(context_, status); - call_.PerformOps(&finish_ops_); - } - - private: - friend class internal::ClientAsyncWriterFactory; - template - ClientAsyncWriter(::grpc::internal::Call call, - ::grpc_impl::ClientContext* context, R* response, - bool start, void* tag) - : context_(context), call_(call), started_(start) { - finish_ops_.RecvMessage(response); - finish_ops_.AllowNoMessage(); - if (start) { - StartCallInternal(tag); - } else { - assert(tag == nullptr); - } - } - - void StartCallInternal(void* tag) { - write_ops_.SendInitialMetadata(&context_->send_initial_metadata_, - context_->initial_metadata_flags()); - // if corked bit is set in context, we just keep the initial metadata - // buffered up to coalesce with later message send. No op is performed. - if (!context_->initial_metadata_corked_) { - write_ops_.set_output_tag(tag); - call_.PerformOps(&write_ops_); - } - } - - ::grpc_impl::ClientContext* context_; - ::grpc::internal::Call call_; - bool started_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> - meta_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpClientSendClose> - write_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpGenericRecvMessage, - ::grpc::internal::CallOpClientRecvStatus> - finish_ops_; -}; - -/// Async client-side interface for bi-directional streaming, -/// where the client-to-server message stream has messages of type \a W, -/// and the server-to-client message stream has messages of type \a R. template -class ClientAsyncReaderWriterInterface - : public internal::ClientAsyncStreamingInterface, - public internal::AsyncWriterInterface, - public internal::AsyncReaderInterface { - public: - /// Signal the client is done with the writes (half-close the client stream). - /// Thread-safe with respect to \a AsyncReaderInterface::Read - /// - /// \param[in] tag The tag identifying the operation. - virtual void WritesDone(void* tag) = 0; -}; +using ClientAsyncReaderWriterInterface = + ::grpc_impl::ClientAsyncReaderWriterInterface; -namespace internal { template -class ClientAsyncReaderWriterFactory { - public: - /// Create a stream object. - /// Start the RPC request if \a start is set. - /// \a tag will be notified on \a cq when the call has been started (i.e. - /// intitial metadata sent). If \a start is not set, \a tag must be - /// nullptr and the actual call must be initiated by StartCall - /// Note that \a context will be used to fill in custom initial metadata - /// used to send to the server when starting the call. - static ClientAsyncReaderWriter* Create( - ChannelInterface* channel, CompletionQueue* cq, - const ::grpc::internal::RpcMethod& method, - ::grpc_impl::ClientContext* context, bool start, void* tag) { - ::grpc::internal::Call call = channel->CreateCall(method, context, cq); - - return new (g_core_codegen_interface->grpc_call_arena_alloc( - call.call(), sizeof(ClientAsyncReaderWriter))) - ClientAsyncReaderWriter(call, context, start, tag); - } -}; -} // namespace internal - -/// Async client-side interface for bi-directional streaming, -/// where the outgoing message stream going to the server -/// has messages of type \a W, and the incoming message stream coming -/// from the server has messages of type \a R. -template -class ClientAsyncReaderWriter final - : public ClientAsyncReaderWriterInterface { - public: - // always allocated against a call arena, no memory free required - static void operator delete(void* ptr, std::size_t size) { - assert(size == sizeof(ClientAsyncReaderWriter)); - } - - // 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(void* tag) override { - assert(!started_); - started_ = true; - StartCallInternal(tag); - } - - /// See the \a ClientAsyncStreamingInterface.ReadInitialMetadata method - /// for semantics of this method. - /// - /// Side effect: - /// - upon receiving initial metadata from the server, the \a ClientContext - /// is updated with it, and then the receiving initial metadata can - /// be accessed through this \a ClientContext. - void ReadInitialMetadata(void* tag) override { - assert(started_); - GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); - - meta_ops_.set_output_tag(tag); - meta_ops_.RecvInitialMetadata(context_); - call_.PerformOps(&meta_ops_); - } - - void Read(R* msg, void* tag) override { - assert(started_); - read_ops_.set_output_tag(tag); - if (!context_->initial_metadata_received_) { - read_ops_.RecvInitialMetadata(context_); - } - read_ops_.RecvMessage(msg); - call_.PerformOps(&read_ops_); - } - - void Write(const W& msg, void* tag) override { - assert(started_); - write_ops_.set_output_tag(tag); - // TODO(ctiller): don't assert - GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok()); - call_.PerformOps(&write_ops_); - } - - void Write(const W& msg, WriteOptions options, void* tag) override { - assert(started_); - write_ops_.set_output_tag(tag); - if (options.is_last_message()) { - options.set_buffer_hint(); - write_ops_.ClientSendClose(); - } - // TODO(ctiller): don't assert - GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok()); - call_.PerformOps(&write_ops_); - } - - void WritesDone(void* tag) override { - assert(started_); - write_ops_.set_output_tag(tag); - write_ops_.ClientSendClose(); - call_.PerformOps(&write_ops_); - } - - /// See the \a ClientAsyncStreamingInterface.Finish method for semantics. - /// Side effect - /// - the \a ClientContext associated with this call is updated with - /// possible initial and trailing metadata sent from the server. - void Finish(Status* status, void* tag) override { - assert(started_); - finish_ops_.set_output_tag(tag); - if (!context_->initial_metadata_received_) { - finish_ops_.RecvInitialMetadata(context_); - } - finish_ops_.ClientRecvStatus(context_, status); - call_.PerformOps(&finish_ops_); - } - - private: - friend class internal::ClientAsyncReaderWriterFactory; - ClientAsyncReaderWriter(::grpc::internal::Call call, - ::grpc_impl::ClientContext* context, bool start, - void* tag) - : context_(context), call_(call), started_(start) { - if (start) { - StartCallInternal(tag); - } else { - assert(tag == nullptr); - } - } - - void StartCallInternal(void* tag) { - write_ops_.SendInitialMetadata(&context_->send_initial_metadata_, - context_->initial_metadata_flags()); - // if corked bit is set in context, we just keep the initial metadata - // buffered up to coalesce with later message send. No op is performed. - if (!context_->initial_metadata_corked_) { - write_ops_.set_output_tag(tag); - call_.PerformOps(&write_ops_); - } - } - - ::grpc_impl::ClientContext* context_; - ::grpc::internal::Call call_; - bool started_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> - meta_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpRecvMessage> - read_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpClientSendClose> - write_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpClientRecvStatus> - finish_ops_; -}; +using ClientAsyncReaderWriter = ::grpc_impl::ClientAsyncReaderWriter; template -class ServerAsyncReaderInterface - : public internal::ServerAsyncStreamingInterface, - public internal::AsyncReaderInterface { - public: - /// Indicate that the stream is to be finished with a certain status code - /// and also send out \a msg response to the client. - /// Request notification for when the server has sent the response and the - /// appropriate signals to the client to end the call. - /// Should not be used concurrently with other operations. - /// - /// It is appropriate to call this method when: - /// * all messages from the client have been received (either known - /// implictly, or explicitly because a previous - /// \a AsyncReaderInterface::Read operation with a non-ok result, - /// e.g., cq->Next(&read_tag, &ok) filled in 'ok' with 'false'). - /// - /// This operation will end when the server has finished sending out initial - /// metadata (if not sent already), response message, and status, or if - /// 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 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. - /// \param[in] msg To be sent to the client as the response for this call. - virtual void Finish(const W& msg, const Status& status, void* tag) = 0; - - /// Indicate that the stream is to be finished with a certain - /// non-OK status code. - /// Request notification for when the server has sent the appropriate - /// signals to the client to end the call. - /// Should not be used concurrently with other operations. - /// - /// This call is meant to end the call with some error, and can be called at - /// any point that the server would like to "fail" the call (though note - /// this shouldn't be called concurrently with any other "sending" call, like - /// \a AsyncWriterInterface::Write). - /// - /// This operation will end when the server has finished sending out initial - /// metadata (if not sent already), and status, or if some failure occurred - /// when trying to do so. - /// - /// gRPC doesn't take ownership or a reference to \a status, so it is safe to - /// to deallocate once FinishWithError returns. - /// - /// \param[in] tag Tag identifying this request. - /// \param[in] status To be sent to the client as the result of this call. - /// - Note: \a status must have a non-OK code. - virtual void FinishWithError(const Status& status, void* tag) = 0; -}; +using ServerAsyncReaderInterface = + ::grpc_impl::ServerAsyncReaderInterface; -/// Async server-side API for doing client-streaming RPCs, -/// where the incoming message stream from the client has messages of type \a R, -/// and the single response message sent from the server is type \a W. template -class ServerAsyncReader final : public ServerAsyncReaderInterface { - public: - explicit ServerAsyncReader(::grpc_impl::ServerContext* ctx) - : call_(nullptr, nullptr, nullptr), ctx_(ctx) {} - - /// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics. - /// - /// Implicit input parameter: - /// - The initial metadata that will be sent to the client from this op will - /// be taken from the \a ServerContext associated with the call. - void SendInitialMetadata(void* tag) override { - GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); - - meta_ops_.set_output_tag(tag); - meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - meta_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - call_.PerformOps(&meta_ops_); - } - - void Read(R* msg, void* tag) override { - read_ops_.set_output_tag(tag); - read_ops_.RecvMessage(msg); - call_.PerformOps(&read_ops_); - } - - /// See the \a ServerAsyncReaderInterface.Read method for semantics - /// - /// Side effect: - /// - also sends initial metadata if not alreay sent. - /// - uses the \a ServerContext associated with this call to send possible - /// initial and trailing metadata. - /// - /// 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 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_) { - finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - finish_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - } - // The response is dropped if the status is not OK. - if (status.ok()) { - finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, - finish_ops_.SendMessage(msg)); - } else { - finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status); - } - call_.PerformOps(&finish_ops_); - } - - /// See the \a ServerAsyncReaderInterface.Read method for semantics - /// - /// Side effect: - /// - also sends initial metadata if not alreay sent. - /// - uses the \a ServerContext associated with this call to send possible - /// initial and trailing metadata. - /// - /// gRPC doesn't take ownership or a reference to \a status, so it is safe to - /// to deallocate once FinishWithError returns. - void FinishWithError(const Status& status, void* tag) override { - GPR_CODEGEN_ASSERT(!status.ok()); - finish_ops_.set_output_tag(tag); - if (!ctx_->sent_initial_metadata_) { - finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - finish_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - } - finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status); - call_.PerformOps(&finish_ops_); - } - - private: - void BindCall(::grpc::internal::Call* call) override { call_ = *call; } - - ::grpc::internal::Call call_; - ::grpc_impl::ServerContext* ctx_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> - meta_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage> read_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpServerSendStatus> - finish_ops_; -}; +using ServerAsyncReader = ::grpc_impl::ServerAsyncReader; template -class ServerAsyncWriterInterface - : public internal::ServerAsyncStreamingInterface, - public internal::AsyncWriterInterface { - public: - /// Indicate that the stream is to be finished with a certain status code. - /// Request notification for when the server has sent the appropriate - /// signals to the client to end the call. - /// Should not be used concurrently with other operations. - /// - /// It is appropriate to call this method when either: - /// * all messages from the client have been received (either known - /// implictly, or explicitly because a previous \a - /// AsyncReaderInterface::Read operation with a non-ok - /// result (e.g., cq->Next(&read_tag, &ok) filled in 'ok' with 'false'. - /// * it is desired to end the call early with some non-OK status code. - /// - /// This operation will end when the server has finished sending out initial - /// metadata (if not sent already), response message, and status, or if - /// some failure occurred when trying to do so. - /// - /// gRPC doesn't take ownership or a reference to \a status, so it is safe to - /// 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. - virtual void Finish(const Status& status, void* tag) = 0; - - /// Request the writing of \a msg and coalesce it with trailing metadata which - /// contains \a status, using WriteOptions options with - /// identifying tag \a tag. - /// - /// WriteAndFinish is equivalent of performing WriteLast and Finish - /// in a single step. - /// - /// gRPC doesn't take ownership or a reference to \a msg and \a status, so it - /// 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. - /// \param[in] status The Status that server returns to client. - /// \param[in] tag The tag identifying the operation. - virtual void WriteAndFinish(const W& msg, WriteOptions options, - const Status& status, void* tag) = 0; -}; +using ServerAsyncWriterInterface = ::grpc_impl::ServerAsyncWriterInterface; -/// Async server-side API for doing server streaming RPCs, -/// where the outgoing message stream from the server has messages of type \a W. template -class ServerAsyncWriter final : public ServerAsyncWriterInterface { - public: - explicit ServerAsyncWriter(::grpc_impl::ServerContext* ctx) - : call_(nullptr, nullptr, nullptr), ctx_(ctx) {} - - /// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics. - /// - /// Implicit input parameter: - /// - The initial metadata that will be sent to the client from this op will - /// be taken from the \a ServerContext associated with the call. - /// - /// \param[in] tag Tag identifying this request. - void SendInitialMetadata(void* tag) override { - GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); - - meta_ops_.set_output_tag(tag); - meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - meta_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - call_.PerformOps(&meta_ops_); - } - - void Write(const W& msg, void* tag) override { - write_ops_.set_output_tag(tag); - EnsureInitialMetadataSent(&write_ops_); - // TODO(ctiller): don't assert - GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok()); - call_.PerformOps(&write_ops_); - } +using ServerAsyncWriter = ::grpc_impl::ServerAsyncWriter; - void Write(const W& msg, WriteOptions options, void* tag) override { - write_ops_.set_output_tag(tag); - if (options.is_last_message()) { - options.set_buffer_hint(); - } - - EnsureInitialMetadataSent(&write_ops_); - // TODO(ctiller): don't assert - GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok()); - call_.PerformOps(&write_ops_); - } - - /// See the \a ServerAsyncWriterInterface.WriteAndFinish method for semantics. - /// - /// Implicit input parameter: - /// - the \a ServerContext associated with this call is used - /// for sending trailing (and initial) metadata to the client. - /// - /// 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 deallocate once WriteAndFinish returns. - void WriteAndFinish(const W& msg, WriteOptions options, const Status& status, - void* tag) override { - write_ops_.set_output_tag(tag); - EnsureInitialMetadataSent(&write_ops_); - options.set_buffer_hint(); - GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok()); - write_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status); - call_.PerformOps(&write_ops_); - } - - /// See the \a ServerAsyncWriterInterface.Finish method for semantics. - /// - /// Implicit input parameter: - /// - the \a ServerContext associated with this call is used for sending - /// trailing (and initial if not already sent) metadata to the client. - /// - /// Note: there are no restrictions are the code of - /// \a status,it may be non-OK - /// - /// gRPC doesn't take ownership or a reference to \a status, so it is safe to - /// to deallocate once Finish returns. - void Finish(const Status& status, void* tag) override { - finish_ops_.set_output_tag(tag); - EnsureInitialMetadataSent(&finish_ops_); - finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status); - call_.PerformOps(&finish_ops_); - } - - private: - void BindCall(::grpc::internal::Call* call) override { call_ = *call; } - - template - void EnsureInitialMetadataSent(T* ops) { - if (!ctx_->sent_initial_metadata_) { - ops->SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - ops->set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - } - } - - ::grpc::internal::Call call_; - ::grpc_impl::ServerContext* ctx_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> - meta_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpServerSendStatus> - write_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpServerSendStatus> - finish_ops_; -}; - -/// Server-side interface for asynchronous bi-directional streaming. template -class ServerAsyncReaderWriterInterface - : public internal::ServerAsyncStreamingInterface, - public internal::AsyncWriterInterface, - public internal::AsyncReaderInterface { - public: - /// Indicate that the stream is to be finished with a certain status code. - /// Request notification for when the server has sent the appropriate - /// signals to the client to end the call. - /// Should not be used concurrently with other operations. - /// - /// It is appropriate to call this method when either: - /// * all messages from the client have been received (either known - /// implictly, or explicitly because a previous \a - /// AsyncReaderInterface::Read operation - /// with a non-ok result (e.g., cq->Next(&read_tag, &ok) filled in 'ok' - /// with 'false'. - /// * it is desired to end the call early with some non-OK status code. - /// - /// This operation will end when the server has finished sending out initial - /// metadata (if not sent already), response message, and status, or if some - /// failure occurred when trying to do so. - /// - /// gRPC doesn't take ownership or a reference to \a status, so it is safe to - /// 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. - virtual void Finish(const Status& status, void* tag) = 0; - - /// Request the writing of \a msg and coalesce it with trailing metadata which - /// contains \a status, using WriteOptions options with - /// identifying tag \a tag. - /// - /// WriteAndFinish is equivalent of performing WriteLast and Finish in a - /// single step. - /// - /// gRPC doesn't take ownership or a reference to \a msg and \a status, so it - /// 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. - /// \param[in] status The Status that server returns to client. - /// \param[in] tag The tag identifying the operation. - virtual void WriteAndFinish(const W& msg, WriteOptions options, - const Status& status, void* tag) = 0; -}; +using ServerAsyncReaderWriterInterface = + ::grpc_impl::ServerAsyncReaderWriterInterface; -/// Async server-side API for doing bidirectional streaming RPCs, -/// where the incoming message stream coming from the client has messages of -/// type \a R, and the outgoing message stream coming from the server has -/// messages of type \a W. template -class ServerAsyncReaderWriter final - : public ServerAsyncReaderWriterInterface { - public: - explicit ServerAsyncReaderWriter(::grpc_impl::ServerContext* ctx) - : call_(nullptr, nullptr, nullptr), ctx_(ctx) {} - - /// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics. - /// - /// Implicit input parameter: - /// - The initial metadata that will be sent to the client from this op will - /// be taken from the \a ServerContext associated with the call. - /// - /// \param[in] tag Tag identifying this request. - void SendInitialMetadata(void* tag) override { - GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); - - meta_ops_.set_output_tag(tag); - meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - meta_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - call_.PerformOps(&meta_ops_); - } - - void Read(R* msg, void* tag) override { - read_ops_.set_output_tag(tag); - read_ops_.RecvMessage(msg); - call_.PerformOps(&read_ops_); - } - - void Write(const W& msg, void* tag) override { - write_ops_.set_output_tag(tag); - EnsureInitialMetadataSent(&write_ops_); - // TODO(ctiller): don't assert - GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok()); - call_.PerformOps(&write_ops_); - } - - void Write(const W& msg, WriteOptions options, void* tag) override { - write_ops_.set_output_tag(tag); - if (options.is_last_message()) { - options.set_buffer_hint(); - } - EnsureInitialMetadataSent(&write_ops_); - GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok()); - call_.PerformOps(&write_ops_); - } - - /// See the \a ServerAsyncReaderWriterInterface.WriteAndFinish - /// method for semantics. - /// - /// Implicit input parameter: - /// - the \a ServerContext associated with this call is used - /// for sending trailing (and initial) metadata to the client. - /// - /// 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 deallocate once WriteAndFinish returns. - void WriteAndFinish(const W& msg, WriteOptions options, const Status& status, - void* tag) override { - write_ops_.set_output_tag(tag); - EnsureInitialMetadataSent(&write_ops_); - options.set_buffer_hint(); - GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok()); - write_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status); - call_.PerformOps(&write_ops_); - } - - /// See the \a ServerAsyncReaderWriterInterface.Finish method for semantics. - /// - /// Implicit input parameter: - /// - the \a ServerContext associated with this call is used for sending - /// trailing (and initial if not already sent) metadata to the client. - /// - /// Note: there are no restrictions are the code of \a status, - /// it may be non-OK - // - /// gRPC doesn't take ownership or a reference to \a status, so it is safe to - /// to deallocate once Finish returns. - void Finish(const Status& status, void* tag) override { - finish_ops_.set_output_tag(tag); - EnsureInitialMetadataSent(&finish_ops_); - - finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status); - call_.PerformOps(&finish_ops_); - } - - private: - friend class ::grpc_impl::Server; - - void BindCall(::grpc::internal::Call* call) override { call_ = *call; } - - template - void EnsureInitialMetadataSent(T* ops) { - if (!ctx_->sent_initial_metadata_) { - ops->SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - ops->set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - } - } - - ::grpc::internal::Call call_; - ::grpc_impl::ServerContext* ctx_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> - meta_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage> read_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpServerSendStatus> - write_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpServerSendStatus> - finish_ops_; -}; - +using ServerAsyncReaderWriter = ::grpc_impl::ServerAsyncReaderWriter; } // namespace grpc #endif // GRPCPP_IMPL_CODEGEN_ASYNC_STREAM_H diff --git a/include/grpcpp/impl/codegen/async_stream_impl.h b/include/grpcpp/impl/codegen/async_stream_impl.h new file mode 100644 index 00000000000..633a3d5dd00 --- /dev/null +++ b/include/grpcpp/impl/codegen/async_stream_impl.h @@ -0,0 +1,1134 @@ +/* + * + * 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_ASYNC_STREAM_IMPL_H +#define GRPCPP_IMPL_CODEGEN_ASYNC_STREAM_IMPL_H + +#include +#include +#include +#include +#include +#include + +namespace grpc_impl { + +namespace internal { +/// Common interface for all client side asynchronous streaming. +class ClientAsyncStreamingInterface { + public: + virtual ~ClientAsyncStreamingInterface() {} + + /// Start the call that was set up by the constructor, but only if the + /// constructor was invoked through the "Prepare" API which doesn't actually + /// start the call + virtual void StartCall(void* tag) = 0; + + /// Request notification of the reading of the initial metadata. Completion + /// will be notified by \a tag on the associated completion queue. + /// This call is optional, but if it is used, it cannot be used concurrently + /// with or after the \a AsyncReaderInterface::Read method. + /// + /// \param[in] tag Tag identifying this request. + virtual void ReadInitialMetadata(void* tag) = 0; + + /// Indicate that the stream is to be finished and request notification for + /// when the call has been ended. + /// Should not be used concurrently with other operations. + /// + /// It is appropriate to call this method when both: + /// * the client side has no more message to send + /// (this can be declared implicitly by calling this method, or + /// explicitly through an earlier call to the WritesDone method + /// of the class in use, e.g. \a ClientAsyncWriterInterface::WritesDone or + /// \a ClientAsyncReaderWriterInterface::WritesDone). + /// * there are no more messages to be received from the server (this can + /// be known implicitly by the calling code, or explicitly from an + /// earlier call to \a AsyncReaderInterface::Read that yielded a failed + /// result, e.g. cq->Next(&read_tag, &ok) filled in 'ok' with 'false'). + /// + /// The tag will be returned when either: + /// - all incoming messages have been read and the server has returned + /// a status. + /// - the server has returned a non-OK status. + /// - the call failed for some reason and the library generated a + /// status. + /// + /// Note that implementations of this method attempt to receive initial + /// metadata from the server if initial metadata hasn't yet been received. + /// + /// \param[in] tag Tag identifying this request. + /// \param[out] status To be updated with the operation status. + virtual void Finish(::grpc::Status* status, void* tag) = 0; +}; + +/// An interface that yields a sequence of messages of type \a R. +template +class AsyncReaderInterface { + public: + virtual ~AsyncReaderInterface() {} + + /// Read a message of type \a R into \a msg. Completion will be notified by \a + /// tag on the associated completion queue. + /// This is thread-safe with respect to \a Write or \a WritesDone methods. It + /// should not be called concurrently with other streaming APIs + /// on the same stream. It is not meaningful to call it concurrently + /// with another \a AsyncReaderInterface::Read on the same stream since reads + /// on the same stream are delivered in order. + /// + /// \param[out] msg Where to eventually store the read message. + /// \param[in] tag The tag identifying the operation. + /// + /// Side effect: note that this method attempt to receive initial metadata for + /// a stream if it hasn't yet been received. + virtual void Read(R* msg, void* tag) = 0; +}; + +/// An interface that can be fed a sequence of messages of type \a W. +template +class AsyncWriterInterface { + public: + virtual ~AsyncWriterInterface() {} + + /// Request the writing of \a msg with identifying tag \a tag. + /// + /// Only one write may be outstanding at any given time. This means that + /// after calling Write, one must wait to receive \a tag from the completion + /// queue BEFORE calling Write again. + /// This is thread-safe with respect to \a AsyncReaderInterface::Read + /// + /// gRPC doesn't take ownership or a reference to \a msg, so it is safe to + /// to deallocate once Write returns. + /// + /// \param[in] msg The message to be written. + /// \param[in] tag The tag identifying the operation. + virtual void Write(const W& msg, void* tag) = 0; + + /// Request the writing of \a msg using WriteOptions \a options with + /// identifying tag \a tag. + /// + /// Only one write may be outstanding at any given time. This means that + /// after calling Write, one must wait to receive \a tag from the completion + /// queue BEFORE calling Write again. + /// WriteOptions \a options is used to set the write options of this message. + /// This is thread-safe with respect to \a AsyncReaderInterface::Read + /// + /// gRPC doesn't take ownership or a reference to \a msg, so it is safe to + /// to deallocate once Write returns. + /// + /// \param[in] msg The message to be written. + /// \param[in] options The WriteOptions to be used to write this message. + /// \param[in] tag The tag identifying the operation. + virtual void Write(const W& msg, ::grpc::WriteOptions options, void* tag) = 0; + + /// Request the writing of \a msg and coalesce it with the writing + /// of trailing metadata, using WriteOptions \a options with + /// identifying tag \a tag. + /// + /// For client, WriteLast is equivalent of performing Write and + /// WritesDone in a single step. + /// For server, WriteLast buffers the \a msg. The writing of \a msg is held + /// until Finish is called, where \a msg and trailing metadata are coalesced + /// and write is initiated. Note that WriteLast can only buffer \a msg up to + /// the flow control window size. If \a msg size is larger than the window + /// size, it will be sent on wire without buffering. + /// + /// gRPC doesn't take ownership or a reference to \a msg, so it is safe to + /// to deallocate once Write returns. + /// + /// \param[in] msg The message to be written. + /// \param[in] options The WriteOptions to be used to write this message. + /// \param[in] tag The tag identifying the operation. + void WriteLast(const W& msg, ::grpc::WriteOptions options, void* tag) { + Write(msg, options.set_last_message(), tag); + } +}; + +} // namespace internal + +template +class ClientAsyncReaderInterface + : public internal::ClientAsyncStreamingInterface, + public internal::AsyncReaderInterface {}; + +namespace internal { +template +class ClientAsyncReaderFactory { + public: + /// Create a stream object. + /// Write the first request out if \a start is set. + /// \a tag will be notified on \a cq when the call has been started and + /// \a request has been written out. If \a start is not set, \a tag must be + /// nullptr and the actual call must be initiated by StartCall + /// Note that \a context will be used to fill in custom initial metadata + /// used to send to the server when starting the call. + template + static ClientAsyncReader* Create(::grpc::ChannelInterface* channel, + ::grpc_impl::CompletionQueue* cq, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context, + const W& request, bool start, void* tag) { + ::grpc::internal::Call call = channel->CreateCall(method, context, cq); + return new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(ClientAsyncReader))) + ClientAsyncReader(call, context, request, start, tag); + } +}; +} // namespace internal + +/// Async client-side API for doing server-streaming RPCs, +/// where the incoming message stream coming from the server has +/// messages of type \a R. +template +class ClientAsyncReader final : public ClientAsyncReaderInterface { + public: + // always allocated against a call arena, no memory free required + static void operator delete(void* ptr, std::size_t size) { + assert(size == sizeof(ClientAsyncReader)); + } + + // 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(void* tag) override { + assert(!started_); + started_ = true; + StartCallInternal(tag); + } + + /// See the \a ClientAsyncStreamingInterface.ReadInitialMetadata + /// method for semantics. + /// + /// Side effect: + /// - upon receiving initial metadata from the server, + /// the \a ClientContext associated with this call is updated, and the + /// calling code can access the received metadata through the + /// \a ClientContext. + void ReadInitialMetadata(void* tag) override { + assert(started_); + GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); + + meta_ops_.set_output_tag(tag); + meta_ops_.RecvInitialMetadata(context_); + call_.PerformOps(&meta_ops_); + } + + void Read(R* msg, void* tag) override { + assert(started_); + read_ops_.set_output_tag(tag); + if (!context_->initial_metadata_received_) { + read_ops_.RecvInitialMetadata(context_); + } + read_ops_.RecvMessage(msg); + call_.PerformOps(&read_ops_); + } + + /// See the \a ClientAsyncStreamingInterface.Finish method for semantics. + /// + /// Side effect: + /// - the \a ClientContext associated with this call is updated with + /// possible initial and trailing metadata received from the server. + void Finish(::grpc::Status* status, void* tag) override { + assert(started_); + finish_ops_.set_output_tag(tag); + if (!context_->initial_metadata_received_) { + finish_ops_.RecvInitialMetadata(context_); + } + finish_ops_.ClientRecvStatus(context_, status); + call_.PerformOps(&finish_ops_); + } + + private: + friend class internal::ClientAsyncReaderFactory; + template + ClientAsyncReader(::grpc::internal::Call call, + ::grpc_impl::ClientContext* context, const W& request, + bool start, void* tag) + : context_(context), call_(call), started_(start) { + // TODO(ctiller): don't assert + GPR_CODEGEN_ASSERT(init_ops_.SendMessage(request).ok()); + init_ops_.ClientSendClose(); + if (start) { + StartCallInternal(tag); + } else { + assert(tag == nullptr); + } + } + + void StartCallInternal(void* tag) { + init_ops_.SendInitialMetadata(&context_->send_initial_metadata_, + context_->initial_metadata_flags()); + init_ops_.set_output_tag(tag); + call_.PerformOps(&init_ops_); + } + + ::grpc_impl::ClientContext* context_; + ::grpc::internal::Call call_; + bool started_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpClientSendClose> + init_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> + meta_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpRecvMessage> + read_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpClientRecvStatus> + finish_ops_; +}; + +/// Common interface for client side asynchronous writing. +template +class ClientAsyncWriterInterface + : public internal::ClientAsyncStreamingInterface, + public internal::AsyncWriterInterface { + public: + /// Signal the client is done with the writes (half-close the client stream). + /// Thread-safe with respect to \a AsyncReaderInterface::Read + /// + /// \param[in] tag The tag identifying the operation. + virtual void WritesDone(void* tag) = 0; +}; + +namespace internal { +template +class ClientAsyncWriterFactory { + public: + /// Create a stream object. + /// Start the RPC if \a start is set + /// \a tag will be notified on \a cq when the call has been started (i.e. + /// intitial metadata sent) and \a request has been written out. + /// If \a start is not set, \a tag must be nullptr and the actual call + /// must be initiated by StartCall + /// Note that \a context will be used to fill in custom initial metadata + /// used to send to the server when starting the call. + /// \a response will be filled in with the single expected response + /// message from the server upon a successful call to the \a Finish + /// method of this instance. + template + static ClientAsyncWriter* Create(::grpc::ChannelInterface* channel, + ::grpc_impl::CompletionQueue* cq, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context, + R* response, bool start, void* tag) { + ::grpc::internal::Call call = channel->CreateCall(method, context, cq); + return new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(ClientAsyncWriter))) + ClientAsyncWriter(call, context, response, start, tag); + } +}; +} // namespace internal + +/// Async API on the client side for doing client-streaming RPCs, +/// where the outgoing message stream going to the server contains +/// messages of type \a W. +template +class ClientAsyncWriter final : public ClientAsyncWriterInterface { + public: + // always allocated against a call arena, no memory free required + static void operator delete(void* ptr, std::size_t size) { + assert(size == sizeof(ClientAsyncWriter)); + } + + // 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(void* tag) override { + assert(!started_); + started_ = true; + StartCallInternal(tag); + } + + /// See the \a ClientAsyncStreamingInterface.ReadInitialMetadata method for + /// semantics. + /// + /// Side effect: + /// - upon receiving initial metadata from the server, the \a ClientContext + /// associated with this call is updated, and the calling code can access + /// the received metadata through the \a ClientContext. + void ReadInitialMetadata(void* tag) override { + assert(started_); + GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); + + meta_ops_.set_output_tag(tag); + meta_ops_.RecvInitialMetadata(context_); + call_.PerformOps(&meta_ops_); + } + + void Write(const W& msg, void* tag) override { + assert(started_); + write_ops_.set_output_tag(tag); + // TODO(ctiller): don't assert + GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok()); + call_.PerformOps(&write_ops_); + } + + void Write(const W& msg, ::grpc::WriteOptions options, void* tag) override { + assert(started_); + write_ops_.set_output_tag(tag); + if (options.is_last_message()) { + options.set_buffer_hint(); + write_ops_.ClientSendClose(); + } + // TODO(ctiller): don't assert + GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok()); + call_.PerformOps(&write_ops_); + } + + void WritesDone(void* tag) override { + assert(started_); + write_ops_.set_output_tag(tag); + write_ops_.ClientSendClose(); + call_.PerformOps(&write_ops_); + } + + /// See the \a ClientAsyncStreamingInterface.Finish method for semantics. + /// + /// Side effect: + /// - the \a ClientContext associated with this call is updated with + /// possible initial and trailing metadata received from the server. + /// - attempts to fill in the \a response parameter passed to this class's + /// constructor with the server's response message. + void Finish(::grpc::Status* status, void* tag) override { + assert(started_); + finish_ops_.set_output_tag(tag); + if (!context_->initial_metadata_received_) { + finish_ops_.RecvInitialMetadata(context_); + } + finish_ops_.ClientRecvStatus(context_, status); + call_.PerformOps(&finish_ops_); + } + + private: + friend class internal::ClientAsyncWriterFactory; + template + ClientAsyncWriter(::grpc::internal::Call call, + ::grpc_impl::ClientContext* context, R* response, + bool start, void* tag) + : context_(context), call_(call), started_(start) { + finish_ops_.RecvMessage(response); + finish_ops_.AllowNoMessage(); + if (start) { + StartCallInternal(tag); + } else { + assert(tag == nullptr); + } + } + + void StartCallInternal(void* tag) { + write_ops_.SendInitialMetadata(&context_->send_initial_metadata_, + context_->initial_metadata_flags()); + // if corked bit is set in context, we just keep the initial metadata + // buffered up to coalesce with later message send. No op is performed. + if (!context_->initial_metadata_corked_) { + write_ops_.set_output_tag(tag); + call_.PerformOps(&write_ops_); + } + } + + ::grpc_impl::ClientContext* context_; + ::grpc::internal::Call call_; + bool started_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> + meta_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpClientSendClose> + write_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpGenericRecvMessage, + ::grpc::internal::CallOpClientRecvStatus> + finish_ops_; +}; + +/// Async client-side interface for bi-directional streaming, +/// where the client-to-server message stream has messages of type \a W, +/// and the server-to-client message stream has messages of type \a R. +template +class ClientAsyncReaderWriterInterface + : public internal::ClientAsyncStreamingInterface, + public internal::AsyncWriterInterface, + public internal::AsyncReaderInterface { + public: + /// Signal the client is done with the writes (half-close the client stream). + /// Thread-safe with respect to \a AsyncReaderInterface::Read + /// + /// \param[in] tag The tag identifying the operation. + virtual void WritesDone(void* tag) = 0; +}; + +namespace internal { +template +class ClientAsyncReaderWriterFactory { + public: + /// Create a stream object. + /// Start the RPC request if \a start is set. + /// \a tag will be notified on \a cq when the call has been started (i.e. + /// intitial metadata sent). If \a start is not set, \a tag must be + /// nullptr and the actual call must be initiated by StartCall + /// Note that \a context will be used to fill in custom initial metadata + /// used to send to the server when starting the call. + static ClientAsyncReaderWriter* Create( + ::grpc::ChannelInterface* channel, ::grpc_impl::CompletionQueue* cq, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context, bool start, void* tag) { + ::grpc::internal::Call call = channel->CreateCall(method, context, cq); + + return new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(ClientAsyncReaderWriter))) + ClientAsyncReaderWriter(call, context, start, tag); + } +}; +} // namespace internal + +/// Async client-side interface for bi-directional streaming, +/// where the outgoing message stream going to the server +/// has messages of type \a W, and the incoming message stream coming +/// from the server has messages of type \a R. +template +class ClientAsyncReaderWriter final + : public ClientAsyncReaderWriterInterface { + public: + // always allocated against a call arena, no memory free required + static void operator delete(void* ptr, std::size_t size) { + assert(size == sizeof(ClientAsyncReaderWriter)); + } + + // 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(void* tag) override { + assert(!started_); + started_ = true; + StartCallInternal(tag); + } + + /// See the \a ClientAsyncStreamingInterface.ReadInitialMetadata method + /// for semantics of this method. + /// + /// Side effect: + /// - upon receiving initial metadata from the server, the \a ClientContext + /// is updated with it, and then the receiving initial metadata can + /// be accessed through this \a ClientContext. + void ReadInitialMetadata(void* tag) override { + assert(started_); + GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); + + meta_ops_.set_output_tag(tag); + meta_ops_.RecvInitialMetadata(context_); + call_.PerformOps(&meta_ops_); + } + + void Read(R* msg, void* tag) override { + assert(started_); + read_ops_.set_output_tag(tag); + if (!context_->initial_metadata_received_) { + read_ops_.RecvInitialMetadata(context_); + } + read_ops_.RecvMessage(msg); + call_.PerformOps(&read_ops_); + } + + void Write(const W& msg, void* tag) override { + assert(started_); + write_ops_.set_output_tag(tag); + // TODO(ctiller): don't assert + GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok()); + call_.PerformOps(&write_ops_); + } + + void Write(const W& msg, ::grpc::WriteOptions options, void* tag) override { + assert(started_); + write_ops_.set_output_tag(tag); + if (options.is_last_message()) { + options.set_buffer_hint(); + write_ops_.ClientSendClose(); + } + // TODO(ctiller): don't assert + GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok()); + call_.PerformOps(&write_ops_); + } + + void WritesDone(void* tag) override { + assert(started_); + write_ops_.set_output_tag(tag); + write_ops_.ClientSendClose(); + call_.PerformOps(&write_ops_); + } + + /// See the \a ClientAsyncStreamingInterface.Finish method for semantics. + /// Side effect + /// - the \a ClientContext associated with this call is updated with + /// possible initial and trailing metadata sent from the server. + void Finish(::grpc::Status* status, void* tag) override { + assert(started_); + finish_ops_.set_output_tag(tag); + if (!context_->initial_metadata_received_) { + finish_ops_.RecvInitialMetadata(context_); + } + finish_ops_.ClientRecvStatus(context_, status); + call_.PerformOps(&finish_ops_); + } + + private: + friend class internal::ClientAsyncReaderWriterFactory; + ClientAsyncReaderWriter(::grpc::internal::Call call, + ::grpc_impl::ClientContext* context, bool start, + void* tag) + : context_(context), call_(call), started_(start) { + if (start) { + StartCallInternal(tag); + } else { + assert(tag == nullptr); + } + } + + void StartCallInternal(void* tag) { + write_ops_.SendInitialMetadata(&context_->send_initial_metadata_, + context_->initial_metadata_flags()); + // if corked bit is set in context, we just keep the initial metadata + // buffered up to coalesce with later message send. No op is performed. + if (!context_->initial_metadata_corked_) { + write_ops_.set_output_tag(tag); + call_.PerformOps(&write_ops_); + } + } + + ::grpc_impl::ClientContext* context_; + ::grpc::internal::Call call_; + bool started_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> + meta_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpRecvMessage> + read_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpClientSendClose> + write_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpClientRecvStatus> + finish_ops_; +}; + +template +class ServerAsyncReaderInterface + : public ::grpc::internal::ServerAsyncStreamingInterface, + public internal::AsyncReaderInterface { + public: + /// Indicate that the stream is to be finished with a certain status code + /// and also send out \a msg response to the client. + /// Request notification for when the server has sent the response and the + /// appropriate signals to the client to end the call. + /// Should not be used concurrently with other operations. + /// + /// It is appropriate to call this method when: + /// * all messages from the client have been received (either known + /// implictly, or explicitly because a previous + /// \a AsyncReaderInterface::Read operation with a non-ok result, + /// e.g., cq->Next(&read_tag, &ok) filled in 'ok' with 'false'). + /// + /// This operation will end when the server has finished sending out initial + /// metadata (if not sent already), response message, and status, or if + /// 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 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. + /// \param[in] msg To be sent to the client as the response for this call. + virtual void Finish(const W& msg, const ::grpc::Status& status, + void* tag) = 0; + + /// Indicate that the stream is to be finished with a certain + /// non-OK status code. + /// Request notification for when the server has sent the appropriate + /// signals to the client to end the call. + /// Should not be used concurrently with other operations. + /// + /// This call is meant to end the call with some error, and can be called at + /// any point that the server would like to "fail" the call (though note + /// this shouldn't be called concurrently with any other "sending" call, like + /// \a AsyncWriterInterface::Write). + /// + /// This operation will end when the server has finished sending out initial + /// metadata (if not sent already), and status, or if some failure occurred + /// when trying to do so. + /// + /// gRPC doesn't take ownership or a reference to \a status, so it is safe to + /// to deallocate once FinishWithError returns. + /// + /// \param[in] tag Tag identifying this request. + /// \param[in] status To be sent to the client as the result of this call. + /// - Note: \a status must have a non-OK code. + virtual void FinishWithError(const ::grpc::Status& status, void* tag) = 0; +}; + +/// Async server-side API for doing client-streaming RPCs, +/// where the incoming message stream from the client has messages of type \a R, +/// and the single response message sent from the server is type \a W. +template +class ServerAsyncReader final : public ServerAsyncReaderInterface { + public: + explicit ServerAsyncReader(::grpc_impl::ServerContext* ctx) + : call_(nullptr, nullptr, nullptr), ctx_(ctx) {} + + /// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics. + /// + /// Implicit input parameter: + /// - The initial metadata that will be sent to the client from this op will + /// be taken from the \a ServerContext associated with the call. + void SendInitialMetadata(void* tag) override { + GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); + + meta_ops_.set_output_tag(tag); + meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + meta_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + call_.PerformOps(&meta_ops_); + } + + void Read(R* msg, void* tag) override { + read_ops_.set_output_tag(tag); + read_ops_.RecvMessage(msg); + call_.PerformOps(&read_ops_); + } + + /// See the \a ServerAsyncReaderInterface.Read method for semantics + /// + /// Side effect: + /// - also sends initial metadata if not alreay sent. + /// - uses the \a ServerContext associated with this call to send possible + /// initial and trailing metadata. + /// + /// 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 deallocate once Finish returns. + void Finish(const W& msg, const ::grpc::Status& status, void* tag) override { + finish_ops_.set_output_tag(tag); + if (!ctx_->sent_initial_metadata_) { + finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + finish_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + } + // The response is dropped if the status is not OK. + if (status.ok()) { + finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, + finish_ops_.SendMessage(msg)); + } else { + finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status); + } + call_.PerformOps(&finish_ops_); + } + + /// See the \a ServerAsyncReaderInterface.Read method for semantics + /// + /// Side effect: + /// - also sends initial metadata if not alreay sent. + /// - uses the \a ServerContext associated with this call to send possible + /// initial and trailing metadata. + /// + /// gRPC doesn't take ownership or a reference to \a status, so it is safe to + /// to deallocate once FinishWithError returns. + void FinishWithError(const ::grpc::Status& status, void* tag) override { + GPR_CODEGEN_ASSERT(!status.ok()); + finish_ops_.set_output_tag(tag); + if (!ctx_->sent_initial_metadata_) { + finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + finish_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + } + finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status); + call_.PerformOps(&finish_ops_); + } + + private: + void BindCall(::grpc::internal::Call* call) override { call_ = *call; } + + ::grpc::internal::Call call_; + ::grpc_impl::ServerContext* ctx_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> + meta_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage> read_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpServerSendStatus> + finish_ops_; +}; + +template +class ServerAsyncWriterInterface + : public ::grpc::internal::ServerAsyncStreamingInterface, + public internal::AsyncWriterInterface { + public: + /// Indicate that the stream is to be finished with a certain status code. + /// Request notification for when the server has sent the appropriate + /// signals to the client to end the call. + /// Should not be used concurrently with other operations. + /// + /// It is appropriate to call this method when either: + /// * all messages from the client have been received (either known + /// implictly, or explicitly because a previous \a + /// AsyncReaderInterface::Read operation with a non-ok + /// result (e.g., cq->Next(&read_tag, &ok) filled in 'ok' with 'false'. + /// * it is desired to end the call early with some non-OK status code. + /// + /// This operation will end when the server has finished sending out initial + /// metadata (if not sent already), response message, and status, or if + /// some failure occurred when trying to do so. + /// + /// gRPC doesn't take ownership or a reference to \a status, so it is safe to + /// 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. + virtual void Finish(const ::grpc::Status& status, void* tag) = 0; + + /// Request the writing of \a msg and coalesce it with trailing metadata which + /// contains \a status, using WriteOptions options with + /// identifying tag \a tag. + /// + /// WriteAndFinish is equivalent of performing WriteLast and Finish + /// in a single step. + /// + /// gRPC doesn't take ownership or a reference to \a msg and \a status, so it + /// 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. + /// \param[in] status The Status that server returns to client. + /// \param[in] tag The tag identifying the operation. + virtual void WriteAndFinish(const W& msg, ::grpc::WriteOptions options, + const ::grpc::Status& status, void* tag) = 0; +}; + +/// Async server-side API for doing server streaming RPCs, +/// where the outgoing message stream from the server has messages of type \a W. +template +class ServerAsyncWriter final : public ServerAsyncWriterInterface { + public: + explicit ServerAsyncWriter(::grpc_impl::ServerContext* ctx) + : call_(nullptr, nullptr, nullptr), ctx_(ctx) {} + + /// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics. + /// + /// Implicit input parameter: + /// - The initial metadata that will be sent to the client from this op will + /// be taken from the \a ServerContext associated with the call. + /// + /// \param[in] tag Tag identifying this request. + void SendInitialMetadata(void* tag) override { + GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); + + meta_ops_.set_output_tag(tag); + meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + meta_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + call_.PerformOps(&meta_ops_); + } + + void Write(const W& msg, void* tag) override { + write_ops_.set_output_tag(tag); + EnsureInitialMetadataSent(&write_ops_); + // TODO(ctiller): don't assert + GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok()); + call_.PerformOps(&write_ops_); + } + + void Write(const W& msg, ::grpc::WriteOptions options, void* tag) override { + write_ops_.set_output_tag(tag); + if (options.is_last_message()) { + options.set_buffer_hint(); + } + + EnsureInitialMetadataSent(&write_ops_); + // TODO(ctiller): don't assert + GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok()); + call_.PerformOps(&write_ops_); + } + + /// See the \a ServerAsyncWriterInterface.WriteAndFinish method for semantics. + /// + /// Implicit input parameter: + /// - the \a ServerContext associated with this call is used + /// for sending trailing (and initial) metadata to the client. + /// + /// 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 deallocate once WriteAndFinish returns. + void WriteAndFinish(const W& msg, ::grpc::WriteOptions options, + const ::grpc::Status& status, void* tag) override { + write_ops_.set_output_tag(tag); + EnsureInitialMetadataSent(&write_ops_); + options.set_buffer_hint(); + GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok()); + write_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status); + call_.PerformOps(&write_ops_); + } + + /// See the \a ServerAsyncWriterInterface.Finish method for semantics. + /// + /// Implicit input parameter: + /// - the \a ServerContext associated with this call is used for sending + /// trailing (and initial if not already sent) metadata to the client. + /// + /// Note: there are no restrictions are the code of + /// \a status,it may be non-OK + /// + /// gRPC doesn't take ownership or a reference to \a status, so it is safe to + /// to deallocate once Finish returns. + void Finish(const ::grpc::Status& status, void* tag) override { + finish_ops_.set_output_tag(tag); + EnsureInitialMetadataSent(&finish_ops_); + finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status); + call_.PerformOps(&finish_ops_); + } + + private: + void BindCall(::grpc::internal::Call* call) override { call_ = *call; } + + template + void EnsureInitialMetadataSent(T* ops) { + if (!ctx_->sent_initial_metadata_) { + ops->SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + ops->set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + } + } + + ::grpc::internal::Call call_; + ::grpc_impl::ServerContext* ctx_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> + meta_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpServerSendStatus> + write_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpServerSendStatus> + finish_ops_; +}; + +/// Server-side interface for asynchronous bi-directional streaming. +template +class ServerAsyncReaderWriterInterface + : public ::grpc::internal::ServerAsyncStreamingInterface, + public internal::AsyncWriterInterface, + public internal::AsyncReaderInterface { + public: + /// Indicate that the stream is to be finished with a certain status code. + /// Request notification for when the server has sent the appropriate + /// signals to the client to end the call. + /// Should not be used concurrently with other operations. + /// + /// It is appropriate to call this method when either: + /// * all messages from the client have been received (either known + /// implictly, or explicitly because a previous \a + /// AsyncReaderInterface::Read operation + /// with a non-ok result (e.g., cq->Next(&read_tag, &ok) filled in 'ok' + /// with 'false'. + /// * it is desired to end the call early with some non-OK status code. + /// + /// This operation will end when the server has finished sending out initial + /// metadata (if not sent already), response message, and status, or if some + /// failure occurred when trying to do so. + /// + /// gRPC doesn't take ownership or a reference to \a status, so it is safe to + /// 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. + virtual void Finish(const ::grpc::Status& status, void* tag) = 0; + + /// Request the writing of \a msg and coalesce it with trailing metadata which + /// contains \a status, using WriteOptions options with + /// identifying tag \a tag. + /// + /// WriteAndFinish is equivalent of performing WriteLast and Finish in a + /// single step. + /// + /// gRPC doesn't take ownership or a reference to \a msg and \a status, so it + /// 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. + /// \param[in] status The Status that server returns to client. + /// \param[in] tag The tag identifying the operation. + virtual void WriteAndFinish(const W& msg, ::grpc::WriteOptions options, + const ::grpc::Status& status, void* tag) = 0; +}; + +/// Async server-side API for doing bidirectional streaming RPCs, +/// where the incoming message stream coming from the client has messages of +/// type \a R, and the outgoing message stream coming from the server has +/// messages of type \a W. +template +class ServerAsyncReaderWriter final + : public ServerAsyncReaderWriterInterface { + public: + explicit ServerAsyncReaderWriter(::grpc_impl::ServerContext* ctx) + : call_(nullptr, nullptr, nullptr), ctx_(ctx) {} + + /// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics. + /// + /// Implicit input parameter: + /// - The initial metadata that will be sent to the client from this op will + /// be taken from the \a ServerContext associated with the call. + /// + /// \param[in] tag Tag identifying this request. + void SendInitialMetadata(void* tag) override { + GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); + + meta_ops_.set_output_tag(tag); + meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + meta_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + call_.PerformOps(&meta_ops_); + } + + void Read(R* msg, void* tag) override { + read_ops_.set_output_tag(tag); + read_ops_.RecvMessage(msg); + call_.PerformOps(&read_ops_); + } + + void Write(const W& msg, void* tag) override { + write_ops_.set_output_tag(tag); + EnsureInitialMetadataSent(&write_ops_); + // TODO(ctiller): don't assert + GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok()); + call_.PerformOps(&write_ops_); + } + + void Write(const W& msg, ::grpc::WriteOptions options, void* tag) override { + write_ops_.set_output_tag(tag); + if (options.is_last_message()) { + options.set_buffer_hint(); + } + EnsureInitialMetadataSent(&write_ops_); + GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok()); + call_.PerformOps(&write_ops_); + } + + /// See the \a ServerAsyncReaderWriterInterface.WriteAndFinish + /// method for semantics. + /// + /// Implicit input parameter: + /// - the \a ServerContext associated with this call is used + /// for sending trailing (and initial) metadata to the client. + /// + /// 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 deallocate once WriteAndFinish returns. + void WriteAndFinish(const W& msg, ::grpc::WriteOptions options, + const ::grpc::Status& status, void* tag) override { + write_ops_.set_output_tag(tag); + EnsureInitialMetadataSent(&write_ops_); + options.set_buffer_hint(); + GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok()); + write_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status); + call_.PerformOps(&write_ops_); + } + + /// See the \a ServerAsyncReaderWriterInterface.Finish method for semantics. + /// + /// Implicit input parameter: + /// - the \a ServerContext associated with this call is used for sending + /// trailing (and initial if not already sent) metadata to the client. + /// + /// Note: there are no restrictions are the code of \a status, + /// it may be non-OK + // + /// gRPC doesn't take ownership or a reference to \a status, so it is safe to + /// to deallocate once Finish returns. + void Finish(const ::grpc::Status& status, void* tag) override { + finish_ops_.set_output_tag(tag); + EnsureInitialMetadataSent(&finish_ops_); + + finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status); + call_.PerformOps(&finish_ops_); + } + + private: + friend class ::grpc_impl::Server; + + void BindCall(::grpc::internal::Call* call) override { call_ = *call; } + + template + void EnsureInitialMetadataSent(T* ops) { + if (!ctx_->sent_initial_metadata_) { + ops->SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + ops->set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + } + } + + ::grpc::internal::Call call_; + ::grpc_impl::ServerContext* ctx_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> + meta_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage> read_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpServerSendStatus> + write_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpServerSendStatus> + finish_ops_; +}; + +} // namespace grpc_impl +#endif // GRPCPP_IMPL_CODEGEN_ASYNC_STREAM_IMPL_H diff --git a/include/grpcpp/impl/codegen/async_unary_call.h b/include/grpcpp/impl/codegen/async_unary_call.h index 5da6a649f14..64ee17dec0d 100644 --- a/include/grpcpp/impl/codegen/async_unary_call.h +++ b/include/grpcpp/impl/codegen/async_unary_call.h @@ -19,299 +19,18 @@ #ifndef GRPCPP_IMPL_CODEGEN_ASYNC_UNARY_CALL_H #define GRPCPP_IMPL_CODEGEN_ASYNC_UNARY_CALL_H -#include -#include -#include -#include -#include -#include -#include +#include namespace grpc { - -extern CoreCodegenInterface* g_core_codegen_interface; - -/// An interface relevant for async client side unary RPCs (which send -/// one request message to a server and receive one response message). -template -class ClientAsyncResponseReaderInterface { - public: - virtual ~ClientAsyncResponseReaderInterface() {} - - /// Start the call that was set up by the constructor, but only if the - /// constructor was invoked through the "Prepare" API which doesn't actually - /// start the call - virtual void StartCall() = 0; - - /// Request notification of the reading of initial metadata. Completion - /// will be notified by \a tag on the associated completion queue. - /// This call is optional, but if it is used, it cannot be used concurrently - /// with or after the \a Finish method. - /// - /// \param[in] tag Tag identifying this request. - virtual void ReadInitialMetadata(void* tag) = 0; - - /// Request to receive the server's response \a msg and final \a status for - /// the call, and to notify \a tag on this call's completion queue when - /// finished. - /// - /// This function will return when either: - /// - when the server's response message and status have been received. - /// - when the server has returned a non-OK status (no message expected in - /// this case). - /// - when the call failed for some reason and the library generated a - /// non-OK status. - /// - /// \param[in] tag Tag identifying this request. - /// \param[out] status To be updated with the operation status. - /// \param[out] msg To be filled in with the server's response message. - virtual void Finish(R* msg, Status* status, void* tag) = 0; -}; - -namespace internal { template -class ClientAsyncResponseReaderFactory { - public: - /// Start a call and write the request out if \a start is set. - /// \a tag will be notified on \a cq when the call has been started (i.e. - /// intitial metadata sent) and \a request has been written out. - /// If \a start is not set, the actual call must be initiated by StartCall - /// Note that \a context will be used to fill in custom initial metadata - /// used to send to the server when starting the call. - template - static ClientAsyncResponseReader* Create( - ChannelInterface* channel, ::grpc_impl::CompletionQueue* cq, - const ::grpc::internal::RpcMethod& method, - ::grpc_impl::ClientContext* context, const W& request, bool start) { - ::grpc::internal::Call call = channel->CreateCall(method, context, cq); - return new (g_core_codegen_interface->grpc_call_arena_alloc( - call.call(), sizeof(ClientAsyncResponseReader))) - ClientAsyncResponseReader(call, context, request, start); - } -}; -} // namespace internal - -/// Async API for client-side unary RPCs, where the message response -/// received from the server is of type \a R. +using ClientAsyncResponseReaderInterface = + grpc_impl::ClientAsyncResponseReaderInterface; template -class ClientAsyncResponseReader final - : public ClientAsyncResponseReaderInterface { - public: - // always allocated against a call arena, no memory free required - static void operator delete(void* ptr, std::size_t size) { - assert(size == sizeof(ClientAsyncResponseReader)); - } - - // 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 { - assert(!started_); - started_ = true; - StartCallInternal(); - } - - /// See \a ClientAsyncResponseReaderInterface::ReadInitialMetadata for - /// semantics. - /// - /// Side effect: - /// - the \a ClientContext associated with this call is updated with - /// possible initial and trailing metadata sent from the server. - void ReadInitialMetadata(void* tag) override { - assert(started_); - GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); - - single_buf.set_output_tag(tag); - single_buf.RecvInitialMetadata(context_); - call_.PerformOps(&single_buf); - initial_metadata_read_ = true; - } - - /// See \a ClientAysncResponseReaderInterface::Finish for semantics. - /// - /// Side effect: - /// - the \a ClientContext associated with this call is updated with - /// possible initial and trailing metadata sent from the server. - void Finish(R* msg, Status* status, void* tag) override { - assert(started_); - if (initial_metadata_read_) { - finish_buf.set_output_tag(tag); - finish_buf.RecvMessage(msg); - finish_buf.AllowNoMessage(); - finish_buf.ClientRecvStatus(context_, status); - call_.PerformOps(&finish_buf); - } else { - single_buf.set_output_tag(tag); - single_buf.RecvInitialMetadata(context_); - single_buf.RecvMessage(msg); - single_buf.AllowNoMessage(); - single_buf.ClientRecvStatus(context_, status); - call_.PerformOps(&single_buf); - } - } - - private: - friend class internal::ClientAsyncResponseReaderFactory; - ::grpc_impl::ClientContext* const context_; - ::grpc::internal::Call call_; - bool started_; - bool initial_metadata_read_ = false; +using ClientAsyncResponseReader = grpc_impl::ClientAsyncResponseReader; - template - ClientAsyncResponseReader(::grpc::internal::Call call, - ::grpc_impl::ClientContext* context, - const W& request, bool start) - : context_(context), call_(call), started_(start) { - // Bind the metadata at time of StartCallInternal but set up the rest here - // TODO(ctiller): don't assert - GPR_CODEGEN_ASSERT(single_buf.SendMessage(request).ok()); - single_buf.ClientSendClose(); - if (start) StartCallInternal(); - } - - void StartCallInternal() { - single_buf.SendInitialMetadata(&context_->send_initial_metadata_, - context_->initial_metadata_flags()); - } - - // disable operator new - static void* operator new(std::size_t size); - static void* operator new(std::size_t size, void* p) { return p; } - - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpClientSendClose, - ::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpRecvMessage, - ::grpc::internal::CallOpClientRecvStatus> - single_buf; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage, - ::grpc::internal::CallOpClientRecvStatus> - finish_buf; -}; - -/// Async server-side API for handling unary calls, where the single -/// response message sent to the client is of type \a W. template -class ServerAsyncResponseWriter final - : public internal::ServerAsyncStreamingInterface { - public: - explicit ServerAsyncResponseWriter(::grpc_impl::ServerContext* ctx) - : call_(nullptr, nullptr, nullptr), ctx_(ctx) {} - - /// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics. - /// - /// Side effect: - /// The initial metadata that will be sent to the client from this op will - /// be taken from the \a ServerContext associated with the call. - /// - /// \param[in] tag Tag identifying this request. - void SendInitialMetadata(void* tag) override { - GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); - - meta_buf_.set_output_tag(tag); - meta_buf_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - meta_buf_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - call_.PerformOps(&meta_buf_); - } - - /// Indicate that the stream is to be finished and request notification - /// when the server has sent the appropriate signals to the client to - /// end the call. Should not be used concurrently with other operations. - /// - /// \param[in] tag Tag identifying this request. - /// \param[in] status To be sent to the client as the result of the call. - /// \param[in] msg Message to be sent to the client. - /// - /// Side effect: - /// - also sends initial metadata if not already sent (using the - /// \a ServerContext associated with this call). - /// - /// Note: if \a status has a non-OK code, then \a msg will not be sent, - /// and the client will receive only the status with possible trailing - /// metadata. - void Finish(const W& msg, const Status& status, void* tag) { - finish_buf_.set_output_tag(tag); - finish_buf_.set_core_cq_tag(&finish_buf_); - if (!ctx_->sent_initial_metadata_) { - finish_buf_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - finish_buf_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - } - // The response is dropped if the status is not OK. - if (status.ok()) { - finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_, - finish_buf_.SendMessage(msg)); - } else { - finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_, status); - } - call_.PerformOps(&finish_buf_); - } - - /// Indicate that the stream is to be finished with a non-OK status, - /// and request notification for when the server has finished sending the - /// appropriate signals to the client to end the call. - /// Should not be used concurrently with other operations. - /// - /// \param[in] tag Tag identifying this request. - /// \param[in] status To be sent to the client as the result of the call. - /// - Note: \a status must have a non-OK code. - /// - /// Side effect: - /// - also sends initial metadata if not already sent (using the - /// \a ServerContext associated with this call). - void FinishWithError(const Status& status, void* tag) { - GPR_CODEGEN_ASSERT(!status.ok()); - finish_buf_.set_output_tag(tag); - if (!ctx_->sent_initial_metadata_) { - finish_buf_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - finish_buf_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - } - finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_, status); - call_.PerformOps(&finish_buf_); - } - - private: - void BindCall(::grpc::internal::Call* call) override { call_ = *call; } - - ::grpc::internal::Call call_; - ::grpc_impl::ServerContext* ctx_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> - meta_buf_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpServerSendStatus> - finish_buf_; -}; +using ServerAsyncResponseWriter = ::grpc_impl::ServerAsyncResponseWriter; } // namespace grpc -namespace std { -template -class default_delete> { - public: - void operator()(void* p) {} -}; -template -class default_delete> { - public: - void operator()(void* p) {} -}; -} // namespace std - #endif // GRPCPP_IMPL_CODEGEN_ASYNC_UNARY_CALL_H diff --git a/include/grpcpp/impl/codegen/async_unary_call_impl.h b/include/grpcpp/impl/codegen/async_unary_call_impl.h new file mode 100644 index 00000000000..ff8bf15602b --- /dev/null +++ b/include/grpcpp/impl/codegen/async_unary_call_impl.h @@ -0,0 +1,315 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPCPP_IMPL_CODEGEN_ASYNC_UNARY_CALL_IMPL_H +#define GRPCPP_IMPL_CODEGEN_ASYNC_UNARY_CALL_IMPL_H + +#include +#include +#include +#include +#include +#include +#include + +namespace grpc_impl { + +/// An interface relevant for async client side unary RPCs (which send +/// one request message to a server and receive one response message). +template +class ClientAsyncResponseReaderInterface { + public: + virtual ~ClientAsyncResponseReaderInterface() {} + + /// Start the call that was set up by the constructor, but only if the + /// constructor was invoked through the "Prepare" API which doesn't actually + /// start the call + virtual void StartCall() = 0; + + /// Request notification of the reading of initial metadata. Completion + /// will be notified by \a tag on the associated completion queue. + /// This call is optional, but if it is used, it cannot be used concurrently + /// with or after the \a Finish method. + /// + /// \param[in] tag Tag identifying this request. + virtual void ReadInitialMetadata(void* tag) = 0; + + /// Request to receive the server's response \a msg and final \a status for + /// the call, and to notify \a tag on this call's completion queue when + /// finished. + /// + /// This function will return when either: + /// - when the server's response message and status have been received. + /// - when the server has returned a non-OK status (no message expected in + /// this case). + /// - when the call failed for some reason and the library generated a + /// non-OK status. + /// + /// \param[in] tag Tag identifying this request. + /// \param[out] status To be updated with the operation status. + /// \param[out] msg To be filled in with the server's response message. + virtual void Finish(R* msg, ::grpc::Status* status, void* tag) = 0; +}; + +namespace internal { +template +class ClientAsyncResponseReaderFactory { + public: + /// Start a call and write the request out if \a start is set. + /// \a tag will be notified on \a cq when the call has been started (i.e. + /// intitial metadata sent) and \a request has been written out. + /// If \a start is not set, the actual call must be initiated by StartCall + /// Note that \a context will be used to fill in custom initial metadata + /// used to send to the server when starting the call. + template + static ClientAsyncResponseReader* Create( + ::grpc::ChannelInterface* channel, ::grpc_impl::CompletionQueue* cq, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context, const W& request, bool start) { + ::grpc::internal::Call call = channel->CreateCall(method, context, cq); + return new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(ClientAsyncResponseReader))) + ClientAsyncResponseReader(call, context, request, start); + } +}; +} // namespace internal + +/// Async API for client-side unary RPCs, where the message response +/// received from the server is of type \a R. +template +class ClientAsyncResponseReader final + : public ClientAsyncResponseReaderInterface { + public: + // always allocated against a call arena, no memory free required + static void operator delete(void* ptr, std::size_t size) { + assert(size == sizeof(ClientAsyncResponseReader)); + } + + // 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 { + assert(!started_); + started_ = true; + StartCallInternal(); + } + + /// See \a ClientAsyncResponseReaderInterface::ReadInitialMetadata for + /// semantics. + /// + /// Side effect: + /// - the \a ClientContext associated with this call is updated with + /// possible initial and trailing metadata sent from the server. + void ReadInitialMetadata(void* tag) override { + assert(started_); + GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); + + single_buf.set_output_tag(tag); + single_buf.RecvInitialMetadata(context_); + call_.PerformOps(&single_buf); + initial_metadata_read_ = true; + } + + /// See \a ClientAysncResponseReaderInterface::Finish for semantics. + /// + /// Side effect: + /// - the \a ClientContext associated with this call is updated with + /// possible initial and trailing metadata sent from the server. + void Finish(R* msg, ::grpc::Status* status, void* tag) override { + assert(started_); + if (initial_metadata_read_) { + finish_buf.set_output_tag(tag); + finish_buf.RecvMessage(msg); + finish_buf.AllowNoMessage(); + finish_buf.ClientRecvStatus(context_, status); + call_.PerformOps(&finish_buf); + } else { + single_buf.set_output_tag(tag); + single_buf.RecvInitialMetadata(context_); + single_buf.RecvMessage(msg); + single_buf.AllowNoMessage(); + single_buf.ClientRecvStatus(context_, status); + call_.PerformOps(&single_buf); + } + } + + private: + friend class internal::ClientAsyncResponseReaderFactory; + ::grpc_impl::ClientContext* const context_; + ::grpc::internal::Call call_; + bool started_; + bool initial_metadata_read_ = false; + + template + ClientAsyncResponseReader(::grpc::internal::Call call, + ::grpc_impl::ClientContext* context, + const W& request, bool start) + : context_(context), call_(call), started_(start) { + // Bind the metadata at time of StartCallInternal but set up the rest here + // TODO(ctiller): don't assert + GPR_CODEGEN_ASSERT(single_buf.SendMessage(request).ok()); + single_buf.ClientSendClose(); + if (start) StartCallInternal(); + } + + void StartCallInternal() { + single_buf.SendInitialMetadata(&context_->send_initial_metadata_, + context_->initial_metadata_flags()); + } + + // disable operator new + static void* operator new(std::size_t size); + static void* operator new(std::size_t size, void* p) { return p; } + + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpClientSendClose, + ::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpRecvMessage, + ::grpc::internal::CallOpClientRecvStatus> + single_buf; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage, + ::grpc::internal::CallOpClientRecvStatus> + finish_buf; +}; + +/// Async server-side API for handling unary calls, where the single +/// response message sent to the client is of type \a W. +template +class ServerAsyncResponseWriter final + : public ::grpc::internal::ServerAsyncStreamingInterface { + public: + explicit ServerAsyncResponseWriter(::grpc_impl::ServerContext* ctx) + : call_(nullptr, nullptr, nullptr), ctx_(ctx) {} + + /// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics. + /// + /// Side effect: + /// The initial metadata that will be sent to the client from this op will + /// be taken from the \a ServerContext associated with the call. + /// + /// \param[in] tag Tag identifying this request. + void SendInitialMetadata(void* tag) override { + GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); + + meta_buf_.set_output_tag(tag); + meta_buf_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + meta_buf_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + call_.PerformOps(&meta_buf_); + } + + /// Indicate that the stream is to be finished and request notification + /// when the server has sent the appropriate signals to the client to + /// end the call. Should not be used concurrently with other operations. + /// + /// \param[in] tag Tag identifying this request. + /// \param[in] status To be sent to the client as the result of the call. + /// \param[in] msg Message to be sent to the client. + /// + /// Side effect: + /// - also sends initial metadata if not already sent (using the + /// \a ServerContext associated with this call). + /// + /// Note: if \a status has a non-OK code, then \a msg will not be sent, + /// and the client will receive only the status with possible trailing + /// metadata. + void Finish(const W& msg, const ::grpc::Status& status, void* tag) { + finish_buf_.set_output_tag(tag); + finish_buf_.set_core_cq_tag(&finish_buf_); + if (!ctx_->sent_initial_metadata_) { + finish_buf_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + finish_buf_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + } + // The response is dropped if the status is not OK. + if (status.ok()) { + finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_, + finish_buf_.SendMessage(msg)); + } else { + finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_, status); + } + call_.PerformOps(&finish_buf_); + } + + /// Indicate that the stream is to be finished with a non-OK status, + /// and request notification for when the server has finished sending the + /// appropriate signals to the client to end the call. + /// Should not be used concurrently with other operations. + /// + /// \param[in] tag Tag identifying this request. + /// \param[in] status To be sent to the client as the result of the call. + /// - Note: \a status must have a non-OK code. + /// + /// Side effect: + /// - also sends initial metadata if not already sent (using the + /// \a ServerContext associated with this call). + void FinishWithError(const ::grpc::Status& status, void* tag) { + GPR_CODEGEN_ASSERT(!status.ok()); + finish_buf_.set_output_tag(tag); + if (!ctx_->sent_initial_metadata_) { + finish_buf_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + finish_buf_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + } + finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_, status); + call_.PerformOps(&finish_buf_); + } + + private: + void BindCall(::grpc::internal::Call* call) override { call_ = *call; } + + ::grpc::internal::Call call_; + ::grpc_impl::ServerContext* ctx_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> + meta_buf_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpServerSendStatus> + finish_buf_; +}; + +} // namespace grpc_impl + +namespace std { +template +class default_delete<::grpc_impl::ClientAsyncResponseReader> { + public: + void operator()(void* p) {} +}; +template +class default_delete<::grpc_impl::ClientAsyncResponseReaderInterface> { + public: + void operator()(void* p) {} +}; +} // namespace std + +#endif // GRPCPP_IMPL_CODEGEN_ASYNC_UNARY_CALL_IMPL_H diff --git a/include/grpcpp/impl/codegen/byte_buffer.h b/include/grpcpp/impl/codegen/byte_buffer.h index e2ba9344bcb..0b7be6fc753 100644 --- a/include/grpcpp/impl/codegen/byte_buffer.h +++ b/include/grpcpp/impl/codegen/byte_buffer.h @@ -29,6 +29,17 @@ #include +namespace grpc_impl { +namespace internal { + +template +class CallbackUnaryHandler; +template +class CallbackServerStreamingHandler; + +} // namespace internal +} // namespace grpc_impl + namespace grpc { class ServerInterface; @@ -45,10 +56,6 @@ template class RpcMethodHandler; template class ServerStreamingHandler; -template -class CallbackUnaryHandler; -template -class CallbackServerStreamingHandler; template class ErrorMethodHandler; class ExternalConnectionAcceptorImpl; @@ -176,9 +183,9 @@ class ByteBuffer final { template friend class internal::ServerStreamingHandler; template - friend class internal::CallbackUnaryHandler; + friend class ::grpc_impl::internal::CallbackUnaryHandler; template - friend class ::grpc::internal::CallbackServerStreamingHandler; + friend class ::grpc_impl::internal::CallbackServerStreamingHandler; template friend class internal::ErrorMethodHandler; template diff --git a/include/grpcpp/impl/codegen/call_op_set.h b/include/grpcpp/impl/codegen/call_op_set.h index d0958bbb251..84d1407cbe2 100644 --- a/include/grpcpp/impl/codegen/call_op_set.h +++ b/include/grpcpp/impl/codegen/call_op_set.h @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/grpcpp/impl/codegen/channel_interface.h b/include/grpcpp/impl/codegen/channel_interface.h index 836c287e509..dd2fe8d687a 100644 --- a/include/grpcpp/impl/codegen/channel_interface.h +++ b/include/grpcpp/impl/codegen/channel_interface.h @@ -27,24 +27,13 @@ namespace grpc_impl { class ClientContext; class CompletionQueue; -} // namespace grpc_impl - -namespace grpc { -class ChannelInterface; - template class ClientReader; template class ClientWriter; template class ClientReaderWriter; - namespace internal { -class Call; -class CallOpSetInterface; -class RpcMethod; -template -class BlockingUnaryCallImpl; template class CallbackUnaryCallImpl; template @@ -62,7 +51,19 @@ class ClientCallbackReaderFactory; template class ClientCallbackWriterFactory; class ClientCallbackUnaryFactory; +} // namespace internal +} // namespace grpc_impl + +namespace grpc { +class ChannelInterface; + +namespace internal { +class Call; +class CallOpSetInterface; +class RpcMethod; class InterceptedChannel; +template +class BlockingUnaryCallImpl; } // namespace internal /// Codegen interface for \a grpc::Channel. @@ -102,30 +103,30 @@ class ChannelInterface { private: template - friend class ::grpc::ClientReader; + friend class ::grpc_impl::ClientReader; template - friend class ::grpc::ClientWriter; + friend class ::grpc_impl::ClientWriter; template - friend class ::grpc::ClientReaderWriter; + friend class ::grpc_impl::ClientReaderWriter; template - friend class ::grpc::internal::ClientAsyncReaderFactory; + friend class ::grpc_impl::internal::ClientAsyncReaderFactory; template - friend class ::grpc::internal::ClientAsyncWriterFactory; + friend class ::grpc_impl::internal::ClientAsyncWriterFactory; template - friend class ::grpc::internal::ClientAsyncReaderWriterFactory; + friend class ::grpc_impl::internal::ClientAsyncReaderWriterFactory; template - friend class ::grpc::internal::ClientAsyncResponseReaderFactory; + friend class ::grpc_impl::internal::ClientAsyncResponseReaderFactory; template - friend class ::grpc::internal::ClientCallbackReaderWriterFactory; + friend class ::grpc_impl::internal::ClientCallbackReaderWriterFactory; template - friend class ::grpc::internal::ClientCallbackReaderFactory; + friend class ::grpc_impl::internal::ClientCallbackReaderFactory; template - friend class ::grpc::internal::ClientCallbackWriterFactory; - friend class ::grpc::internal::ClientCallbackUnaryFactory; + friend class ::grpc_impl::internal::ClientCallbackWriterFactory; + friend class ::grpc_impl::internal::ClientCallbackUnaryFactory; template friend class ::grpc::internal::BlockingUnaryCallImpl; template - friend class ::grpc::internal::CallbackUnaryCallImpl; + friend class ::grpc_impl::internal::CallbackUnaryCallImpl; friend class ::grpc::internal::RpcMethod; friend class ::grpc::internal::InterceptedChannel; virtual internal::Call CreateCall(const internal::RpcMethod& method, diff --git a/include/grpcpp/impl/codegen/client_callback.h b/include/grpcpp/impl/codegen/client_callback.h index 9441a48b051..4f60741624a 100644 --- a/include/grpcpp/impl/codegen/client_callback.h +++ b/include/grpcpp/impl/codegen/client_callback.h @@ -19,1012 +19,25 @@ #ifndef GRPCPP_IMPL_CODEGEN_CLIENT_CALLBACK_H #define GRPCPP_IMPL_CODEGEN_CLIENT_CALLBACK_H -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace grpc_impl { -class Channel; -class ClientContext; -} // namespace grpc_impl +#include namespace grpc { - -namespace internal { -class RpcMethod; - -/// Perform a callback-based unary call -/// TODO(vjpai): Combine as much as possible with the blocking unary call code -template -void CallbackUnaryCall(ChannelInterface* channel, const RpcMethod& method, - ::grpc_impl::ClientContext* context, - const InputMessage* request, OutputMessage* result, - std::function on_completion) { - CallbackUnaryCallImpl x( - channel, method, context, request, result, on_completion); -} - -template -class CallbackUnaryCallImpl { - public: - CallbackUnaryCallImpl(ChannelInterface* channel, const RpcMethod& method, - ::grpc_impl::ClientContext* context, - const InputMessage* request, OutputMessage* result, - std::function on_completion) { - CompletionQueue* cq = channel->CallbackCQ(); - GPR_CODEGEN_ASSERT(cq != nullptr); - Call call(channel->CreateCall(method, context, cq)); - - using FullCallOpSet = - CallOpSet, - CallOpClientSendClose, CallOpClientRecvStatus>; - - auto* ops = new (g_core_codegen_interface->grpc_call_arena_alloc( - call.call(), sizeof(FullCallOpSet))) FullCallOpSet; - - auto* tag = new (g_core_codegen_interface->grpc_call_arena_alloc( - call.call(), sizeof(CallbackWithStatusTag))) - CallbackWithStatusTag(call.call(), on_completion, ops); - - // TODO(vjpai): Unify code with sync API as much as possible - Status s = ops->SendMessagePtr(request); - if (!s.ok()) { - tag->force_run(s); - return; - } - ops->SendInitialMetadata(&context->send_initial_metadata_, - context->initial_metadata_flags()); - ops->RecvInitialMetadata(context); - ops->RecvMessage(result); - ops->AllowNoMessage(); - ops->ClientSendClose(); - ops->ClientRecvStatus(context, tag->status_ptr()); - ops->set_core_cq_tag(tag); - call.PerformOps(ops); - } -}; -} // namespace internal - namespace experimental { -// Forward declarations -template -class ClientBidiReactor; template -class ClientReadReactor; -template -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 -// will interact exclusively with the reactors that they define. -template -class ClientCallbackReaderWriter { - public: - virtual ~ClientCallbackReaderWriter() {} - virtual void StartCall() = 0; - virtual void Write(const Request* req, WriteOptions options) = 0; - virtual void WritesDone() = 0; - virtual void Read(Response* resp) = 0; - virtual void AddHold(int holds) = 0; - virtual void RemoveHold() = 0; - - protected: - void BindReactor(ClientBidiReactor* reactor) { - reactor->BindStream(this); - } -}; - -template -class ClientCallbackReader { - public: - virtual ~ClientCallbackReader() {} - virtual void StartCall() = 0; - virtual void Read(Response* resp) = 0; - virtual void AddHold(int holds) = 0; - virtual void RemoveHold() = 0; - - protected: - void BindReactor(ClientReadReactor* reactor) { - reactor->BindReader(this); - } -}; +using ClientReadReactor = + ::grpc_impl::experimental::ClientReadReactor; template -class ClientCallbackWriter { - public: - virtual ~ClientCallbackWriter() {} - virtual void StartCall() = 0; - void Write(const Request* req) { Write(req, WriteOptions()); } - virtual void Write(const Request* req, WriteOptions options) = 0; - void WriteLast(const Request* req, WriteOptions options) { - Write(req, options.set_last_message()); - } - virtual void WritesDone() = 0; +using ClientWriteReactor = + ::grpc_impl::experimental::ClientWriteReactor; - virtual void AddHold(int holds) = 0; - virtual void RemoveHold() = 0; - - protected: - void BindReactor(ClientWriteReactor* reactor) { - reactor->BindWriter(this); - } -}; - -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 -// activated by calling StartCall, possibly after initiating StartRead, -// StartWrite, or AddHold operations on the streaming object. Note that none of -// the classes are pure; all reactions have a default empty reaction so that the -// user class only needs to override those classes that it cares about. -// The reactor must be passed to the stub invocation before any of the below -// operations can be called. - -/// \a ClientBidiReactor is the interface for a bidirectional streaming RPC. template -class ClientBidiReactor { - public: - virtual ~ClientBidiReactor() {} - - /// Activate the RPC and initiate any reads or writes that have been Start'ed - /// before this call. All streaming RPCs issued by the client MUST have - /// StartCall invoked on them (even if they are canceled) as this call is the - /// activation of their lifecycle. - void StartCall() { stream_->StartCall(); } - - /// Initiate a read operation (or post it for later initiation if StartCall - /// has not yet been invoked). - /// - /// \param[out] resp Where to eventually store the read message. Valid when - /// the library calls OnReadDone - void StartRead(Response* resp) { stream_->Read(resp); } - - /// Initiate a write operation (or post it for later initiation if StartCall - /// has not yet been invoked). - /// - /// \param[in] req The message to be written. The library takes temporary - /// ownership until OnWriteDone, at which point the application - /// regains ownership of msg. - void StartWrite(const Request* req) { StartWrite(req, WriteOptions()); } - - /// Initiate/post a write operation with specified options. - /// - /// \param[in] req The message to be written. The library takes temporary - /// ownership until OnWriteDone, at which point the application - /// regains ownership of msg. - /// \param[in] options The WriteOptions to use for writing this message - void StartWrite(const Request* req, WriteOptions options) { - stream_->Write(req, std::move(options)); - } - - /// Initiate/post a write operation with specified options and an indication - /// that this is the last write (like StartWrite and StartWritesDone, merged). - /// Note that calling this means that no more calls to StartWrite, - /// StartWriteLast, or StartWritesDone are allowed. - /// - /// \param[in] req The message to be written. The library takes temporary - /// ownership until OnWriteDone, at which point the application - /// regains ownership of msg. - /// \param[in] options The WriteOptions to use for writing this message - void StartWriteLast(const Request* req, WriteOptions options) { - StartWrite(req, std::move(options.set_last_message())); - } - - /// Indicate that the RPC will have no more write operations. This can only be - /// issued once for a given RPC. This is not required or allowed if - /// StartWriteLast is used since that already has the same implication. - /// Note that calling this means that no more calls to StartWrite, - /// StartWriteLast, or StartWritesDone are allowed. - void StartWritesDone() { stream_->WritesDone(); } - - /// Holds are needed if (and only if) this stream has operations that take - /// place on it after StartCall but from outside one of the reactions - /// (OnReadDone, etc). This is _not_ a common use of the streaming API. - /// - /// Holds must be added before calling StartCall. If a stream still has a hold - /// in place, its resources will not be destroyed even if the status has - /// already come in from the wire and there are currently no active callbacks - /// outstanding. Similarly, the stream will not call OnDone if there are still - /// holds on it. - /// - /// For example, if a StartRead or StartWrite operation is going to be - /// initiated from elsewhere in the application, the application should call - /// AddHold or AddMultipleHolds before StartCall. If there is going to be, - /// for example, a read-flow and a write-flow taking place outside the - /// reactions, then call AddMultipleHolds(2) before StartCall. When the - /// application knows that it won't issue any more read operations (such as - /// when a read comes back as not ok), it should issue a RemoveHold(). It - /// should also call RemoveHold() again after it does StartWriteLast or - /// StartWritesDone that indicates that there will be no more write ops. - /// The number of RemoveHold calls must match the total number of AddHold - /// calls plus the number of holds added by AddMultipleHolds. - void AddHold() { AddMultipleHolds(1); } - void AddMultipleHolds(int holds) { stream_->AddHold(holds); } - void RemoveHold() { stream_->RemoveHold(); } - - /// Notifies the application that all operations associated with this RPC - /// have completed and provides the RPC status outcome. - /// - /// \param[in] s The status outcome of this RPC - virtual void OnDone(const Status& s) {} - - /// Notifies the application that a read of initial metadata from the - /// server is done. If the application chooses not to implement this method, - /// it can assume that the initial metadata has been read before the first - /// call of OnReadDone or OnDone. - /// - /// \param[in] ok Was the initial metadata read successfully? If false, no - /// further read-side operation will succeed. - virtual void OnReadInitialMetadataDone(bool ok) {} - - /// Notifies the application that a StartRead operation completed. - /// - /// \param[in] ok Was it successful? If false, no further read-side operation - /// will succeed. - virtual void OnReadDone(bool ok) {} - - /// Notifies the application that a StartWrite operation completed. - /// - /// \param[in] ok Was it successful? If false, no further write-side operation - /// will succeed. - virtual void OnWriteDone(bool ok) {} - - /// Notifies the application that a StartWritesDone operation completed. Note - /// that this is only used on explicit StartWritesDone operations and not for - /// those that are implicitly invoked as part of a StartWriteLast. - /// - /// \param[in] ok Was it successful? If false, the application will later see - /// the failure reflected as a bad status in OnDone. - virtual void OnWritesDoneDone(bool ok) {} - - private: - friend class ClientCallbackReaderWriter; - void BindStream(ClientCallbackReaderWriter* stream) { - stream_ = stream; - } - ClientCallbackReaderWriter* stream_; -}; - -/// \a ClientReadReactor is the interface for a server-streaming RPC. -/// All public methods behave as in ClientBidiReactor. -template -class ClientReadReactor { - public: - virtual ~ClientReadReactor() {} - - void StartCall() { reader_->StartCall(); } - void StartRead(Response* resp) { reader_->Read(resp); } - - void AddHold() { AddMultipleHolds(1); } - void AddMultipleHolds(int holds) { reader_->AddHold(holds); } - void RemoveHold() { reader_->RemoveHold(); } - - virtual void OnDone(const Status& s) {} - virtual void OnReadInitialMetadataDone(bool ok) {} - virtual void OnReadDone(bool ok) {} - - private: - friend class ClientCallbackReader; - void BindReader(ClientCallbackReader* reader) { reader_ = reader; } - ClientCallbackReader* reader_; -}; - -/// \a ClientWriteReactor is the interface for a client-streaming RPC. -/// All public methods behave as in ClientBidiReactor. -template -class ClientWriteReactor { - public: - virtual ~ClientWriteReactor() {} - - void StartCall() { writer_->StartCall(); } - void StartWrite(const Request* req) { StartWrite(req, WriteOptions()); } - void StartWrite(const Request* req, WriteOptions options) { - writer_->Write(req, std::move(options)); - } - void StartWriteLast(const Request* req, WriteOptions options) { - StartWrite(req, std::move(options.set_last_message())); - } - void StartWritesDone() { writer_->WritesDone(); } - - void AddHold() { AddMultipleHolds(1); } - void AddMultipleHolds(int holds) { writer_->AddHold(holds); } - void RemoveHold() { writer_->RemoveHold(); } - - virtual void OnDone(const Status& s) {} - virtual void OnReadInitialMetadataDone(bool ok) {} - virtual void OnWriteDone(bool ok) {} - virtual void OnWritesDoneDone(bool ok) {} - - private: - friend class ClientCallbackWriter; - void BindWriter(ClientCallbackWriter* writer) { writer_ = writer; } - ClientCallbackWriter* 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); -} +using ClientBidiReactor = + ::grpc_impl::experimental::ClientBidiReactor; +typedef ::grpc_impl::experimental::ClientUnaryReactor ClientUnaryReactor; } // namespace experimental - -namespace internal { - -// Forward declare factory classes for friendship -template -class ClientCallbackReaderWriterFactory; -template -class ClientCallbackReaderFactory; -template -class ClientCallbackWriterFactory; - -template -class ClientCallbackReaderWriterImpl - : public ::grpc::experimental::ClientCallbackReaderWriter { - public: - // always allocated against a call arena, no memory free required - static void operator delete(void* ptr, std::size_t size) { - assert(size == sizeof(ClientCallbackReaderWriterImpl)); - } - - // 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 MaybeFinish() { - if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( - 1, std::memory_order_acq_rel) == 1)) { - Status s = std::move(finish_status_); - auto* reactor = reactor_; - auto* call = call_.call(); - this->~ClientCallbackReaderWriterImpl(); - g_core_codegen_interface->grpc_call_unref(call); - reactor->OnDone(s); - } - } - - void StartCall() override { - // This call initiates two batches, plus any backlog, each with a callback - // 1. Send initial metadata (unless corked) + recv initial metadata - // 2. Any read backlog - // 3. Any write backlog - // 4. Recv trailing metadata, on_completion callback - started_ = true; - - start_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnReadInitialMetadataDone(ok); - MaybeFinish(); - }, - &start_ops_); - if (!start_corked_) { - 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_); - - // Also set up the read and write tags so that they don't have to be set up - // each time - write_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnWriteDone(ok); - MaybeFinish(); - }, - &write_ops_); - write_ops_.set_core_cq_tag(&write_tag_); - - read_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnReadDone(ok); - MaybeFinish(); - }, - &read_ops_); - read_ops_.set_core_cq_tag(&read_tag_); - if (read_ops_at_start_) { - call_.PerformOps(&read_ops_); - } - - if (write_ops_at_start_) { - call_.PerformOps(&write_ops_); - } - - if (writes_done_ops_at_start_) { - call_.PerformOps(&writes_done_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 Read(Response* msg) override { - read_ops_.RecvMessage(msg); - callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); - if (started_) { - call_.PerformOps(&read_ops_); - } else { - read_ops_at_start_ = true; - } - } - - void Write(const Request* msg, WriteOptions options) override { - if (start_corked_) { - write_ops_.SendInitialMetadata(&context_->send_initial_metadata_, - context_->initial_metadata_flags()); - start_corked_ = false; - } - - if (options.is_last_message()) { - options.set_buffer_hint(); - write_ops_.ClientSendClose(); - } - // TODO(vjpai): don't assert - GPR_CODEGEN_ASSERT(write_ops_.SendMessagePtr(msg, options).ok()); - callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); - if (started_) { - call_.PerformOps(&write_ops_); - } else { - write_ops_at_start_ = true; - } - } - void WritesDone() override { - if (start_corked_) { - writes_done_ops_.SendInitialMetadata(&context_->send_initial_metadata_, - context_->initial_metadata_flags()); - start_corked_ = false; - } - writes_done_ops_.ClientSendClose(); - writes_done_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnWritesDoneDone(ok); - MaybeFinish(); - }, - &writes_done_ops_); - writes_done_ops_.set_core_cq_tag(&writes_done_tag_); - callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); - if (started_) { - call_.PerformOps(&writes_done_ops_); - } else { - writes_done_ops_at_start_ = true; - } - } - - void AddHold(int holds) override { - callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed); - } - void RemoveHold() override { MaybeFinish(); } - - private: - friend class ClientCallbackReaderWriterFactory; - - ClientCallbackReaderWriterImpl( - Call call, ::grpc_impl::ClientContext* context, - ::grpc::experimental::ClientBidiReactor* reactor) - : context_(context), - call_(call), - reactor_(reactor), - start_corked_(context_->initial_metadata_corked_) { - this->BindReactor(reactor); - } - - ::grpc_impl::ClientContext* const context_; - Call call_; - ::grpc::experimental::ClientBidiReactor* const reactor_; - - CallOpSet start_ops_; - CallbackWithSuccessTag start_tag_; - bool start_corked_; - - CallOpSet finish_ops_; - CallbackWithSuccessTag finish_tag_; - Status finish_status_; - - CallOpSet - write_ops_; - CallbackWithSuccessTag write_tag_; - bool write_ops_at_start_{false}; - - CallOpSet writes_done_ops_; - CallbackWithSuccessTag writes_done_tag_; - bool writes_done_ops_at_start_{false}; - - CallOpSet> read_ops_; - CallbackWithSuccessTag read_tag_; - bool read_ops_at_start_{false}; - - // Minimum of 2 callbacks to pre-register for start and finish - std::atomic callbacks_outstanding_{2}; - bool started_{false}; -}; - -template -class ClientCallbackReaderWriterFactory { - public: - static void Create( - ChannelInterface* channel, const ::grpc::internal::RpcMethod& method, - ::grpc_impl::ClientContext* context, - ::grpc::experimental::ClientBidiReactor* 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(ClientCallbackReaderWriterImpl))) - ClientCallbackReaderWriterImpl(call, context, - reactor); - } -}; - -template -class ClientCallbackReaderImpl - : public ::grpc::experimental::ClientCallbackReader { - public: - // always allocated against a call arena, no memory free required - static void operator delete(void* ptr, std::size_t size) { - assert(size == sizeof(ClientCallbackReaderImpl)); - } - - // 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 MaybeFinish() { - if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( - 1, std::memory_order_acq_rel) == 1)) { - Status s = std::move(finish_status_); - auto* reactor = reactor_; - auto* call = call_.call(); - this->~ClientCallbackReaderImpl(); - g_core_codegen_interface->grpc_call_unref(call); - reactor->OnDone(s); - } - } - - void StartCall() override { - // This call initiates two batches, plus any backlog, each with a callback - // 1. Send initial metadata (unless corked) + recv initial metadata - // 2. Any backlog - // 3. Recv trailing metadata, on_completion callback - 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_); - - // Also set up the read tag so it doesn't have to be set up each time - read_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnReadDone(ok); - MaybeFinish(); - }, - &read_ops_); - read_ops_.set_core_cq_tag(&read_tag_); - if (read_ops_at_start_) { - call_.PerformOps(&read_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 Read(Response* msg) override { - read_ops_.RecvMessage(msg); - callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); - if (started_) { - call_.PerformOps(&read_ops_); - } else { - read_ops_at_start_ = true; - } - } - - void AddHold(int holds) override { - callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed); - } - void RemoveHold() override { MaybeFinish(); } - - private: - friend class ClientCallbackReaderFactory; - - template - ClientCallbackReaderImpl( - Call call, ::grpc_impl::ClientContext* context, Request* request, - ::grpc::experimental::ClientReadReactor* 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(); - } - - ::grpc_impl::ClientContext* const context_; - Call call_; - ::grpc::experimental::ClientReadReactor* const reactor_; - - CallOpSet - start_ops_; - CallbackWithSuccessTag start_tag_; - - CallOpSet finish_ops_; - CallbackWithSuccessTag finish_tag_; - Status finish_status_; - - CallOpSet> read_ops_; - CallbackWithSuccessTag read_tag_; - bool read_ops_at_start_{false}; - - // Minimum of 2 callbacks to pre-register for start and finish - std::atomic callbacks_outstanding_{2}; - bool started_{false}; -}; - -template -class ClientCallbackReaderFactory { - public: - template - static void Create( - ChannelInterface* channel, const ::grpc::internal::RpcMethod& method, - ::grpc_impl::ClientContext* context, const Request* request, - ::grpc::experimental::ClientReadReactor* 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(ClientCallbackReaderImpl))) - ClientCallbackReaderImpl(call, context, request, reactor); - } -}; - -template -class ClientCallbackWriterImpl - : public ::grpc::experimental::ClientCallbackWriter { - public: - // always allocated against a call arena, no memory free required - static void operator delete(void* ptr, std::size_t size) { - assert(size == sizeof(ClientCallbackWriterImpl)); - } - - // 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 MaybeFinish() { - if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( - 1, std::memory_order_acq_rel) == 1)) { - Status s = std::move(finish_status_); - auto* reactor = reactor_; - auto* call = call_.call(); - this->~ClientCallbackWriterImpl(); - g_core_codegen_interface->grpc_call_unref(call); - reactor->OnDone(s); - } - } - - void StartCall() override { - // This call initiates two batches, plus any backlog, each with a callback - // 1. Send initial metadata (unless corked) + recv initial metadata - // 2. Any backlog - // 3. Recv trailing metadata, on_completion callback - started_ = true; - - start_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnReadInitialMetadataDone(ok); - MaybeFinish(); - }, - &start_ops_); - if (!start_corked_) { - 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_); - - // Also set up the read and write tags so that they don't have to be set up - // each time - write_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnWriteDone(ok); - MaybeFinish(); - }, - &write_ops_); - write_ops_.set_core_cq_tag(&write_tag_); - - if (write_ops_at_start_) { - call_.PerformOps(&write_ops_); - } - - if (writes_done_ops_at_start_) { - call_.PerformOps(&writes_done_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 Write(const Request* msg, WriteOptions options) override { - if (start_corked_) { - write_ops_.SendInitialMetadata(&context_->send_initial_metadata_, - context_->initial_metadata_flags()); - start_corked_ = false; - } - - if (options.is_last_message()) { - options.set_buffer_hint(); - write_ops_.ClientSendClose(); - } - // TODO(vjpai): don't assert - GPR_CODEGEN_ASSERT(write_ops_.SendMessagePtr(msg, options).ok()); - callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); - if (started_) { - call_.PerformOps(&write_ops_); - } else { - write_ops_at_start_ = true; - } - } - void WritesDone() override { - if (start_corked_) { - writes_done_ops_.SendInitialMetadata(&context_->send_initial_metadata_, - context_->initial_metadata_flags()); - start_corked_ = false; - } - writes_done_ops_.ClientSendClose(); - writes_done_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnWritesDoneDone(ok); - MaybeFinish(); - }, - &writes_done_ops_); - writes_done_ops_.set_core_cq_tag(&writes_done_tag_); - callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); - if (started_) { - call_.PerformOps(&writes_done_ops_); - } else { - writes_done_ops_at_start_ = true; - } - } - - void AddHold(int holds) override { - callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed); - } - void RemoveHold() override { MaybeFinish(); } - - private: - friend class ClientCallbackWriterFactory; - - template - ClientCallbackWriterImpl( - Call call, ::grpc_impl::ClientContext* context, Response* response, - ::grpc::experimental::ClientWriteReactor* reactor) - : context_(context), - call_(call), - reactor_(reactor), - start_corked_(context_->initial_metadata_corked_) { - this->BindReactor(reactor); - finish_ops_.RecvMessage(response); - finish_ops_.AllowNoMessage(); - } - - ::grpc_impl::ClientContext* const context_; - Call call_; - ::grpc::experimental::ClientWriteReactor* const reactor_; - - CallOpSet start_ops_; - CallbackWithSuccessTag start_tag_; - bool start_corked_; - - CallOpSet finish_ops_; - CallbackWithSuccessTag finish_tag_; - Status finish_status_; - - CallOpSet - write_ops_; - CallbackWithSuccessTag write_tag_; - bool write_ops_at_start_{false}; - - CallOpSet writes_done_ops_; - CallbackWithSuccessTag writes_done_tag_; - bool writes_done_ops_at_start_{false}; - - // Minimum of 2 callbacks to pre-register for start and finish - std::atomic callbacks_outstanding_{2}; - bool started_{false}; -}; - -template -class ClientCallbackWriterFactory { - public: - template - static void Create( - ChannelInterface* channel, const ::grpc::internal::RpcMethod& method, - ::grpc_impl::ClientContext* context, Response* response, - ::grpc::experimental::ClientWriteReactor* 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(ClientCallbackWriterImpl))) - ClientCallbackWriterImpl(call, context, response, reactor); - } -}; - -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 (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( - 1, std::memory_order_acq_rel) == 1)) { - 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 - ClientCallbackUnaryImpl(Call call, ::grpc_impl::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(); - } - - ::grpc_impl::ClientContext* const context_; - Call call_; - ::grpc::experimental::ClientUnaryReactor* const reactor_; - - CallOpSet - start_ops_; - CallbackWithSuccessTag start_tag_; - - CallOpSet finish_ops_; - CallbackWithSuccessTag finish_tag_; - Status finish_status_; - - // This call will have 2 callbacks: start and finish - std::atomic callbacks_outstanding_{2}; - bool started_{false}; -}; - -class ClientCallbackUnaryFactory { - public: - template - static void Create(ChannelInterface* channel, - const ::grpc::internal::RpcMethod& method, - ::grpc_impl::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 #endif // GRPCPP_IMPL_CODEGEN_CLIENT_CALLBACK_H diff --git a/include/grpcpp/impl/codegen/client_callback_impl.h b/include/grpcpp/impl/codegen/client_callback_impl.h new file mode 100644 index 00000000000..81847bc9e04 --- /dev/null +++ b/include/grpcpp/impl/codegen/client_callback_impl.h @@ -0,0 +1,1067 @@ +/* + * + * 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_CLIENT_CALLBACK_IMPL_H +#define GRPCPP_IMPL_CODEGEN_CLIENT_CALLBACK_IMPL_H +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace grpc { +namespace internal { +class RpcMethod; +} // namespace internal +} // namespace grpc + +namespace grpc_impl { +class Channel; +class ClientContext; + +namespace internal { + +/// Perform a callback-based unary call +/// TODO(vjpai): Combine as much as possible with the blocking unary call code +template +void CallbackUnaryCall(::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context, + const InputMessage* request, OutputMessage* result, + std::function on_completion) { + CallbackUnaryCallImpl x( + channel, method, context, request, result, on_completion); +} + +template +class CallbackUnaryCallImpl { + public: + CallbackUnaryCallImpl(::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context, + const InputMessage* request, OutputMessage* result, + std::function on_completion) { + ::grpc_impl::CompletionQueue* cq = channel->CallbackCQ(); + GPR_CODEGEN_ASSERT(cq != nullptr); + grpc::internal::Call call(channel->CreateCall(method, context, cq)); + + using FullCallOpSet = grpc::internal::CallOpSet< + ::grpc::internal::CallOpSendInitialMetadata, + grpc::internal::CallOpSendMessage, + grpc::internal::CallOpRecvInitialMetadata, + grpc::internal::CallOpRecvMessage, + grpc::internal::CallOpClientSendClose, + grpc::internal::CallOpClientRecvStatus>; + + auto* ops = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(FullCallOpSet))) FullCallOpSet; + + auto* tag = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(grpc::internal::CallbackWithStatusTag))) + grpc::internal::CallbackWithStatusTag(call.call(), on_completion, ops); + + // TODO(vjpai): Unify code with sync API as much as possible + ::grpc::Status s = ops->SendMessagePtr(request); + if (!s.ok()) { + tag->force_run(s); + return; + } + ops->SendInitialMetadata(&context->send_initial_metadata_, + context->initial_metadata_flags()); + ops->RecvInitialMetadata(context); + ops->RecvMessage(result); + ops->AllowNoMessage(); + ops->ClientSendClose(); + ops->ClientRecvStatus(context, tag->status_ptr()); + ops->set_core_cq_tag(tag); + call.PerformOps(ops); + } +}; +} // namespace internal + +namespace experimental { + +// Forward declarations +template +class ClientBidiReactor; +template +class ClientReadReactor; +template +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 +// will interact exclusively with the reactors that they define. +template +class ClientCallbackReaderWriter { + public: + virtual ~ClientCallbackReaderWriter() {} + virtual void StartCall() = 0; + virtual void Write(const Request* req, ::grpc::WriteOptions options) = 0; + virtual void WritesDone() = 0; + virtual void Read(Response* resp) = 0; + virtual void AddHold(int holds) = 0; + virtual void RemoveHold() = 0; + + protected: + void BindReactor(ClientBidiReactor* reactor) { + reactor->BindStream(this); + } +}; + +template +class ClientCallbackReader { + public: + virtual ~ClientCallbackReader() {} + virtual void StartCall() = 0; + virtual void Read(Response* resp) = 0; + virtual void AddHold(int holds) = 0; + virtual void RemoveHold() = 0; + + protected: + void BindReactor(ClientReadReactor* reactor) { + reactor->BindReader(this); + } +}; + +template +class ClientCallbackWriter { + public: + virtual ~ClientCallbackWriter() {} + virtual void StartCall() = 0; + void Write(const Request* req) { Write(req, ::grpc::WriteOptions()); } + virtual void Write(const Request* req, ::grpc::WriteOptions options) = 0; + void WriteLast(const Request* req, ::grpc::WriteOptions options) { + Write(req, options.set_last_message()); + } + virtual void WritesDone() = 0; + + virtual void AddHold(int holds) = 0; + virtual void RemoveHold() = 0; + + protected: + void BindReactor(ClientWriteReactor* reactor) { + reactor->BindWriter(this); + } +}; + +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 +// activated by calling StartCall, possibly after initiating StartRead, +// StartWrite, or AddHold operations on the streaming object. Note that none of +// the classes are pure; all reactions have a default empty reaction so that the +// user class only needs to override those classes that it cares about. +// The reactor must be passed to the stub invocation before any of the below +// operations can be called. + +/// \a ClientBidiReactor is the interface for a bidirectional streaming RPC. +template +class ClientBidiReactor { + public: + virtual ~ClientBidiReactor() {} + + /// Activate the RPC and initiate any reads or writes that have been Start'ed + /// before this call. All streaming RPCs issued by the client MUST have + /// StartCall invoked on them (even if they are canceled) as this call is the + /// activation of their lifecycle. + void StartCall() { stream_->StartCall(); } + + /// Initiate a read operation (or post it for later initiation if StartCall + /// has not yet been invoked). + /// + /// \param[out] resp Where to eventually store the read message. Valid when + /// the library calls OnReadDone + void StartRead(Response* resp) { stream_->Read(resp); } + + /// Initiate a write operation (or post it for later initiation if StartCall + /// has not yet been invoked). + /// + /// \param[in] req The message to be written. The library takes temporary + /// ownership until OnWriteDone, at which point the application + /// regains ownership of msg. + void StartWrite(const Request* req) { + StartWrite(req, ::grpc::WriteOptions()); + } + + /// Initiate/post a write operation with specified options. + /// + /// \param[in] req The message to be written. The library takes temporary + /// ownership until OnWriteDone, at which point the application + /// regains ownership of msg. + /// \param[in] options The WriteOptions to use for writing this message + void StartWrite(const Request* req, ::grpc::WriteOptions options) { + stream_->Write(req, std::move(options)); + } + + /// Initiate/post a write operation with specified options and an indication + /// that this is the last write (like StartWrite and StartWritesDone, merged). + /// Note that calling this means that no more calls to StartWrite, + /// StartWriteLast, or StartWritesDone are allowed. + /// + /// \param[in] req The message to be written. The library takes temporary + /// ownership until OnWriteDone, at which point the application + /// regains ownership of msg. + /// \param[in] options The WriteOptions to use for writing this message + void StartWriteLast(const Request* req, ::grpc::WriteOptions options) { + StartWrite(req, std::move(options.set_last_message())); + } + + /// Indicate that the RPC will have no more write operations. This can only be + /// issued once for a given RPC. This is not required or allowed if + /// StartWriteLast is used since that already has the same implication. + /// Note that calling this means that no more calls to StartWrite, + /// StartWriteLast, or StartWritesDone are allowed. + void StartWritesDone() { stream_->WritesDone(); } + + /// Holds are needed if (and only if) this stream has operations that take + /// place on it after StartCall but from outside one of the reactions + /// (OnReadDone, etc). This is _not_ a common use of the streaming API. + /// + /// Holds must be added before calling StartCall. If a stream still has a hold + /// in place, its resources will not be destroyed even if the status has + /// already come in from the wire and there are currently no active callbacks + /// outstanding. Similarly, the stream will not call OnDone if there are still + /// holds on it. + /// + /// For example, if a StartRead or StartWrite operation is going to be + /// initiated from elsewhere in the application, the application should call + /// AddHold or AddMultipleHolds before StartCall. If there is going to be, + /// for example, a read-flow and a write-flow taking place outside the + /// reactions, then call AddMultipleHolds(2) before StartCall. When the + /// application knows that it won't issue any more read operations (such as + /// when a read comes back as not ok), it should issue a RemoveHold(). It + /// should also call RemoveHold() again after it does StartWriteLast or + /// StartWritesDone that indicates that there will be no more write ops. + /// The number of RemoveHold calls must match the total number of AddHold + /// calls plus the number of holds added by AddMultipleHolds. + void AddHold() { AddMultipleHolds(1); } + void AddMultipleHolds(int holds) { stream_->AddHold(holds); } + void RemoveHold() { stream_->RemoveHold(); } + + /// Notifies the application that all operations associated with this RPC + /// have completed and provides the RPC status outcome. + /// + /// \param[in] s The status outcome of this RPC + virtual void OnDone(const ::grpc::Status& s) {} + + /// Notifies the application that a read of initial metadata from the + /// server is done. If the application chooses not to implement this method, + /// it can assume that the initial metadata has been read before the first + /// call of OnReadDone or OnDone. + /// + /// \param[in] ok Was the initial metadata read successfully? If false, no + /// further read-side operation will succeed. + virtual void OnReadInitialMetadataDone(bool ok) {} + + /// Notifies the application that a StartRead operation completed. + /// + /// \param[in] ok Was it successful? If false, no further read-side operation + /// will succeed. + virtual void OnReadDone(bool ok) {} + + /// Notifies the application that a StartWrite operation completed. + /// + /// \param[in] ok Was it successful? If false, no further write-side operation + /// will succeed. + virtual void OnWriteDone(bool ok) {} + + /// Notifies the application that a StartWritesDone operation completed. Note + /// that this is only used on explicit StartWritesDone operations and not for + /// those that are implicitly invoked as part of a StartWriteLast. + /// + /// \param[in] ok Was it successful? If false, the application will later see + /// the failure reflected as a bad status in OnDone. + virtual void OnWritesDoneDone(bool ok) {} + + private: + friend class ClientCallbackReaderWriter; + void BindStream(ClientCallbackReaderWriter* stream) { + stream_ = stream; + } + ClientCallbackReaderWriter* stream_; +}; + +/// \a ClientReadReactor is the interface for a server-streaming RPC. +/// All public methods behave as in ClientBidiReactor. +template +class ClientReadReactor { + public: + virtual ~ClientReadReactor() {} + + void StartCall() { reader_->StartCall(); } + void StartRead(Response* resp) { reader_->Read(resp); } + + void AddHold() { AddMultipleHolds(1); } + void AddMultipleHolds(int holds) { reader_->AddHold(holds); } + void RemoveHold() { reader_->RemoveHold(); } + + virtual void OnDone(const ::grpc::Status& s) {} + virtual void OnReadInitialMetadataDone(bool ok) {} + virtual void OnReadDone(bool ok) {} + + private: + friend class ClientCallbackReader; + void BindReader(ClientCallbackReader* reader) { reader_ = reader; } + ClientCallbackReader* reader_; +}; + +/// \a ClientWriteReactor is the interface for a client-streaming RPC. +/// All public methods behave as in ClientBidiReactor. +template +class ClientWriteReactor { + public: + virtual ~ClientWriteReactor() {} + + void StartCall() { writer_->StartCall(); } + void StartWrite(const Request* req) { + StartWrite(req, ::grpc::WriteOptions()); + } + void StartWrite(const Request* req, ::grpc::WriteOptions options) { + writer_->Write(req, std::move(options)); + } + void StartWriteLast(const Request* req, ::grpc::WriteOptions options) { + StartWrite(req, std::move(options.set_last_message())); + } + void StartWritesDone() { writer_->WritesDone(); } + + void AddHold() { AddMultipleHolds(1); } + void AddMultipleHolds(int holds) { writer_->AddHold(holds); } + void RemoveHold() { writer_->RemoveHold(); } + + virtual void OnDone(const ::grpc::Status& s) {} + virtual void OnReadInitialMetadataDone(bool ok) {} + virtual void OnWriteDone(bool ok) {} + virtual void OnWritesDoneDone(bool ok) {} + + private: + friend class ClientCallbackWriter; + void BindWriter(ClientCallbackWriter* writer) { writer_ = writer; } + ClientCallbackWriter* 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 ::grpc::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 { + +// Forward declare factory classes for friendship +template +class ClientCallbackReaderWriterFactory; +template +class ClientCallbackReaderFactory; +template +class ClientCallbackWriterFactory; + +template +class ClientCallbackReaderWriterImpl + : public experimental::ClientCallbackReaderWriter { + public: + // always allocated against a call arena, no memory free required + static void operator delete(void* ptr, std::size_t size) { + assert(size == sizeof(ClientCallbackReaderWriterImpl)); + } + + // 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 MaybeFinish() { + if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( + 1, std::memory_order_acq_rel) == 1)) { + ::grpc::Status s = std::move(finish_status_); + auto* reactor = reactor_; + auto* call = call_.call(); + this->~ClientCallbackReaderWriterImpl(); + ::grpc::g_core_codegen_interface->grpc_call_unref(call); + reactor->OnDone(s); + } + } + + void StartCall() override { + // This call initiates two batches, plus any backlog, each with a callback + // 1. Send initial metadata (unless corked) + recv initial metadata + // 2. Any read backlog + // 3. Any write backlog + // 4. Recv trailing metadata, on_completion callback + started_ = true; + + start_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnReadInitialMetadataDone(ok); + MaybeFinish(); + }, + &start_ops_); + if (!start_corked_) { + 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_); + + // Also set up the read and write tags so that they don't have to be set up + // each time + write_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnWriteDone(ok); + MaybeFinish(); + }, + &write_ops_); + write_ops_.set_core_cq_tag(&write_tag_); + + read_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnReadDone(ok); + MaybeFinish(); + }, + &read_ops_); + read_ops_.set_core_cq_tag(&read_tag_); + if (read_ops_at_start_) { + call_.PerformOps(&read_ops_); + } + + if (write_ops_at_start_) { + call_.PerformOps(&write_ops_); + } + + if (writes_done_ops_at_start_) { + call_.PerformOps(&writes_done_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 Read(Response* msg) override { + read_ops_.RecvMessage(msg); + callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); + if (started_) { + call_.PerformOps(&read_ops_); + } else { + read_ops_at_start_ = true; + } + } + + void Write(const Request* msg, ::grpc::WriteOptions options) override { + if (start_corked_) { + write_ops_.SendInitialMetadata(&context_->send_initial_metadata_, + context_->initial_metadata_flags()); + start_corked_ = false; + } + + if (options.is_last_message()) { + options.set_buffer_hint(); + write_ops_.ClientSendClose(); + } + // TODO(vjpai): don't assert + GPR_CODEGEN_ASSERT(write_ops_.SendMessagePtr(msg, options).ok()); + callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); + if (started_) { + call_.PerformOps(&write_ops_); + } else { + write_ops_at_start_ = true; + } + } + void WritesDone() override { + if (start_corked_) { + writes_done_ops_.SendInitialMetadata(&context_->send_initial_metadata_, + context_->initial_metadata_flags()); + start_corked_ = false; + } + writes_done_ops_.ClientSendClose(); + writes_done_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnWritesDoneDone(ok); + MaybeFinish(); + }, + &writes_done_ops_); + writes_done_ops_.set_core_cq_tag(&writes_done_tag_); + callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); + if (started_) { + call_.PerformOps(&writes_done_ops_); + } else { + writes_done_ops_at_start_ = true; + } + } + + void AddHold(int holds) override { + callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed); + } + void RemoveHold() override { MaybeFinish(); } + + private: + friend class ClientCallbackReaderWriterFactory; + + ClientCallbackReaderWriterImpl( + grpc::internal::Call call, ::grpc_impl::ClientContext* context, + experimental::ClientBidiReactor* reactor) + : context_(context), + call_(call), + reactor_(reactor), + start_corked_(context_->initial_metadata_corked_) { + this->BindReactor(reactor); + } + + ::grpc_impl::ClientContext* const context_; + grpc::internal::Call call_; + experimental::ClientBidiReactor* const reactor_; + + grpc::internal::CallOpSet + start_ops_; + grpc::internal::CallbackWithSuccessTag start_tag_; + bool start_corked_; + + grpc::internal::CallOpSet finish_ops_; + grpc::internal::CallbackWithSuccessTag finish_tag_; + ::grpc::Status finish_status_; + + grpc::internal::CallOpSet + write_ops_; + grpc::internal::CallbackWithSuccessTag write_tag_; + bool write_ops_at_start_{false}; + + grpc::internal::CallOpSet + writes_done_ops_; + grpc::internal::CallbackWithSuccessTag writes_done_tag_; + bool writes_done_ops_at_start_{false}; + + grpc::internal::CallOpSet> + read_ops_; + grpc::internal::CallbackWithSuccessTag read_tag_; + bool read_ops_at_start_{false}; + + // Minimum of 2 callbacks to pre-register for start and finish + std::atomic callbacks_outstanding_{2}; + bool started_{false}; +}; + +template +class ClientCallbackReaderWriterFactory { + public: + static void Create( + ::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context, + experimental::ClientBidiReactor* reactor) { + grpc::internal::Call call = + channel->CreateCall(method, context, channel->CallbackCQ()); + + ::grpc::g_core_codegen_interface->grpc_call_ref(call.call()); + new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(ClientCallbackReaderWriterImpl))) + ClientCallbackReaderWriterImpl(call, context, + reactor); + } +}; + +template +class ClientCallbackReaderImpl + : public experimental::ClientCallbackReader { + public: + // always allocated against a call arena, no memory free required + static void operator delete(void* ptr, std::size_t size) { + assert(size == sizeof(ClientCallbackReaderImpl)); + } + + // 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 MaybeFinish() { + if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( + 1, std::memory_order_acq_rel) == 1)) { + ::grpc::Status s = std::move(finish_status_); + auto* reactor = reactor_; + auto* call = call_.call(); + this->~ClientCallbackReaderImpl(); + ::grpc::g_core_codegen_interface->grpc_call_unref(call); + reactor->OnDone(s); + } + } + + void StartCall() override { + // This call initiates two batches, plus any backlog, each with a callback + // 1. Send initial metadata (unless corked) + recv initial metadata + // 2. Any backlog + // 3. Recv trailing metadata, on_completion callback + 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_); + + // Also set up the read tag so it doesn't have to be set up each time + read_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnReadDone(ok); + MaybeFinish(); + }, + &read_ops_); + read_ops_.set_core_cq_tag(&read_tag_); + if (read_ops_at_start_) { + call_.PerformOps(&read_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 Read(Response* msg) override { + read_ops_.RecvMessage(msg); + callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); + if (started_) { + call_.PerformOps(&read_ops_); + } else { + read_ops_at_start_ = true; + } + } + + void AddHold(int holds) override { + callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed); + } + void RemoveHold() override { MaybeFinish(); } + + private: + friend class ClientCallbackReaderFactory; + + template + ClientCallbackReaderImpl(::grpc::internal::Call call, + ::grpc_impl::ClientContext* context, + Request* request, + experimental::ClientReadReactor* 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(); + } + + ::grpc_impl::ClientContext* const context_; + grpc::internal::Call call_; + experimental::ClientReadReactor* const reactor_; + + grpc::internal::CallOpSet + start_ops_; + grpc::internal::CallbackWithSuccessTag start_tag_; + + grpc::internal::CallOpSet finish_ops_; + grpc::internal::CallbackWithSuccessTag finish_tag_; + ::grpc::Status finish_status_; + + grpc::internal::CallOpSet> + read_ops_; + grpc::internal::CallbackWithSuccessTag read_tag_; + bool read_ops_at_start_{false}; + + // Minimum of 2 callbacks to pre-register for start and finish + std::atomic callbacks_outstanding_{2}; + bool started_{false}; +}; + +template +class ClientCallbackReaderFactory { + public: + template + static void Create(::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context, + const Request* request, + experimental::ClientReadReactor* reactor) { + grpc::internal::Call call = + channel->CreateCall(method, context, channel->CallbackCQ()); + + ::grpc::g_core_codegen_interface->grpc_call_ref(call.call()); + new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(ClientCallbackReaderImpl))) + ClientCallbackReaderImpl(call, context, request, reactor); + } +}; + +template +class ClientCallbackWriterImpl + : public experimental::ClientCallbackWriter { + public: + // always allocated against a call arena, no memory free required + static void operator delete(void* ptr, std::size_t size) { + assert(size == sizeof(ClientCallbackWriterImpl)); + } + + // 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 MaybeFinish() { + if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( + 1, std::memory_order_acq_rel) == 1)) { + ::grpc::Status s = std::move(finish_status_); + auto* reactor = reactor_; + auto* call = call_.call(); + this->~ClientCallbackWriterImpl(); + ::grpc::g_core_codegen_interface->grpc_call_unref(call); + reactor->OnDone(s); + } + } + + void StartCall() override { + // This call initiates two batches, plus any backlog, each with a callback + // 1. Send initial metadata (unless corked) + recv initial metadata + // 2. Any backlog + // 3. Recv trailing metadata, on_completion callback + started_ = true; + + start_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnReadInitialMetadataDone(ok); + MaybeFinish(); + }, + &start_ops_); + if (!start_corked_) { + 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_); + + // Also set up the read and write tags so that they don't have to be set up + // each time + write_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnWriteDone(ok); + MaybeFinish(); + }, + &write_ops_); + write_ops_.set_core_cq_tag(&write_tag_); + + if (write_ops_at_start_) { + call_.PerformOps(&write_ops_); + } + + if (writes_done_ops_at_start_) { + call_.PerformOps(&writes_done_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 Write(const Request* msg, ::grpc::WriteOptions options) override { + if (start_corked_) { + write_ops_.SendInitialMetadata(&context_->send_initial_metadata_, + context_->initial_metadata_flags()); + start_corked_ = false; + } + + if (options.is_last_message()) { + options.set_buffer_hint(); + write_ops_.ClientSendClose(); + } + // TODO(vjpai): don't assert + GPR_CODEGEN_ASSERT(write_ops_.SendMessagePtr(msg, options).ok()); + callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); + if (started_) { + call_.PerformOps(&write_ops_); + } else { + write_ops_at_start_ = true; + } + } + void WritesDone() override { + if (start_corked_) { + writes_done_ops_.SendInitialMetadata(&context_->send_initial_metadata_, + context_->initial_metadata_flags()); + start_corked_ = false; + } + writes_done_ops_.ClientSendClose(); + writes_done_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnWritesDoneDone(ok); + MaybeFinish(); + }, + &writes_done_ops_); + writes_done_ops_.set_core_cq_tag(&writes_done_tag_); + callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); + if (started_) { + call_.PerformOps(&writes_done_ops_); + } else { + writes_done_ops_at_start_ = true; + } + } + + void AddHold(int holds) override { + callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed); + } + void RemoveHold() override { MaybeFinish(); } + + private: + friend class ClientCallbackWriterFactory; + + template + ClientCallbackWriterImpl(::grpc::internal::Call call, + ::grpc_impl::ClientContext* context, + Response* response, + experimental::ClientWriteReactor* reactor) + : context_(context), + call_(call), + reactor_(reactor), + start_corked_(context_->initial_metadata_corked_) { + this->BindReactor(reactor); + finish_ops_.RecvMessage(response); + finish_ops_.AllowNoMessage(); + } + + ::grpc_impl::ClientContext* const context_; + grpc::internal::Call call_; + experimental::ClientWriteReactor* const reactor_; + + grpc::internal::CallOpSet + start_ops_; + grpc::internal::CallbackWithSuccessTag start_tag_; + bool start_corked_; + + grpc::internal::CallOpSet + finish_ops_; + grpc::internal::CallbackWithSuccessTag finish_tag_; + ::grpc::Status finish_status_; + + grpc::internal::CallOpSet + write_ops_; + grpc::internal::CallbackWithSuccessTag write_tag_; + bool write_ops_at_start_{false}; + + grpc::internal::CallOpSet + writes_done_ops_; + grpc::internal::CallbackWithSuccessTag writes_done_tag_; + bool writes_done_ops_at_start_{false}; + + // Minimum of 2 callbacks to pre-register for start and finish + std::atomic callbacks_outstanding_{2}; + bool started_{false}; +}; + +template +class ClientCallbackWriterFactory { + public: + template + static void Create(::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context, Response* response, + experimental::ClientWriteReactor* reactor) { + grpc::internal::Call call = + channel->CreateCall(method, context, channel->CallbackCQ()); + + ::grpc::g_core_codegen_interface->grpc_call_ref(call.call()); + new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(ClientCallbackWriterImpl))) + ClientCallbackWriterImpl(call, context, response, reactor); + } +}; + +class ClientCallbackUnaryImpl final : public 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 (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( + 1, std::memory_order_acq_rel) == 1)) { + ::grpc::Status s = std::move(finish_status_); + auto* reactor = reactor_; + auto* call = call_.call(); + this->~ClientCallbackUnaryImpl(); + ::grpc::g_core_codegen_interface->grpc_call_unref(call); + reactor->OnDone(s); + } + } + + private: + friend class ClientCallbackUnaryFactory; + + template + ClientCallbackUnaryImpl(::grpc::internal::Call call, + ::grpc_impl::ClientContext* context, Request* request, + Response* response, + 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(); + } + + ::grpc_impl::ClientContext* const context_; + grpc::internal::Call call_; + experimental::ClientUnaryReactor* const reactor_; + + grpc::internal::CallOpSet + start_ops_; + grpc::internal::CallbackWithSuccessTag start_tag_; + + grpc::internal::CallOpSet + finish_ops_; + grpc::internal::CallbackWithSuccessTag finish_tag_; + ::grpc::Status finish_status_; + + // This call will have 2 callbacks: start and finish + std::atomic callbacks_outstanding_{2}; + bool started_{false}; +}; + +class ClientCallbackUnaryFactory { + public: + template + static void Create(::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context, + const Request* request, Response* response, + experimental::ClientUnaryReactor* reactor) { + grpc::internal::Call call = + channel->CreateCall(method, context, channel->CallbackCQ()); + + ::grpc::g_core_codegen_interface->grpc_call_ref(call.call()); + + new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(ClientCallbackUnaryImpl))) + ClientCallbackUnaryImpl(call, context, request, response, reactor); + } +}; + +} // namespace internal +} // namespace grpc_impl +#endif // GRPCPP_IMPL_CODEGEN_CLIENT_CALLBACK_IMPL_H diff --git a/include/grpcpp/impl/codegen/client_context_impl.h b/include/grpcpp/impl/codegen/client_context_impl.h index 8491215cf0e..638ea641bed 100644 --- a/include/grpcpp/impl/codegen/client_context_impl.h +++ b/include/grpcpp/impl/codegen/client_context_impl.h @@ -63,10 +63,19 @@ class ChannelInterface; namespace internal { class RpcMethod; -class CallOpClientRecvStatus; -class CallOpRecvInitialMetadata; template class BlockingUnaryCallImpl; +class CallOpClientRecvStatus; +class CallOpRecvInitialMetadata; +} // namespace internal + +namespace testing { +class InteropClientContextInspector; +} // namespace testing +} // namespace grpc +namespace grpc_impl { + +namespace internal { template class CallbackUnaryCallImpl; template @@ -78,6 +87,10 @@ class ClientCallbackWriterImpl; class ClientCallbackUnaryImpl; } // namespace internal +class CallCredentials; +class Channel; +class CompletionQueue; +class ServerContext; template class ClientReader; template @@ -93,17 +106,6 @@ class ClientAsyncReaderWriter; template class ClientAsyncResponseReader; -namespace testing { -class InteropClientContextInspector; -} // namespace testing -} // namespace grpc -namespace grpc_impl { - -class CallCredentials; -class Channel; -class CompletionQueue; -class ServerContext; - /// Options for \a ClientContext::FromServerContext specifying which traits from /// the \a ServerContext to propagate (copy) from it into a new \a /// ClientContext. @@ -398,30 +400,30 @@ class ClientContext { friend class ::grpc::internal::CallOpRecvInitialMetadata; friend class ::grpc_impl::Channel; template - friend class ::grpc::ClientReader; + friend class ::grpc_impl::ClientReader; template - friend class ::grpc::ClientWriter; + friend class ::grpc_impl::ClientWriter; template - friend class ::grpc::ClientReaderWriter; + friend class ::grpc_impl::ClientReaderWriter; template - friend class ::grpc::ClientAsyncReader; + friend class ::grpc_impl::ClientAsyncReader; template - friend class ::grpc::ClientAsyncWriter; + friend class ::grpc_impl::ClientAsyncWriter; template - friend class ::grpc::ClientAsyncReaderWriter; + friend class ::grpc_impl::ClientAsyncReaderWriter; template - friend class ::grpc::ClientAsyncResponseReader; + friend class ::grpc_impl::ClientAsyncResponseReader; template friend class ::grpc::internal::BlockingUnaryCallImpl; template - friend class ::grpc::internal::CallbackUnaryCallImpl; + friend class ::grpc_impl::internal::CallbackUnaryCallImpl; template - friend class ::grpc::internal::ClientCallbackReaderWriterImpl; + friend class ::grpc_impl::internal::ClientCallbackReaderWriterImpl; template - friend class ::grpc::internal::ClientCallbackReaderImpl; + friend class ::grpc_impl::internal::ClientCallbackReaderImpl; template - friend class ::grpc::internal::ClientCallbackWriterImpl; - friend class ::grpc::internal::ClientCallbackUnaryImpl; + friend class ::grpc_impl::internal::ClientCallbackWriterImpl; + friend class ::grpc_impl::internal::ClientCallbackUnaryImpl; // Used by friend class CallOpClientRecvStatus void set_debug_error_string(const grpc::string& debug_error_string) { diff --git a/include/grpcpp/impl/codegen/client_unary_call.h b/include/grpcpp/impl/codegen/client_unary_call.h index 599dd1ecac9..7f80e571c07 100644 --- a/include/grpcpp/impl/codegen/client_unary_call.h +++ b/include/grpcpp/impl/codegen/client_unary_call.h @@ -49,10 +49,10 @@ class BlockingUnaryCallImpl { BlockingUnaryCallImpl(ChannelInterface* channel, const RpcMethod& method, grpc_impl::ClientContext* context, const InputMessage& request, OutputMessage* result) { - CompletionQueue cq(grpc_completion_queue_attributes{ + ::grpc_impl::CompletionQueue cq(grpc_completion_queue_attributes{ GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING, nullptr}); // Pluckable completion queue - Call call(channel->CreateCall(method, context, &cq)); + ::grpc::internal::Call call(channel->CreateCall(method, context, &cq)); CallOpSet, CallOpClientSendClose, CallOpClientRecvStatus> diff --git a/include/grpcpp/impl/codegen/completion_queue_impl.h b/include/grpcpp/impl/codegen/completion_queue_impl.h index 0a6b0b0977b..7716a57e84a 100644 --- a/include/grpcpp/impl/codegen/completion_queue_impl.h +++ b/include/grpcpp/impl/codegen/completion_queue_impl.h @@ -47,9 +47,6 @@ class Channel; class Server; class ServerBuilder; class ServerContext; -} // namespace grpc_impl -namespace grpc { - template class ClientReader; template @@ -64,6 +61,8 @@ namespace internal { template class ServerReaderWriterBody; } // namespace internal +} // namespace grpc_impl +namespace grpc { class ChannelInterface; class ServerInterface; @@ -255,17 +254,17 @@ class CompletionQueue : private ::grpc::GrpcLibraryCodegen { // Friend synchronous wrappers so that they can access Pluck(), which is // a semi-private API geared towards the synchronous implementation. template - friend class ::grpc::ClientReader; + friend class ::grpc_impl::ClientReader; template - friend class ::grpc::ClientWriter; + friend class ::grpc_impl::ClientWriter; template - friend class ::grpc::ClientReaderWriter; + friend class ::grpc_impl::ClientReaderWriter; template - friend class ::grpc::ServerReader; + friend class ::grpc_impl::ServerReader; template - friend class ::grpc::ServerWriter; + friend class ::grpc_impl::ServerWriter; template - friend class ::grpc::internal::ServerReaderWriterBody; + friend class ::grpc_impl::internal::ServerReaderWriterBody; template friend class ::grpc::internal::RpcMethodHandler; template diff --git a/include/grpcpp/impl/codegen/server_callback.h b/include/grpcpp/impl/codegen/server_callback.h index 36ae19c5bec..cb771a662b9 100644 --- a/include/grpcpp/impl/codegen/server_callback.h +++ b/include/grpcpp/impl/codegen/server_callback.h @@ -19,1141 +19,26 @@ #ifndef GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_H #define GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_H -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include namespace grpc { - -// Declare base class of all reactors as internal -namespace internal { - -// Forward declarations -template -class CallbackClientStreamingHandler; -template -class CallbackServerStreamingHandler; -template -class CallbackBidiHandler; - -class ServerReactor { - public: - virtual ~ServerReactor() = default; - virtual void OnDone() = 0; - virtual void OnCancel() = 0; - - private: - friend class ::grpc_impl::ServerContext; - template - friend class CallbackClientStreamingHandler; - template - friend class CallbackServerStreamingHandler; - template - 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 (GPR_UNLIKELY(on_cancel_conditions_remaining_.fetch_sub( - 1, std::memory_order_acq_rel) == 1)) { - OnCancel(); - } - } - - std::atomic on_cancel_conditions_remaining_{2}; -}; - -template -class DefaultMessageHolder - : public experimental::MessageHolder { - public: - DefaultMessageHolder() { - this->set_request(&request_obj_); - this->set_response(&response_obj_); - } - void Release() override { - // the object is allocated in the call arena. - this->~DefaultMessageHolder(); - } - - private: - Request request_obj_; - Response response_obj_; -}; - -} // namespace internal - namespace experimental { - -// Forward declarations -template -class ServerReadReactor; -template -class ServerWriteReactor; -template -class ServerBidiReactor; - -// For unary RPCs, the exposed controller class is only an interface -// and the actual implementation is an internal class. -class ServerCallbackRpcController { - public: - virtual ~ServerCallbackRpcController() = default; - - // The method handler must call this function when it is done so that - // the library knows to free its resources - virtual void Finish(Status s) = 0; - - // Allow the method handler to push out the initial metadata before - // the response and status are ready - virtual void SendInitialMetadata(std::function) = 0; - - /// SetCancelCallback passes in a callback to be called when the RPC is - /// canceled for whatever reason (streaming calls have OnCancel instead). This - /// is an advanced and uncommon use with several important restrictions. This - /// function may not be called more than once on the same RPC. - /// - /// If code calls SetCancelCallback on an RPC, it must also call - /// ClearCancelCallback before calling Finish on the RPC controller. That - /// method makes sure that no cancellation callback is executed for this RPC - /// beyond the point of its return. ClearCancelCallback may be called even if - /// SetCancelCallback was not called for this RPC, and it may be called - /// multiple times. It _must_ be called if SetCancelCallback was called for - /// this RPC. - /// - /// The callback should generally be lightweight and nonblocking and primarily - /// concerned with clearing application state related to the RPC or causing - /// operations (such as cancellations) to happen on dependent RPCs. - /// - /// If the RPC is already canceled at the time that SetCancelCallback is - /// called, the callback is invoked immediately. - /// - /// The cancellation callback may be executed concurrently with the method - /// handler that invokes it but will certainly not issue or execute after the - /// return of ClearCancelCallback. If ClearCancelCallback is invoked while the - /// callback is already executing, the callback will complete its execution - /// before ClearCancelCallback takes effect. - /// - /// To preserve the orderings described above, the callback may be called - /// under a lock that is also used for ClearCancelCallback and - /// ServerContext::IsCancelled, so the callback CANNOT call either of those - /// operations on this RPC or any other function that causes those operations - /// to be called before the callback completes. - virtual void SetCancelCallback(std::function callback) = 0; - virtual void ClearCancelCallback() = 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 RpcAllocatorState* GetRpcAllocatorState() = 0; -}; - -// NOTE: The actual streaming object classes are provided -// as API only to support mocking. There are no implementations of -// these class interfaces in the API. -template -class ServerCallbackReader { - public: - virtual ~ServerCallbackReader() {} - virtual void Finish(Status s) = 0; - virtual void SendInitialMetadata() = 0; - virtual void Read(Request* msg) = 0; - - protected: - template - void BindReactor(ServerReadReactor* reactor) { - reactor->InternalBindReader(this); - } -}; - -template -class ServerCallbackWriter { - public: - virtual ~ServerCallbackWriter() {} - - virtual void Finish(Status s) = 0; - virtual void SendInitialMetadata() = 0; - virtual void Write(const Response* msg, WriteOptions options) = 0; - virtual void WriteAndFinish(const Response* msg, WriteOptions options, - Status s) { - // Default implementation that can/should be overridden - Write(msg, std::move(options)); - Finish(std::move(s)); - } - - protected: - template - void BindReactor(ServerWriteReactor* reactor) { - reactor->InternalBindWriter(this); - } -}; - -template -class ServerCallbackReaderWriter { - public: - virtual ~ServerCallbackReaderWriter() {} - - virtual void Finish(Status s) = 0; - virtual void SendInitialMetadata() = 0; - virtual void Read(Request* msg) = 0; - virtual void Write(const Response* msg, WriteOptions options) = 0; - virtual void WriteAndFinish(const Response* msg, WriteOptions options, - Status s) { - // Default implementation that can/should be overridden - Write(msg, std::move(options)); - Finish(std::move(s)); - } - - protected: - void BindReactor(ServerBidiReactor* reactor) { - reactor->InternalBindStream(this); - } -}; - -// The following classes are the reactor interfaces that are to be implemented -// by the user, returned as the result of the method handler for a callback -// method, and activated by the call to OnStarted. The library guarantees that -// OnStarted will be called for any reactor that has been created using a -// method handler registered on a service. No operation initiation method may be -// called until after the call to OnStarted. -// Note that none of the classes are pure; all reactions have a default empty -// reaction so that the user class only needs to override those classes that it -// cares about. - -/// \a ServerBidiReactor is the interface for a bidirectional streaming RPC. template -class ServerBidiReactor : public internal::ServerReactor { - public: - ~ServerBidiReactor() = default; - - /// Do NOT call any operation initiation method (names that start with Start) - /// until after the library has called OnStarted on this object. - - /// Send any initial metadata stored in the RPC context. If not invoked, - /// any initial metadata will be passed along with the first Write or the - /// Finish (if there are no writes). - void StartSendInitialMetadata() { stream_->SendInitialMetadata(); } - - /// Initiate a read operation. - /// - /// \param[out] req Where to eventually store the read message. Valid when - /// the library calls OnReadDone - void StartRead(Request* req) { stream_->Read(req); } - - /// Initiate a write operation. - /// - /// \param[in] resp The message to be written. The library takes temporary - /// ownership until OnWriteDone, at which point the - /// application regains ownership of resp. - void StartWrite(const Response* resp) { StartWrite(resp, WriteOptions()); } - - /// Initiate a write operation with specified options. - /// - /// \param[in] resp The message to be written. The library takes temporary - /// ownership until OnWriteDone, at which point the - /// application regains ownership of resp. - /// \param[in] options The WriteOptions to use for writing this message - void StartWrite(const Response* resp, WriteOptions options) { - stream_->Write(resp, std::move(options)); - } - - /// Initiate a write operation with specified options and final RPC Status, - /// which also causes any trailing metadata for this RPC to be sent out. - /// StartWriteAndFinish is like merging StartWriteLast and Finish into a - /// single step. A key difference, though, is that this operation doesn't have - /// an OnWriteDone reaction - it is considered complete only when OnDone is - /// available. An RPC can either have StartWriteAndFinish or Finish, but not - /// both. - /// - /// \param[in] resp The message to be written. The library takes temporary - /// ownership until Onone, at which point the application - /// regains ownership of resp. - /// \param[in] options The WriteOptions to use for writing this message - /// \param[in] s The status outcome of this RPC - void StartWriteAndFinish(const Response* resp, WriteOptions options, - Status s) { - stream_->WriteAndFinish(resp, std::move(options), std::move(s)); - } - - /// Inform system of a planned write operation with specified options, but - /// allow the library to schedule the actual write coalesced with the writing - /// of trailing metadata (which takes place on a Finish call). - /// - /// \param[in] resp The message to be written. The library takes temporary - /// ownership until OnWriteDone, at which point the - /// application regains ownership of resp. - /// \param[in] options The WriteOptions to use for writing this message - void StartWriteLast(const Response* resp, WriteOptions options) { - StartWrite(resp, std::move(options.set_last_message())); - } - - /// Indicate that the stream is to be finished and the trailing metadata and - /// RPC status are to be sent. Every RPC MUST be finished using either Finish - /// or StartWriteAndFinish (but not both), even if the RPC is already - /// cancelled. - /// - /// \param[in] s The status outcome of this RPC - void Finish(Status s) { stream_->Finish(std::move(s)); } - - /// Notify the application that a streaming RPC has started and that it is now - /// ok to call any operation initiation method. An RPC is considered started - /// after the server has received all initial metadata from the client, which - /// is a result of the client calling StartCall(). - /// - /// \param[in] context The context object now associated with this RPC - virtual void OnStarted(::grpc_impl::ServerContext* context) {} - - /// Notifies the application that an explicit StartSendInitialMetadata - /// operation completed. Not used when the sending of initial metadata - /// piggybacks onto the first write. - /// - /// \param[in] ok Was it successful? If false, no further write-side operation - /// will succeed. - virtual void OnSendInitialMetadataDone(bool ok) {} - - /// Notifies the application that a StartRead operation completed. - /// - /// \param[in] ok Was it successful? If false, no further read-side operation - /// will succeed. - virtual void OnReadDone(bool ok) {} - - /// Notifies the application that a StartWrite (or StartWriteLast) operation - /// completed. - /// - /// \param[in] ok Was it successful? If false, no further write-side operation - /// will succeed. - virtual void OnWriteDone(bool ok) {} - - /// Notifies the application that all operations associated with this RPC - /// have completed. This is an override (from the internal base class) but not - /// final, so derived classes should override it if they want to take action. - void OnDone() override {} - - /// Notifies the application that this RPC has been cancelled. This is an - /// override (from the internal base class) but not final, so derived classes - /// should override it if they want to take action. - void OnCancel() override {} - - private: - friend class ServerCallbackReaderWriter; - // May be overridden by internal implementation details. This is not a public - // customization point. - virtual void InternalBindStream( - ServerCallbackReaderWriter* stream) { - stream_ = stream; - } +using ServerReadReactor = + ::grpc_impl::experimental::ServerReadReactor; - ServerCallbackReaderWriter* stream_; -}; - -/// \a ServerReadReactor is the interface for a client-streaming RPC. template -class ServerReadReactor : public internal::ServerReactor { - public: - ~ServerReadReactor() = default; - - /// The following operation initiations are exactly like ServerBidiReactor. - void StartSendInitialMetadata() { reader_->SendInitialMetadata(); } - void StartRead(Request* req) { reader_->Read(req); } - void Finish(Status s) { reader_->Finish(std::move(s)); } - - /// Similar to ServerBidiReactor::OnStarted, except that this also provides - /// the response object that the stream fills in before calling Finish. - /// (It must be filled in if status is OK, but it may be filled in otherwise.) - /// - /// \param[in] context The context object now associated with this RPC - /// \param[in] resp The response object to be used by this RPC - virtual void OnStarted(::grpc_impl::ServerContext* context, Response* resp) {} - - /// The following notifications are exactly like ServerBidiReactor. - virtual void OnSendInitialMetadataDone(bool ok) {} - virtual void OnReadDone(bool ok) {} - void OnDone() override {} - void OnCancel() override {} - - private: - friend class ServerCallbackReader; - // May be overridden by internal implementation details. This is not a public - // customization point. - virtual void InternalBindReader(ServerCallbackReader* reader) { - reader_ = reader; - } +using ServerWriteReactor = + ::grpc_impl::experimental::ServerWriteReactor; - ServerCallbackReader* reader_; -}; - -/// \a ServerWriteReactor is the interface for a server-streaming RPC. template -class ServerWriteReactor : public internal::ServerReactor { - public: - ~ServerWriteReactor() = default; - - /// The following operation initiations are exactly like ServerBidiReactor. - void StartSendInitialMetadata() { writer_->SendInitialMetadata(); } - void StartWrite(const Response* resp) { StartWrite(resp, WriteOptions()); } - void StartWrite(const Response* resp, WriteOptions options) { - writer_->Write(resp, std::move(options)); - } - void StartWriteAndFinish(const Response* resp, WriteOptions options, - Status s) { - writer_->WriteAndFinish(resp, std::move(options), std::move(s)); - } - void StartWriteLast(const Response* resp, WriteOptions options) { - StartWrite(resp, std::move(options.set_last_message())); - } - void Finish(Status s) { writer_->Finish(std::move(s)); } - - /// Similar to ServerBidiReactor::OnStarted, except that this also provides - /// the request object sent by the client. - /// - /// \param[in] context The context object now associated with this RPC - /// \param[in] req The request object sent by the client - virtual void OnStarted(::grpc_impl::ServerContext* context, - const Request* req) {} - - /// The following notifications are exactly like ServerBidiReactor. - virtual void OnSendInitialMetadataDone(bool ok) {} - virtual void OnWriteDone(bool ok) {} - void OnDone() override {} - void OnCancel() override {} +using ServerBidiReactor = + ::grpc_impl::experimental::ServerBidiReactor; - private: - friend class ServerCallbackWriter; - // May be overridden by internal implementation details. This is not a public - // customization point. - virtual void InternalBindWriter(ServerCallbackWriter* writer) { - writer_ = writer; - } - - ServerCallbackWriter* writer_; -}; +typedef ::grpc_impl::experimental::ServerCallbackRpcController + ServerCallbackRpcController; } // namespace experimental - -namespace internal { - -template -class UnimplementedReadReactor - : public experimental::ServerReadReactor { - public: - void OnDone() override { delete this; } - void OnStarted(::grpc_impl::ServerContext*, Response*) override { - this->Finish(Status(StatusCode::UNIMPLEMENTED, "")); - } -}; - -template -class UnimplementedWriteReactor - : public experimental::ServerWriteReactor { - public: - void OnDone() override { delete this; } - void OnStarted(::grpc_impl::ServerContext*, const Request*) override { - this->Finish(Status(StatusCode::UNIMPLEMENTED, "")); - } -}; - -template -class UnimplementedBidiReactor - : public experimental::ServerBidiReactor { - public: - void OnDone() override { delete this; } - void OnStarted(::grpc_impl::ServerContext*) override { - this->Finish(Status(StatusCode::UNIMPLEMENTED, "")); - } -}; - -template -class CallbackUnaryHandler : public MethodHandler { - public: - CallbackUnaryHandler( - std::function - func) - : func_(func) {} - - void SetMessageAllocator( - experimental::MessageAllocator* 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_state = - static_cast*>( - param.internal_data); - auto* controller = new (g_core_codegen_interface->grpc_call_arena_alloc( - param.call->call(), sizeof(ServerCallbackRpcControllerImpl))) - ServerCallbackRpcControllerImpl(param.server_context, param.call, - allocator_state, - 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(), - controller->response(), controller); - } else { - // if deserialization failed, we need to fail the call - controller->Finish(status); - } - } - - void* Deserialize(grpc_call* call, grpc_byte_buffer* req, Status* status, - void** handler_data) final { - ByteBuffer buf; - buf.set_buffer(req); - RequestType* request = nullptr; - experimental::MessageHolder* allocator_state = - nullptr; - if (allocator_ != nullptr) { - allocator_state = allocator_->AllocateMessages(); - } else { - allocator_state = new (g_core_codegen_interface->grpc_call_arena_alloc( - call, sizeof(DefaultMessageHolder))) - DefaultMessageHolder(); - } - *handler_data = allocator_state; - request = allocator_state->request(); - *status = SerializationTraits::Deserialize(&buf, request); - buf.Release(); - if (status->ok()) { - return request; - } - // Clean up on deserialization failure. - allocator_state->Release(); - return nullptr; - } - - private: - std::function - func_; - experimental::MessageAllocator* allocator_ = - nullptr; - - // The implementation class of ServerCallbackRpcController is a private member - // of CallbackUnaryHandler since it is never exposed anywhere, and this allows - // it to take advantage of CallbackUnaryHandler's friendships. - class ServerCallbackRpcControllerImpl - : public experimental::ServerCallbackRpcController { - public: - void Finish(Status s) override { - finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); }, - &finish_ops_); - if (!ctx_->sent_initial_metadata_) { - finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - finish_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - } - // The response is dropped if the status is not OK. - if (s.ok()) { - finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, - finish_ops_.SendMessagePtr(response())); - } else { - finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s); - } - finish_ops_.set_core_cq_tag(&finish_tag_); - call_.PerformOps(&finish_ops_); - } - - void SendInitialMetadata(std::function f) override { - GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); - callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); - // TODO(vjpai): Consider taking f as a move-capture if we adopt C++14 - // and if performance of this operation matters - meta_tag_.Set(call_.call(), - [this, f](bool ok) { - f(ok); - MaybeDone(); - }, - &meta_ops_); - meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - meta_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - meta_ops_.set_core_cq_tag(&meta_tag_); - call_.PerformOps(&meta_ops_); - } - - // Neither SetCancelCallback nor ClearCancelCallback should affect the - // callbacks_outstanding_ count since they are paired and both must precede - // the invocation of Finish (if they are used at all) - void SetCancelCallback(std::function callback) override { - ctx_->SetCancelCallback(std::move(callback)); - } - - void ClearCancelCallback() override { ctx_->ClearCancelCallback(); } - - experimental::RpcAllocatorState* GetRpcAllocatorState() override { - return allocator_state_; - } - - private: - friend class CallbackUnaryHandler; - - ServerCallbackRpcControllerImpl( - ::grpc_impl::ServerContext* ctx, Call* call, - experimental::MessageHolder* allocator_state, - std::function call_requester) - : ctx_(ctx), - call_(*call), - allocator_state_(allocator_state), - call_requester_(std::move(call_requester)) { - ctx_->BeginCompletionOp(call, [this](bool) { MaybeDone(); }, nullptr); - } - - const RequestType* request() { return allocator_state_->request(); } - ResponseType* response() { return allocator_state_->response(); } - - void MaybeDone() { - if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( - 1, std::memory_order_acq_rel) == 1)) { - grpc_call* call = call_.call(); - auto call_requester = std::move(call_requester_); - allocator_state_->Release(); - this->~ServerCallbackRpcControllerImpl(); // explicitly call destructor - g_core_codegen_interface->grpc_call_unref(call); - call_requester(); - } - } - - CallOpSet meta_ops_; - CallbackWithSuccessTag meta_tag_; - CallOpSet - finish_ops_; - CallbackWithSuccessTag finish_tag_; - - ::grpc_impl::ServerContext* ctx_; - Call call_; - experimental::MessageHolder* const - allocator_state_; - std::function call_requester_; - std::atomic callbacks_outstanding_{ - 2}; // reserve for Finish and CompletionOp - }; -}; - -template -class CallbackClientStreamingHandler : public MethodHandler { - public: - CallbackClientStreamingHandler( - std::function< - experimental::ServerReadReactor*()> - func) - : func_(std::move(func)) {} - void RunHandler(const HandlerParameter& param) final { - // Arena allocate a reader structure (that includes response) - g_core_codegen_interface->grpc_call_ref(param.call->call()); - - experimental::ServerReadReactor* reactor = - param.status.ok() - ? CatchingReactorCreator< - experimental::ServerReadReactor>( - func_) - : nullptr; - - if (reactor == nullptr) { - // if deserialization or reactor creator failed, we need to fail the call - reactor = new UnimplementedReadReactor; - } - - auto* reader = new (g_core_codegen_interface->grpc_call_arena_alloc( - param.call->call(), sizeof(ServerCallbackReaderImpl))) - ServerCallbackReaderImpl(param.server_context, param.call, - std::move(param.call_requester), reactor); - - 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(); - } - - private: - std::function*()> - func_; - - class ServerCallbackReaderImpl - : public experimental::ServerCallbackReader { - public: - void Finish(Status s) override { - finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); }, - &finish_ops_); - if (!ctx_->sent_initial_metadata_) { - finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - finish_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - } - // The response is dropped if the status is not OK. - if (s.ok()) { - finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, - finish_ops_.SendMessagePtr(&resp_)); - } else { - finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s); - } - finish_ops_.set_core_cq_tag(&finish_tag_); - call_.PerformOps(&finish_ops_); - } - - void SendInitialMetadata() override { - GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); - callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); - meta_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnSendInitialMetadataDone(ok); - MaybeDone(); - }, - &meta_ops_); - meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - meta_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - meta_ops_.set_core_cq_tag(&meta_tag_); - call_.PerformOps(&meta_ops_); - } - - void Read(RequestType* req) override { - callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); - read_ops_.RecvMessage(req); - call_.PerformOps(&read_ops_); - } - - private: - friend class CallbackClientStreamingHandler; - - ServerCallbackReaderImpl( - ::grpc_impl::ServerContext* ctx, Call* call, - std::function call_requester, - experimental::ServerReadReactor* reactor) - : ctx_(ctx), - call_(*call), - call_requester_(std::move(call_requester)), - reactor_(reactor) { - ctx_->BeginCompletionOp(call, [this](bool) { MaybeDone(); }, reactor); - read_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnReadDone(ok); - MaybeDone(); - }, - &read_ops_); - read_ops_.set_core_cq_tag(&read_tag_); - } - - ~ServerCallbackReaderImpl() {} - - ResponseType* response() { return &resp_; } - - void MaybeDone() { - if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( - 1, std::memory_order_acq_rel) == 1)) { - reactor_->OnDone(); - grpc_call* call = call_.call(); - auto call_requester = std::move(call_requester_); - this->~ServerCallbackReaderImpl(); // explicitly call destructor - g_core_codegen_interface->grpc_call_unref(call); - call_requester(); - } - } - - CallOpSet meta_ops_; - CallbackWithSuccessTag meta_tag_; - CallOpSet - finish_ops_; - CallbackWithSuccessTag finish_tag_; - CallOpSet> read_ops_; - CallbackWithSuccessTag read_tag_; - - ::grpc_impl::ServerContext* ctx_; - Call call_; - ResponseType resp_; - std::function call_requester_; - experimental::ServerReadReactor* reactor_; - std::atomic callbacks_outstanding_{ - 3}; // reserve for OnStarted, Finish, and CompletionOp - }; -}; - -template -class CallbackServerStreamingHandler : public MethodHandler { - public: - CallbackServerStreamingHandler( - std::function< - experimental::ServerWriteReactor*()> - func) - : func_(std::move(func)) {} - void RunHandler(const HandlerParameter& param) final { - // Arena allocate a writer structure - g_core_codegen_interface->grpc_call_ref(param.call->call()); - - experimental::ServerWriteReactor* reactor = - param.status.ok() - ? CatchingReactorCreator< - experimental::ServerWriteReactor>( - func_) - : nullptr; - - if (reactor == nullptr) { - // if deserialization or reactor creator failed, we need to fail the call - reactor = new UnimplementedWriteReactor; - } - - auto* writer = new (g_core_codegen_interface->grpc_call_arena_alloc( - param.call->call(), sizeof(ServerCallbackWriterImpl))) - ServerCallbackWriterImpl(param.server_context, param.call, - static_cast(param.request), - 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, - 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(); - *status = SerializationTraits::Deserialize(&buf, request); - buf.Release(); - if (status->ok()) { - return request; - } - request->~RequestType(); - return nullptr; - } - - private: - std::function*()> - func_; - - class ServerCallbackWriterImpl - : public experimental::ServerCallbackWriter { - public: - void Finish(Status s) override { - finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); }, - &finish_ops_); - finish_ops_.set_core_cq_tag(&finish_tag_); - - if (!ctx_->sent_initial_metadata_) { - finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - finish_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - } - finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s); - call_.PerformOps(&finish_ops_); - } - - void SendInitialMetadata() override { - GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); - callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); - meta_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnSendInitialMetadataDone(ok); - MaybeDone(); - }, - &meta_ops_); - meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - meta_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - meta_ops_.set_core_cq_tag(&meta_tag_); - call_.PerformOps(&meta_ops_); - } - - void Write(const ResponseType* resp, WriteOptions options) override { - callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); - if (options.is_last_message()) { - options.set_buffer_hint(); - } - if (!ctx_->sent_initial_metadata_) { - write_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - write_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - } - // TODO(vjpai): don't assert - GPR_CODEGEN_ASSERT(write_ops_.SendMessagePtr(resp, options).ok()); - call_.PerformOps(&write_ops_); - } - - void WriteAndFinish(const ResponseType* resp, WriteOptions options, - Status s) override { - // This combines the write into the finish callback - // Don't send any message if the status is bad - if (s.ok()) { - // TODO(vjpai): don't assert - GPR_CODEGEN_ASSERT(finish_ops_.SendMessagePtr(resp, options).ok()); - } - Finish(std::move(s)); - } - - private: - friend class CallbackServerStreamingHandler; - - ServerCallbackWriterImpl( - ::grpc_impl::ServerContext* ctx, Call* call, const RequestType* req, - std::function call_requester, - experimental::ServerWriteReactor* reactor) - : ctx_(ctx), - call_(*call), - req_(req), - call_requester_(std::move(call_requester)), - reactor_(reactor) { - ctx_->BeginCompletionOp(call, [this](bool) { MaybeDone(); }, reactor); - write_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnWriteDone(ok); - MaybeDone(); - }, - &write_ops_); - write_ops_.set_core_cq_tag(&write_tag_); - } - ~ServerCallbackWriterImpl() { req_->~RequestType(); } - - const RequestType* request() { return req_; } - - void MaybeDone() { - if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( - 1, std::memory_order_acq_rel) == 1)) { - reactor_->OnDone(); - grpc_call* call = call_.call(); - auto call_requester = std::move(call_requester_); - this->~ServerCallbackWriterImpl(); // explicitly call destructor - g_core_codegen_interface->grpc_call_unref(call); - call_requester(); - } - } - - CallOpSet meta_ops_; - CallbackWithSuccessTag meta_tag_; - CallOpSet - finish_ops_; - CallbackWithSuccessTag finish_tag_; - CallOpSet write_ops_; - CallbackWithSuccessTag write_tag_; - - ::grpc_impl::ServerContext* ctx_; - Call call_; - const RequestType* req_; - std::function call_requester_; - experimental::ServerWriteReactor* reactor_; - std::atomic callbacks_outstanding_{ - 3}; // reserve for OnStarted, Finish, and CompletionOp - }; -}; - -template -class CallbackBidiHandler : public MethodHandler { - public: - CallbackBidiHandler( - std::function< - experimental::ServerBidiReactor*()> - func) - : func_(std::move(func)) {} - void RunHandler(const HandlerParameter& param) final { - g_core_codegen_interface->grpc_call_ref(param.call->call()); - - experimental::ServerBidiReactor* reactor = - param.status.ok() - ? CatchingReactorCreator< - experimental::ServerBidiReactor>( - func_) - : nullptr; - - if (reactor == nullptr) { - // if deserialization or reactor creator failed, we need to fail the call - reactor = new UnimplementedBidiReactor; - } - - auto* stream = new (g_core_codegen_interface->grpc_call_arena_alloc( - param.call->call(), sizeof(ServerCallbackReaderWriterImpl))) - ServerCallbackReaderWriterImpl(param.server_context, param.call, - std::move(param.call_requester), - reactor); - - stream->BindReactor(reactor); - reactor->OnStarted(param.server_context); - // The earliest that OnCancel can be called is after OnStarted is done. - reactor->MaybeCallOnCancel(); - stream->MaybeDone(); - } - - private: - std::function*()> - func_; - - class ServerCallbackReaderWriterImpl - : public experimental::ServerCallbackReaderWriter { - public: - void Finish(Status s) override { - finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); }, - &finish_ops_); - finish_ops_.set_core_cq_tag(&finish_tag_); - - if (!ctx_->sent_initial_metadata_) { - finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - finish_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - } - finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s); - call_.PerformOps(&finish_ops_); - } - - void SendInitialMetadata() override { - GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); - callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); - meta_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnSendInitialMetadataDone(ok); - MaybeDone(); - }, - &meta_ops_); - meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - meta_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - meta_ops_.set_core_cq_tag(&meta_tag_); - call_.PerformOps(&meta_ops_); - } - - void Write(const ResponseType* resp, WriteOptions options) override { - callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); - if (options.is_last_message()) { - options.set_buffer_hint(); - } - if (!ctx_->sent_initial_metadata_) { - write_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - write_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - } - // TODO(vjpai): don't assert - GPR_CODEGEN_ASSERT(write_ops_.SendMessagePtr(resp, options).ok()); - call_.PerformOps(&write_ops_); - } - - void WriteAndFinish(const ResponseType* resp, WriteOptions options, - Status s) override { - // Don't send any message if the status is bad - if (s.ok()) { - // TODO(vjpai): don't assert - GPR_CODEGEN_ASSERT(finish_ops_.SendMessagePtr(resp, options).ok()); - } - Finish(std::move(s)); - } - - void Read(RequestType* req) override { - callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); - read_ops_.RecvMessage(req); - call_.PerformOps(&read_ops_); - } - - private: - friend class CallbackBidiHandler; - - ServerCallbackReaderWriterImpl( - ::grpc_impl::ServerContext* ctx, Call* call, - std::function call_requester, - experimental::ServerBidiReactor* reactor) - : ctx_(ctx), - call_(*call), - call_requester_(std::move(call_requester)), - reactor_(reactor) { - ctx_->BeginCompletionOp(call, [this](bool) { MaybeDone(); }, reactor); - write_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnWriteDone(ok); - MaybeDone(); - }, - &write_ops_); - write_ops_.set_core_cq_tag(&write_tag_); - read_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnReadDone(ok); - MaybeDone(); - }, - &read_ops_); - read_ops_.set_core_cq_tag(&read_tag_); - } - ~ServerCallbackReaderWriterImpl() {} - - void MaybeDone() { - if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( - 1, std::memory_order_acq_rel) == 1)) { - reactor_->OnDone(); - grpc_call* call = call_.call(); - auto call_requester = std::move(call_requester_); - this->~ServerCallbackReaderWriterImpl(); // explicitly call destructor - g_core_codegen_interface->grpc_call_unref(call); - call_requester(); - } - } - - CallOpSet meta_ops_; - CallbackWithSuccessTag meta_tag_; - CallOpSet - finish_ops_; - CallbackWithSuccessTag finish_tag_; - CallOpSet write_ops_; - CallbackWithSuccessTag write_tag_; - CallOpSet> read_ops_; - CallbackWithSuccessTag read_tag_; - - ::grpc_impl::ServerContext* ctx_; - Call call_; - std::function call_requester_; - experimental::ServerBidiReactor* reactor_; - std::atomic callbacks_outstanding_{ - 3}; // reserve for OnStarted, Finish, and CompletionOp - }; -}; - -} // namespace internal - } // namespace grpc #endif // GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_H diff --git a/include/grpcpp/impl/codegen/server_callback_impl.h b/include/grpcpp/impl/codegen/server_callback_impl.h new file mode 100644 index 00000000000..08ecdfd6497 --- /dev/null +++ b/include/grpcpp/impl/codegen/server_callback_impl.h @@ -0,0 +1,1186 @@ +/* + * + * 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_SERVER_CALLBACK_IMPL_H +#define GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_IMPL_H + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace grpc_impl { + +// Declare base class of all reactors as internal +namespace internal { + +// Forward declarations +template +class CallbackClientStreamingHandler; +template +class CallbackServerStreamingHandler; +template +class CallbackBidiHandler; + +class ServerReactor { + public: + virtual ~ServerReactor() = default; + virtual void OnDone() = 0; + virtual void OnCancel() = 0; + + private: + friend class ::grpc_impl::ServerContext; + template + friend class CallbackClientStreamingHandler; + template + friend class CallbackServerStreamingHandler; + template + 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 (GPR_UNLIKELY(on_cancel_conditions_remaining_.fetch_sub( + 1, std::memory_order_acq_rel) == 1)) { + OnCancel(); + } + } + + std::atomic on_cancel_conditions_remaining_{2}; +}; + +template +class DefaultMessageHolder + : public ::grpc::experimental::MessageHolder { + public: + DefaultMessageHolder() { + this->set_request(&request_obj_); + this->set_response(&response_obj_); + } + void Release() override { + // the object is allocated in the call arena. + this->~DefaultMessageHolder(); + } + + private: + Request request_obj_; + Response response_obj_; +}; + +} // namespace internal + +namespace experimental { + +// Forward declarations +template +class ServerReadReactor; +template +class ServerWriteReactor; +template +class ServerBidiReactor; + +// For unary RPCs, the exposed controller class is only an interface +// and the actual implementation is an internal class. +class ServerCallbackRpcController { + public: + virtual ~ServerCallbackRpcController() = default; + + // The method handler must call this function when it is done so that + // the library knows to free its resources + virtual void Finish(::grpc::Status s) = 0; + + // Allow the method handler to push out the initial metadata before + // the response and status are ready + virtual void SendInitialMetadata(std::function) = 0; + + /// SetCancelCallback passes in a callback to be called when the RPC is + /// canceled for whatever reason (streaming calls have OnCancel instead). This + /// is an advanced and uncommon use with several important restrictions. This + /// function may not be called more than once on the same RPC. + /// + /// If code calls SetCancelCallback on an RPC, it must also call + /// ClearCancelCallback before calling Finish on the RPC controller. That + /// method makes sure that no cancellation callback is executed for this RPC + /// beyond the point of its return. ClearCancelCallback may be called even if + /// SetCancelCallback was not called for this RPC, and it may be called + /// multiple times. It _must_ be called if SetCancelCallback was called for + /// this RPC. + /// + /// The callback should generally be lightweight and nonblocking and primarily + /// concerned with clearing application state related to the RPC or causing + /// operations (such as cancellations) to happen on dependent RPCs. + /// + /// If the RPC is already canceled at the time that SetCancelCallback is + /// called, the callback is invoked immediately. + /// + /// The cancellation callback may be executed concurrently with the method + /// handler that invokes it but will certainly not issue or execute after the + /// return of ClearCancelCallback. If ClearCancelCallback is invoked while the + /// callback is already executing, the callback will complete its execution + /// before ClearCancelCallback takes effect. + /// + /// To preserve the orderings described above, the callback may be called + /// under a lock that is also used for ClearCancelCallback and + /// ServerContext::IsCancelled, so the callback CANNOT call either of those + /// operations on this RPC or any other function that causes those operations + /// to be called before the callback completes. + virtual void SetCancelCallback(std::function callback) = 0; + virtual void ClearCancelCallback() = 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 grpc::experimental::RpcAllocatorState* GetRpcAllocatorState() = 0; +}; + +// NOTE: The actual streaming object classes are provided +// as API only to support mocking. There are no implementations of +// these class interfaces in the API. +template +class ServerCallbackReader { + public: + virtual ~ServerCallbackReader() {} + virtual void Finish(::grpc::Status s) = 0; + virtual void SendInitialMetadata() = 0; + virtual void Read(Request* msg) = 0; + + protected: + template + void BindReactor(ServerReadReactor* reactor) { + reactor->InternalBindReader(this); + } +}; + +template +class ServerCallbackWriter { + public: + virtual ~ServerCallbackWriter() {} + + virtual void Finish(::grpc::Status s) = 0; + virtual void SendInitialMetadata() = 0; + virtual void Write(const Response* msg, ::grpc::WriteOptions options) = 0; + virtual void WriteAndFinish(const Response* msg, ::grpc::WriteOptions options, + ::grpc::Status s) { + // Default implementation that can/should be overridden + Write(msg, std::move(options)); + Finish(std::move(s)); + } + + protected: + template + void BindReactor(ServerWriteReactor* reactor) { + reactor->InternalBindWriter(this); + } +}; + +template +class ServerCallbackReaderWriter { + public: + virtual ~ServerCallbackReaderWriter() {} + + virtual void Finish(::grpc::Status s) = 0; + virtual void SendInitialMetadata() = 0; + virtual void Read(Request* msg) = 0; + virtual void Write(const Response* msg, ::grpc::WriteOptions options) = 0; + virtual void WriteAndFinish(const Response* msg, ::grpc::WriteOptions options, + ::grpc::Status s) { + // Default implementation that can/should be overridden + Write(msg, std::move(options)); + Finish(std::move(s)); + } + + protected: + void BindReactor(ServerBidiReactor* reactor) { + reactor->InternalBindStream(this); + } +}; + +// The following classes are the reactor interfaces that are to be implemented +// by the user, returned as the result of the method handler for a callback +// method, and activated by the call to OnStarted. The library guarantees that +// OnStarted will be called for any reactor that has been created using a +// method handler registered on a service. No operation initiation method may be +// called until after the call to OnStarted. +// Note that none of the classes are pure; all reactions have a default empty +// reaction so that the user class only needs to override those classes that it +// cares about. + +/// \a ServerBidiReactor is the interface for a bidirectional streaming RPC. +template +class ServerBidiReactor : public internal::ServerReactor { + public: + ~ServerBidiReactor() = default; + + /// Do NOT call any operation initiation method (names that start with Start) + /// until after the library has called OnStarted on this object. + + /// Send any initial metadata stored in the RPC context. If not invoked, + /// any initial metadata will be passed along with the first Write or the + /// Finish (if there are no writes). + void StartSendInitialMetadata() { stream_->SendInitialMetadata(); } + + /// Initiate a read operation. + /// + /// \param[out] req Where to eventually store the read message. Valid when + /// the library calls OnReadDone + void StartRead(Request* req) { stream_->Read(req); } + + /// Initiate a write operation. + /// + /// \param[in] resp The message to be written. The library takes temporary + /// ownership until OnWriteDone, at which point the + /// application regains ownership of resp. + void StartWrite(const Response* resp) { + StartWrite(resp, ::grpc::WriteOptions()); + } + + /// Initiate a write operation with specified options. + /// + /// \param[in] resp The message to be written. The library takes temporary + /// ownership until OnWriteDone, at which point the + /// application regains ownership of resp. + /// \param[in] options The WriteOptions to use for writing this message + void StartWrite(const Response* resp, ::grpc::WriteOptions options) { + stream_->Write(resp, std::move(options)); + } + + /// Initiate a write operation with specified options and final RPC Status, + /// which also causes any trailing metadata for this RPC to be sent out. + /// StartWriteAndFinish is like merging StartWriteLast and Finish into a + /// single step. A key difference, though, is that this operation doesn't have + /// an OnWriteDone reaction - it is considered complete only when OnDone is + /// available. An RPC can either have StartWriteAndFinish or Finish, but not + /// both. + /// + /// \param[in] resp The message to be written. The library takes temporary + /// ownership until Onone, at which point the application + /// regains ownership of resp. + /// \param[in] options The WriteOptions to use for writing this message + /// \param[in] s The status outcome of this RPC + void StartWriteAndFinish(const Response* resp, ::grpc::WriteOptions options, + ::grpc::Status s) { + stream_->WriteAndFinish(resp, std::move(options), std::move(s)); + } + + /// Inform system of a planned write operation with specified options, but + /// allow the library to schedule the actual write coalesced with the writing + /// of trailing metadata (which takes place on a Finish call). + /// + /// \param[in] resp The message to be written. The library takes temporary + /// ownership until OnWriteDone, at which point the + /// application regains ownership of resp. + /// \param[in] options The WriteOptions to use for writing this message + void StartWriteLast(const Response* resp, ::grpc::WriteOptions options) { + StartWrite(resp, std::move(options.set_last_message())); + } + + /// Indicate that the stream is to be finished and the trailing metadata and + /// RPC status are to be sent. Every RPC MUST be finished using either Finish + /// or StartWriteAndFinish (but not both), even if the RPC is already + /// cancelled. + /// + /// \param[in] s The status outcome of this RPC + void Finish(::grpc::Status s) { stream_->Finish(std::move(s)); } + + /// Notify the application that a streaming RPC has started and that it is now + /// ok to call any operation initiation method. An RPC is considered started + /// after the server has received all initial metadata from the client, which + /// is a result of the client calling StartCall(). + /// + /// \param[in] context The context object now associated with this RPC + virtual void OnStarted(::grpc_impl::ServerContext* context) {} + + /// Notifies the application that an explicit StartSendInitialMetadata + /// operation completed. Not used when the sending of initial metadata + /// piggybacks onto the first write. + /// + /// \param[in] ok Was it successful? If false, no further write-side operation + /// will succeed. + virtual void OnSendInitialMetadataDone(bool ok) {} + + /// Notifies the application that a StartRead operation completed. + /// + /// \param[in] ok Was it successful? If false, no further read-side operation + /// will succeed. + virtual void OnReadDone(bool ok) {} + + /// Notifies the application that a StartWrite (or StartWriteLast) operation + /// completed. + /// + /// \param[in] ok Was it successful? If false, no further write-side operation + /// will succeed. + virtual void OnWriteDone(bool ok) {} + + /// Notifies the application that all operations associated with this RPC + /// have completed. This is an override (from the internal base class) but not + /// final, so derived classes should override it if they want to take action. + void OnDone() override {} + + /// Notifies the application that this RPC has been cancelled. This is an + /// override (from the internal base class) but not final, so derived classes + /// should override it if they want to take action. + void OnCancel() override {} + + private: + friend class ServerCallbackReaderWriter; + // May be overridden by internal implementation details. This is not a public + // customization point. + virtual void InternalBindStream( + ServerCallbackReaderWriter* stream) { + stream_ = stream; + } + + ServerCallbackReaderWriter* stream_; +}; + +/// \a ServerReadReactor is the interface for a client-streaming RPC. +template +class ServerReadReactor : public internal::ServerReactor { + public: + ~ServerReadReactor() = default; + + /// The following operation initiations are exactly like ServerBidiReactor. + void StartSendInitialMetadata() { reader_->SendInitialMetadata(); } + void StartRead(Request* req) { reader_->Read(req); } + void Finish(::grpc::Status s) { reader_->Finish(std::move(s)); } + + /// Similar to ServerBidiReactor::OnStarted, except that this also provides + /// the response object that the stream fills in before calling Finish. + /// (It must be filled in if status is OK, but it may be filled in otherwise.) + /// + /// \param[in] context The context object now associated with this RPC + /// \param[in] resp The response object to be used by this RPC + virtual void OnStarted(::grpc_impl::ServerContext* context, Response* resp) {} + + /// The following notifications are exactly like ServerBidiReactor. + virtual void OnSendInitialMetadataDone(bool ok) {} + virtual void OnReadDone(bool ok) {} + void OnDone() override {} + void OnCancel() override {} + + private: + friend class ServerCallbackReader; + // May be overridden by internal implementation details. This is not a public + // customization point. + virtual void InternalBindReader(ServerCallbackReader* reader) { + reader_ = reader; + } + + ServerCallbackReader* reader_; +}; + +/// \a ServerWriteReactor is the interface for a server-streaming RPC. +template +class ServerWriteReactor : public internal::ServerReactor { + public: + ~ServerWriteReactor() = default; + + /// The following operation initiations are exactly like ServerBidiReactor. + void StartSendInitialMetadata() { writer_->SendInitialMetadata(); } + void StartWrite(const Response* resp) { + StartWrite(resp, ::grpc::WriteOptions()); + } + void StartWrite(const Response* resp, ::grpc::WriteOptions options) { + writer_->Write(resp, std::move(options)); + } + void StartWriteAndFinish(const Response* resp, ::grpc::WriteOptions options, + ::grpc::Status s) { + writer_->WriteAndFinish(resp, std::move(options), std::move(s)); + } + void StartWriteLast(const Response* resp, ::grpc::WriteOptions options) { + StartWrite(resp, std::move(options.set_last_message())); + } + void Finish(::grpc::Status s) { writer_->Finish(std::move(s)); } + + /// Similar to ServerBidiReactor::OnStarted, except that this also provides + /// the request object sent by the client. + /// + /// \param[in] context The context object now associated with this RPC + /// \param[in] req The request object sent by the client + virtual void OnStarted(::grpc_impl::ServerContext* context, + const Request* req) {} + + /// The following notifications are exactly like ServerBidiReactor. + virtual void OnSendInitialMetadataDone(bool ok) {} + virtual void OnWriteDone(bool ok) {} + void OnDone() override {} + void OnCancel() override {} + + private: + friend class ServerCallbackWriter; + // May be overridden by internal implementation details. This is not a public + // customization point. + virtual void InternalBindWriter(ServerCallbackWriter* writer) { + writer_ = writer; + } + + ServerCallbackWriter* writer_; +}; + +} // namespace experimental + +namespace internal { + +template +class UnimplementedReadReactor + : public experimental::ServerReadReactor { + public: + void OnDone() override { delete this; } + void OnStarted(::grpc_impl::ServerContext*, Response*) override { + this->Finish(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")); + } +}; + +template +class UnimplementedWriteReactor + : public experimental::ServerWriteReactor { + public: + void OnDone() override { delete this; } + void OnStarted(::grpc_impl::ServerContext*, const Request*) override { + this->Finish(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")); + } +}; + +template +class UnimplementedBidiReactor + : public experimental::ServerBidiReactor { + public: + void OnDone() override { delete this; } + void OnStarted(::grpc_impl::ServerContext*) override { + this->Finish(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")); + } +}; + +template +class CallbackUnaryHandler : public grpc::internal::MethodHandler { + public: + CallbackUnaryHandler( + std::function + func) + : func_(func) {} + + void SetMessageAllocator( + ::grpc::experimental::MessageAllocator* + allocator) { + allocator_ = allocator; + } + + void RunHandler(const HandlerParameter& param) final { + // Arena allocate a controller structure (that includes request/response) + ::grpc::g_core_codegen_interface->grpc_call_ref(param.call->call()); + auto* allocator_state = static_cast< + grpc::experimental::MessageHolder*>( + param.internal_data); + auto* controller = + new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + param.call->call(), sizeof(ServerCallbackRpcControllerImpl))) + ServerCallbackRpcControllerImpl(param.server_context, param.call, + allocator_state, + std::move(param.call_requester)); + ::grpc::Status status = param.status; + if (status.ok()) { + // Call the actual function handler and expect the user to call finish + grpc::internal::CatchingCallback(func_, param.server_context, + controller->request(), + controller->response(), controller); + } else { + // if deserialization failed, we need to fail the call + controller->Finish(status); + } + } + + void* Deserialize(grpc_call* call, grpc_byte_buffer* req, + ::grpc::Status* status, void** handler_data) final { + grpc::ByteBuffer buf; + buf.set_buffer(req); + RequestType* request = nullptr; + ::grpc::experimental::MessageHolder* + allocator_state = nullptr; + if (allocator_ != nullptr) { + allocator_state = allocator_->AllocateMessages(); + } else { + allocator_state = + new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + call, sizeof(DefaultMessageHolder))) + DefaultMessageHolder(); + } + *handler_data = allocator_state; + request = allocator_state->request(); + *status = + ::grpc::SerializationTraits::Deserialize(&buf, request); + buf.Release(); + if (status->ok()) { + return request; + } + // Clean up on deserialization failure. + allocator_state->Release(); + return nullptr; + } + + private: + std::function + func_; + grpc::experimental::MessageAllocator* allocator_ = + nullptr; + + // The implementation class of ServerCallbackRpcController is a private member + // of CallbackUnaryHandler since it is never exposed anywhere, and this allows + // it to take advantage of CallbackUnaryHandler's friendships. + class ServerCallbackRpcControllerImpl + : public experimental::ServerCallbackRpcController { + public: + void Finish(::grpc::Status s) override { + finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); }, + &finish_ops_); + if (!ctx_->sent_initial_metadata_) { + finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + finish_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + } + // The response is dropped if the status is not OK. + if (s.ok()) { + finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, + finish_ops_.SendMessagePtr(response())); + } else { + finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s); + } + finish_ops_.set_core_cq_tag(&finish_tag_); + call_.PerformOps(&finish_ops_); + } + + void SendInitialMetadata(std::function f) override { + GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); + callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); + // TODO(vjpai): Consider taking f as a move-capture if we adopt C++14 + // and if performance of this operation matters + meta_tag_.Set(call_.call(), + [this, f](bool ok) { + f(ok); + MaybeDone(); + }, + &meta_ops_); + meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + meta_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + meta_ops_.set_core_cq_tag(&meta_tag_); + call_.PerformOps(&meta_ops_); + } + + // Neither SetCancelCallback nor ClearCancelCallback should affect the + // callbacks_outstanding_ count since they are paired and both must precede + // the invocation of Finish (if they are used at all) + void SetCancelCallback(std::function callback) override { + ctx_->SetCancelCallback(std::move(callback)); + } + + void ClearCancelCallback() override { ctx_->ClearCancelCallback(); } + + grpc::experimental::RpcAllocatorState* GetRpcAllocatorState() override { + return allocator_state_; + } + + private: + friend class CallbackUnaryHandler; + + ServerCallbackRpcControllerImpl( + ServerContext* ctx, ::grpc::internal::Call* call, + ::grpc::experimental::MessageHolder* + allocator_state, + std::function call_requester) + : ctx_(ctx), + call_(*call), + allocator_state_(allocator_state), + call_requester_(std::move(call_requester)) { + ctx_->BeginCompletionOp(call, [this](bool) { MaybeDone(); }, nullptr); + } + + const RequestType* request() { return allocator_state_->request(); } + ResponseType* response() { return allocator_state_->response(); } + + void MaybeDone() { + if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( + 1, std::memory_order_acq_rel) == 1)) { + grpc_call* call = call_.call(); + auto call_requester = std::move(call_requester_); + allocator_state_->Release(); + this->~ServerCallbackRpcControllerImpl(); // explicitly call destructor + ::grpc::g_core_codegen_interface->grpc_call_unref(call); + call_requester(); + } + } + + grpc::internal::CallOpSet + meta_ops_; + grpc::internal::CallbackWithSuccessTag meta_tag_; + grpc::internal::CallOpSet + finish_ops_; + grpc::internal::CallbackWithSuccessTag finish_tag_; + + ::grpc_impl::ServerContext* ctx_; + grpc::internal::Call call_; + grpc::experimental::MessageHolder* const + allocator_state_; + std::function call_requester_; + std::atomic callbacks_outstanding_{ + 2}; // reserve for Finish and CompletionOp + }; +}; + +template +class CallbackClientStreamingHandler : public grpc::internal::MethodHandler { + public: + CallbackClientStreamingHandler( + std::function< + experimental::ServerReadReactor*()> + func) + : func_(std::move(func)) {} + void RunHandler(const HandlerParameter& param) final { + // Arena allocate a reader structure (that includes response) + ::grpc::g_core_codegen_interface->grpc_call_ref(param.call->call()); + + experimental::ServerReadReactor* reactor = + param.status.ok() + ? ::grpc::internal::CatchingReactorCreator< + experimental::ServerReadReactor>( + func_) + : nullptr; + + if (reactor == nullptr) { + // if deserialization or reactor creator failed, we need to fail the call + reactor = new UnimplementedReadReactor; + } + + auto* reader = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + param.call->call(), sizeof(ServerCallbackReaderImpl))) + ServerCallbackReaderImpl(param.server_context, param.call, + std::move(param.call_requester), reactor); + + 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(); + } + + private: + std::function*()> + func_; + + class ServerCallbackReaderImpl + : public experimental::ServerCallbackReader { + public: + void Finish(::grpc::Status s) override { + finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); }, + &finish_ops_); + if (!ctx_->sent_initial_metadata_) { + finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + finish_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + } + // The response is dropped if the status is not OK. + if (s.ok()) { + finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, + finish_ops_.SendMessagePtr(&resp_)); + } else { + finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s); + } + finish_ops_.set_core_cq_tag(&finish_tag_); + call_.PerformOps(&finish_ops_); + } + + void SendInitialMetadata() override { + GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); + callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); + meta_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnSendInitialMetadataDone(ok); + MaybeDone(); + }, + &meta_ops_); + meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + meta_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + meta_ops_.set_core_cq_tag(&meta_tag_); + call_.PerformOps(&meta_ops_); + } + + void Read(RequestType* req) override { + callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); + read_ops_.RecvMessage(req); + call_.PerformOps(&read_ops_); + } + + private: + friend class CallbackClientStreamingHandler; + + ServerCallbackReaderImpl( + ::grpc_impl::ServerContext* ctx, grpc::internal::Call* call, + std::function call_requester, + experimental::ServerReadReactor* reactor) + : ctx_(ctx), + call_(*call), + call_requester_(std::move(call_requester)), + reactor_(reactor) { + ctx_->BeginCompletionOp(call, [this](bool) { MaybeDone(); }, reactor); + read_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnReadDone(ok); + MaybeDone(); + }, + &read_ops_); + read_ops_.set_core_cq_tag(&read_tag_); + } + + ~ServerCallbackReaderImpl() {} + + ResponseType* response() { return &resp_; } + + void MaybeDone() { + if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( + 1, std::memory_order_acq_rel) == 1)) { + reactor_->OnDone(); + grpc_call* call = call_.call(); + auto call_requester = std::move(call_requester_); + this->~ServerCallbackReaderImpl(); // explicitly call destructor + ::grpc::g_core_codegen_interface->grpc_call_unref(call); + call_requester(); + } + } + + grpc::internal::CallOpSet + meta_ops_; + grpc::internal::CallbackWithSuccessTag meta_tag_; + grpc::internal::CallOpSet + finish_ops_; + grpc::internal::CallbackWithSuccessTag finish_tag_; + grpc::internal::CallOpSet> + read_ops_; + grpc::internal::CallbackWithSuccessTag read_tag_; + + ::grpc_impl::ServerContext* ctx_; + grpc::internal::Call call_; + ResponseType resp_; + std::function call_requester_; + experimental::ServerReadReactor* reactor_; + std::atomic callbacks_outstanding_{ + 3}; // reserve for OnStarted, Finish, and CompletionOp + }; +}; + +template +class CallbackServerStreamingHandler : public grpc::internal::MethodHandler { + public: + CallbackServerStreamingHandler( + std::function< + experimental::ServerWriteReactor*()> + func) + : func_(std::move(func)) {} + void RunHandler(const HandlerParameter& param) final { + // Arena allocate a writer structure + ::grpc::g_core_codegen_interface->grpc_call_ref(param.call->call()); + + experimental::ServerWriteReactor* reactor = + param.status.ok() + ? ::grpc::internal::CatchingReactorCreator< + experimental::ServerWriteReactor>( + func_) + : nullptr; + + if (reactor == nullptr) { + // if deserialization or reactor creator failed, we need to fail the call + reactor = new UnimplementedWriteReactor; + } + + auto* writer = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + param.call->call(), sizeof(ServerCallbackWriterImpl))) + ServerCallbackWriterImpl(param.server_context, param.call, + static_cast(param.request), + 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, + ::grpc::Status* status, void** handler_data) final { + ::grpc::ByteBuffer buf; + buf.set_buffer(req); + auto* request = + new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + call, sizeof(RequestType))) RequestType(); + *status = + ::grpc::SerializationTraits::Deserialize(&buf, request); + buf.Release(); + if (status->ok()) { + return request; + } + request->~RequestType(); + return nullptr; + } + + private: + std::function*()> + func_; + + class ServerCallbackWriterImpl + : public experimental::ServerCallbackWriter { + public: + void Finish(::grpc::Status s) override { + finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); }, + &finish_ops_); + finish_ops_.set_core_cq_tag(&finish_tag_); + + if (!ctx_->sent_initial_metadata_) { + finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + finish_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + } + finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s); + call_.PerformOps(&finish_ops_); + } + + void SendInitialMetadata() override { + GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); + callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); + meta_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnSendInitialMetadataDone(ok); + MaybeDone(); + }, + &meta_ops_); + meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + meta_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + meta_ops_.set_core_cq_tag(&meta_tag_); + call_.PerformOps(&meta_ops_); + } + + void Write(const ResponseType* resp, + ::grpc::WriteOptions options) override { + callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); + if (options.is_last_message()) { + options.set_buffer_hint(); + } + if (!ctx_->sent_initial_metadata_) { + write_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + write_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + } + // TODO(vjpai): don't assert + GPR_CODEGEN_ASSERT(write_ops_.SendMessagePtr(resp, options).ok()); + call_.PerformOps(&write_ops_); + } + + void WriteAndFinish(const ResponseType* resp, ::grpc::WriteOptions options, + ::grpc::Status s) override { + // This combines the write into the finish callback + // Don't send any message if the status is bad + if (s.ok()) { + // TODO(vjpai): don't assert + GPR_CODEGEN_ASSERT(finish_ops_.SendMessagePtr(resp, options).ok()); + } + Finish(std::move(s)); + } + + private: + friend class CallbackServerStreamingHandler; + + ServerCallbackWriterImpl( + ::grpc_impl::ServerContext* ctx, grpc::internal::Call* call, + const RequestType* req, std::function call_requester, + experimental::ServerWriteReactor* reactor) + : ctx_(ctx), + call_(*call), + req_(req), + call_requester_(std::move(call_requester)), + reactor_(reactor) { + ctx_->BeginCompletionOp(call, [this](bool) { MaybeDone(); }, reactor); + write_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnWriteDone(ok); + MaybeDone(); + }, + &write_ops_); + write_ops_.set_core_cq_tag(&write_tag_); + } + ~ServerCallbackWriterImpl() { req_->~RequestType(); } + + const RequestType* request() { return req_; } + + void MaybeDone() { + if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( + 1, std::memory_order_acq_rel) == 1)) { + reactor_->OnDone(); + grpc_call* call = call_.call(); + auto call_requester = std::move(call_requester_); + this->~ServerCallbackWriterImpl(); // explicitly call destructor + ::grpc::g_core_codegen_interface->grpc_call_unref(call); + call_requester(); + } + } + + grpc::internal::CallOpSet + meta_ops_; + grpc::internal::CallbackWithSuccessTag meta_tag_; + grpc::internal::CallOpSet + finish_ops_; + grpc::internal::CallbackWithSuccessTag finish_tag_; + grpc::internal::CallOpSet + write_ops_; + grpc::internal::CallbackWithSuccessTag write_tag_; + + ::grpc_impl::ServerContext* ctx_; + grpc::internal::Call call_; + const RequestType* req_; + std::function call_requester_; + experimental::ServerWriteReactor* reactor_; + std::atomic callbacks_outstanding_{ + 3}; // reserve for OnStarted, Finish, and CompletionOp + }; +}; + +template +class CallbackBidiHandler : public grpc::internal::MethodHandler { + public: + CallbackBidiHandler( + std::function< + experimental::ServerBidiReactor*()> + func) + : func_(std::move(func)) {} + void RunHandler(const HandlerParameter& param) final { + ::grpc::g_core_codegen_interface->grpc_call_ref(param.call->call()); + + experimental::ServerBidiReactor* reactor = + param.status.ok() + ? ::grpc::internal::CatchingReactorCreator< + experimental::ServerBidiReactor>( + func_) + : nullptr; + + if (reactor == nullptr) { + // if deserialization or reactor creator failed, we need to fail the call + reactor = new UnimplementedBidiReactor; + } + + auto* stream = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + param.call->call(), sizeof(ServerCallbackReaderWriterImpl))) + ServerCallbackReaderWriterImpl(param.server_context, param.call, + std::move(param.call_requester), + reactor); + + stream->BindReactor(reactor); + reactor->OnStarted(param.server_context); + // The earliest that OnCancel can be called is after OnStarted is done. + reactor->MaybeCallOnCancel(); + stream->MaybeDone(); + } + + private: + std::function*()> + func_; + + class ServerCallbackReaderWriterImpl + : public experimental::ServerCallbackReaderWriter { + public: + void Finish(::grpc::Status s) override { + finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); }, + &finish_ops_); + finish_ops_.set_core_cq_tag(&finish_tag_); + + if (!ctx_->sent_initial_metadata_) { + finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + finish_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + } + finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s); + call_.PerformOps(&finish_ops_); + } + + void SendInitialMetadata() override { + GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); + callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); + meta_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnSendInitialMetadataDone(ok); + MaybeDone(); + }, + &meta_ops_); + meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + meta_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + meta_ops_.set_core_cq_tag(&meta_tag_); + call_.PerformOps(&meta_ops_); + } + + void Write(const ResponseType* resp, + ::grpc::WriteOptions options) override { + callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); + if (options.is_last_message()) { + options.set_buffer_hint(); + } + if (!ctx_->sent_initial_metadata_) { + write_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + write_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + } + // TODO(vjpai): don't assert + GPR_CODEGEN_ASSERT(write_ops_.SendMessagePtr(resp, options).ok()); + call_.PerformOps(&write_ops_); + } + + void WriteAndFinish(const ResponseType* resp, ::grpc::WriteOptions options, + ::grpc::Status s) override { + // Don't send any message if the status is bad + if (s.ok()) { + // TODO(vjpai): don't assert + GPR_CODEGEN_ASSERT(finish_ops_.SendMessagePtr(resp, options).ok()); + } + Finish(std::move(s)); + } + + void Read(RequestType* req) override { + callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); + read_ops_.RecvMessage(req); + call_.PerformOps(&read_ops_); + } + + private: + friend class CallbackBidiHandler; + + ServerCallbackReaderWriterImpl( + ::grpc_impl::ServerContext* ctx, grpc::internal::Call* call, + std::function call_requester, + experimental::ServerBidiReactor* reactor) + : ctx_(ctx), + call_(*call), + call_requester_(std::move(call_requester)), + reactor_(reactor) { + ctx_->BeginCompletionOp(call, [this](bool) { MaybeDone(); }, reactor); + write_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnWriteDone(ok); + MaybeDone(); + }, + &write_ops_); + write_ops_.set_core_cq_tag(&write_tag_); + read_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnReadDone(ok); + MaybeDone(); + }, + &read_ops_); + read_ops_.set_core_cq_tag(&read_tag_); + } + ~ServerCallbackReaderWriterImpl() {} + + void MaybeDone() { + if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( + 1, std::memory_order_acq_rel) == 1)) { + reactor_->OnDone(); + grpc_call* call = call_.call(); + auto call_requester = std::move(call_requester_); + this->~ServerCallbackReaderWriterImpl(); // explicitly call destructor + ::grpc::g_core_codegen_interface->grpc_call_unref(call); + call_requester(); + } + } + + grpc::internal::CallOpSet + meta_ops_; + grpc::internal::CallbackWithSuccessTag meta_tag_; + grpc::internal::CallOpSet + finish_ops_; + grpc::internal::CallbackWithSuccessTag finish_tag_; + grpc::internal::CallOpSet + write_ops_; + grpc::internal::CallbackWithSuccessTag write_tag_; + grpc::internal::CallOpSet> + read_ops_; + grpc::internal::CallbackWithSuccessTag read_tag_; + + ::grpc_impl::ServerContext* ctx_; + grpc::internal::Call call_; + std::function call_requester_; + experimental::ServerBidiReactor* reactor_; + std::atomic callbacks_outstanding_{ + 3}; // reserve for OnStarted, Finish, and CompletionOp + }; +}; + +} // namespace internal + +} // namespace grpc_impl + +#endif // GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_IMPL_H diff --git a/include/grpcpp/impl/codegen/server_context_impl.h b/include/grpcpp/impl/codegen/server_context_impl.h index 9497735eacc..72137f153b1 100644 --- a/include/grpcpp/impl/codegen/server_context_impl.h +++ b/include/grpcpp/impl/codegen/server_context_impl.h @@ -44,10 +44,6 @@ namespace grpc_impl { class ClientContext; class CompletionQueue; class Server; -} // namespace grpc_impl -namespace grpc { -class GenericServerContext; -class ServerInterface; template class ServerAsyncReader; template @@ -62,14 +58,6 @@ template class ServerWriter; namespace internal { -template -class ServerReaderWriterBody; -template -class RpcMethodHandler; -template -class ClientStreamingHandler; -template -class ServerStreamingHandler; template class BidiStreamingHandler; template @@ -80,12 +68,28 @@ template class CallbackServerStreamingHandler; template class CallbackBidiHandler; +template +class ServerReaderWriterBody; +class ServerReactor; +} // namespace internal + +} // namespace grpc_impl +namespace grpc { +class GenericServerContext; +class ServerInterface; + +namespace internal { +template +class ClientStreamingHandler; +template +class ServerStreamingHandler; +template +class RpcMethodHandler; template class TemplatedBidiStreamingHandler; template class ErrorMethodHandler; class Call; -class ServerReactor; } // namespace internal class ServerInterface; @@ -275,19 +279,19 @@ class ServerContext { friend class ::grpc::ServerInterface; friend class ::grpc_impl::Server; template - friend class ::grpc::ServerAsyncReader; + friend class ::grpc_impl::ServerAsyncReader; template - friend class ::grpc::ServerAsyncWriter; + friend class ::grpc_impl::ServerAsyncWriter; template - friend class ::grpc::ServerAsyncResponseWriter; + friend class ::grpc_impl::ServerAsyncResponseWriter; template - friend class ::grpc::ServerAsyncReaderWriter; + friend class ::grpc_impl::ServerAsyncReaderWriter; template - friend class ::grpc::ServerReader; + friend class ::grpc_impl::ServerReader; template - friend class ::grpc::ServerWriter; + friend class ::grpc_impl::ServerWriter; template - friend class ::grpc::internal::ServerReaderWriterBody; + friend class ::grpc_impl::internal::ServerReaderWriterBody; template friend class ::grpc::internal::RpcMethodHandler; template @@ -297,13 +301,13 @@ class ServerContext { template friend class ::grpc::internal::TemplatedBidiStreamingHandler; template - friend class ::grpc::internal::CallbackUnaryHandler; + friend class ::grpc_impl::internal::CallbackUnaryHandler; template - friend class ::grpc::internal::CallbackClientStreamingHandler; + friend class ::grpc_impl::internal::CallbackClientStreamingHandler; template - friend class ::grpc::internal::CallbackServerStreamingHandler; + friend class ::grpc_impl::internal::CallbackServerStreamingHandler; template - friend class ::grpc::internal::CallbackBidiHandler; + friend class ::grpc_impl::internal::CallbackBidiHandler; template <::grpc::StatusCode code> friend class ::grpc::internal::ErrorMethodHandler; friend class ::grpc_impl::ClientContext; @@ -317,7 +321,7 @@ class ServerContext { void BeginCompletionOp(::grpc::internal::Call* call, std::function callback, - ::grpc::internal::ServerReactor* reactor); + ::grpc_impl::internal::ServerReactor* reactor); /// Return the tag queued by BeginCompletionOp() ::grpc::internal::CompletionQueueTag* GetCompletionOpTag(); diff --git a/include/grpcpp/impl/codegen/service_type.h b/include/grpcpp/impl/codegen/service_type.h index 4109ee1b504..f13dfb99fa0 100644 --- a/include/grpcpp/impl/codegen/service_type.h +++ b/include/grpcpp/impl/codegen/service_type.h @@ -149,8 +149,9 @@ class Service { void RequestAsyncUnary(int index, ::grpc_impl::ServerContext* context, Message* request, internal::ServerAsyncStreamingInterface* stream, - CompletionQueue* call_cq, - ServerCompletionQueue* notification_cq, void* tag) { + ::grpc_impl::CompletionQueue* call_cq, + ::grpc_impl::ServerCompletionQueue* notification_cq, + void* tag) { // Typecast the index to size_t for indexing into a vector // while preserving the API that existed before a compiler // warning was first seen (grpc/grpc#11664) @@ -160,8 +161,9 @@ class Service { } void RequestAsyncClientStreaming( int index, ::grpc_impl::ServerContext* context, - internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, - ServerCompletionQueue* notification_cq, void* tag) { + internal::ServerAsyncStreamingInterface* stream, + ::grpc_impl::CompletionQueue* call_cq, + ::grpc_impl::ServerCompletionQueue* notification_cq, void* tag) { size_t idx = static_cast(index); server_->RequestAsyncCall(methods_[idx].get(), context, stream, call_cq, notification_cq, tag); @@ -169,16 +171,18 @@ class Service { template void RequestAsyncServerStreaming( int index, ::grpc_impl::ServerContext* context, Message* request, - internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, - ServerCompletionQueue* notification_cq, void* tag) { + internal::ServerAsyncStreamingInterface* stream, + ::grpc_impl::CompletionQueue* call_cq, + ::grpc_impl::ServerCompletionQueue* notification_cq, void* tag) { size_t idx = static_cast(index); server_->RequestAsyncCall(methods_[idx].get(), context, stream, call_cq, notification_cq, tag, request); } void RequestAsyncBidiStreaming( int index, ::grpc_impl::ServerContext* context, - internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, - ServerCompletionQueue* notification_cq, void* tag) { + internal::ServerAsyncStreamingInterface* stream, + ::grpc_impl::CompletionQueue* call_cq, + ::grpc_impl::ServerCompletionQueue* notification_cq, void* tag) { size_t idx = static_cast(index); server_->RequestAsyncCall(methods_[idx].get(), context, stream, call_cq, notification_cq, tag); diff --git a/include/grpcpp/impl/codegen/sync_stream.h b/include/grpcpp/impl/codegen/sync_stream.h index 9d030a13a71..cd447d7c5a5 100644 --- a/include/grpcpp/impl/codegen/sync_stream.h +++ b/include/grpcpp/impl/codegen/sync_stream.h @@ -19,918 +19,42 @@ #ifndef GRPCPP_IMPL_CODEGEN_SYNC_STREAM_H #define GRPCPP_IMPL_CODEGEN_SYNC_STREAM_H -#include -#include -#include -#include -#include -#include -#include -#include +#include namespace grpc { - -namespace internal { -/// Common interface for all synchronous client side streaming. -class ClientStreamingInterface { - public: - virtual ~ClientStreamingInterface() {} - - /// Block waiting until the stream finishes and a final status of the call is - /// available. - /// - /// It is appropriate to call this method when both: - /// * the calling code (client-side) has no more message to send - /// (this can be declared implicitly by calling this method, or - /// explicitly through an earlier call to WritesDone method of the - /// class in use, e.g. \a ClientWriterInterface::WritesDone or - /// \a ClientReaderWriterInterface::WritesDone). - /// * there are no more messages to be received from the server (which can - /// be known implicitly, or explicitly from an earlier call to \a - /// ReaderInterface::Read that returned "false"). - /// - /// This function will return either: - /// - when all incoming messages have been read and the server has - /// returned status. - /// - when the server has returned a non-OK status. - /// - OR when the call failed for some reason and the library generated a - /// status. - /// - /// Return values: - /// - \a Status contains the status code, message and details for the call - /// - the \a ClientContext associated with this call is updated with - /// possible trailing metadata sent from the server. - virtual Status Finish() = 0; -}; - -/// Common interface for all synchronous server side streaming. -class ServerStreamingInterface { - public: - virtual ~ServerStreamingInterface() {} - - /// Block to send initial metadata to client. - /// This call is optional, but if it is used, it cannot be used concurrently - /// with or after the \a Finish method. - /// - /// The initial metadata that will be sent to the client will be - /// taken from the \a ServerContext associated with the call. - virtual void SendInitialMetadata() = 0; -}; - -/// An interface that yields a sequence of messages of type \a R. template -class ReaderInterface { - public: - virtual ~ReaderInterface() {} - - /// Get an upper bound on the next message size available for reading on this - /// stream. - virtual bool NextMessageSize(uint32_t* sz) = 0; - - /// Block to read a message and parse to \a msg. Returns \a true on success. - /// This is thread-safe with respect to \a Write or \WritesDone methods on - /// the same stream. It should not be called concurrently with another \a - /// Read on the same stream as the order of delivery will not be defined. - /// - /// \param[out] msg The read message. - /// - /// \return \a false when there will be no more incoming messages, either - /// because the other side has called \a WritesDone() or the stream has failed - /// (or been cancelled). - virtual bool Read(R* msg) = 0; -}; - -/// An interface that can be fed a sequence of messages of type \a W. -template -class WriterInterface { - public: - virtual ~WriterInterface() {} - - /// Block to write \a msg to the stream with WriteOptions \a options. - /// This is thread-safe with respect to \a ReaderInterface::Read - /// - /// \param msg The message to be written to the stream. - /// \param options The WriteOptions affecting the write operation. - /// - /// \return \a true on success, \a false when the stream has been closed. - virtual bool Write(const W& msg, WriteOptions options) = 0; - - /// Block to write \a msg to the stream with default write options. - /// This is thread-safe with respect to \a ReaderInterface::Read - /// - /// \param msg The message to be written to the stream. - /// - /// \return \a true on success, \a false when the stream has been closed. - inline bool Write(const W& msg) { return Write(msg, WriteOptions()); } - - /// Write \a msg and coalesce it with the writing of trailing metadata, using - /// WriteOptions \a options. - /// - /// For client, WriteLast is equivalent of performing Write and WritesDone in - /// a single step. \a msg and trailing metadata are coalesced and sent on wire - /// by calling this function. For server, WriteLast buffers the \a msg. - /// The writing of \a msg is held until the service handler returns, - /// where \a msg and trailing metadata are coalesced and sent on wire. - /// Note that WriteLast can only buffer \a msg up to the flow control window - /// size. If \a msg size is larger than the window size, it will be sent on - /// wire without buffering. - /// - /// \param[in] msg The message to be written to the stream. - /// \param[in] options The WriteOptions to be used to write this message. - void WriteLast(const W& msg, WriteOptions options) { - Write(msg, options.set_last_message()); - } -}; - -} // namespace internal +using ClientReaderInterface = ::grpc_impl::ClientReaderInterface; -/// Client-side interface for streaming reads of message of type \a R. template -class ClientReaderInterface : public internal::ClientStreamingInterface, - public internal::ReaderInterface { - public: - /// Block to wait for initial metadata from server. The received metadata - /// can only be accessed after this call returns. Should only be called before - /// the first read. Calling this method is optional, and if it is not called - /// the metadata will be available in ClientContext after the first read. - virtual void WaitForInitialMetadata() = 0; -}; - -namespace internal { -template -class ClientReaderFactory { - public: - template - static ClientReader* Create(ChannelInterface* channel, - const ::grpc::internal::RpcMethod& method, - ::grpc_impl::ClientContext* context, - const W& request) { - return new ClientReader(channel, method, context, request); - } -}; -} // namespace internal - -/// Synchronous (blocking) client-side API for doing server-streaming RPCs, -/// where the stream of messages coming from the server has messages -/// of type \a R. -template -class ClientReader final : public ClientReaderInterface { - public: - /// See the \a ClientStreamingInterface.WaitForInitialMetadata method for - /// semantics. - /// - // Side effect: - /// Once complete, the initial metadata read from - /// the server will be accessible through the \a ClientContext used to - /// construct this object. - void WaitForInitialMetadata() override { - GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); - - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> - ops; - ops.RecvInitialMetadata(context_); - call_.PerformOps(&ops); - cq_.Pluck(&ops); /// status ignored - } - - bool NextMessageSize(uint32_t* sz) override { - *sz = call_.max_receive_message_size(); - return true; - } - - /// See the \a ReaderInterface.Read method for semantics. - /// Side effect: - /// This also receives initial metadata from the server, if not - /// already received (if initial metadata is received, it can be then - /// accessed through the \a ClientContext associated with this call). - bool Read(R* msg) override { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpRecvMessage> - ops; - if (!context_->initial_metadata_received_) { - ops.RecvInitialMetadata(context_); - } - ops.RecvMessage(msg); - call_.PerformOps(&ops); - return cq_.Pluck(&ops) && ops.got_message; - } - - /// See the \a ClientStreamingInterface.Finish method for semantics. - /// - /// Side effect: - /// The \a ClientContext associated with this call is updated with - /// possible metadata received from the server. - Status Finish() override { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpClientRecvStatus> ops; - Status status; - ops.ClientRecvStatus(context_, &status); - call_.PerformOps(&ops); - GPR_CODEGEN_ASSERT(cq_.Pluck(&ops)); - return status; - } - - private: - friend class internal::ClientReaderFactory; - ::grpc_impl::ClientContext* context_; - ::grpc_impl::CompletionQueue cq_; - ::grpc::internal::Call call_; - - /// Block to create a stream and write the initial metadata and \a request - /// out. Note that \a context will be used to fill in custom initial - /// metadata used to send to the server when starting the call. - template - ClientReader(::grpc::ChannelInterface* channel, - const ::grpc::internal::RpcMethod& method, - ::grpc_impl::ClientContext* context, const W& request) - : context_(context), - cq_(grpc_completion_queue_attributes{ - GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING, - nullptr}), // Pluckable cq - call_(channel->CreateCall(method, context, &cq_)) { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpClientSendClose> - ops; - ops.SendInitialMetadata(&context->send_initial_metadata_, - context->initial_metadata_flags()); - // TODO(ctiller): don't assert - GPR_CODEGEN_ASSERT(ops.SendMessagePtr(&request).ok()); - ops.ClientSendClose(); - call_.PerformOps(&ops); - cq_.Pluck(&ops); - } -}; - -/// Client-side interface for streaming writes of message type \a W. +using ClientReader = ::grpc_impl::ClientReader; template -class ClientWriterInterface : public internal::ClientStreamingInterface, - public internal::WriterInterface { - public: - /// Half close writing from the client. (signal that the stream of messages - /// coming from the client is complete). - /// Blocks until currently-pending writes are completed. - /// Thread safe with respect to \a ReaderInterface::Read operations only - /// - /// \return Whether the writes were successful. - virtual bool WritesDone() = 0; -}; - -namespace internal { +using ClientWriterInterface = ::grpc_impl::ClientWriterInterface; template -class ClientWriterFactory { - public: - template - static ClientWriter* Create(::grpc::ChannelInterface* channel, - const ::grpc::internal::RpcMethod& method, - ::grpc_impl::ClientContext* context, - R* response) { - return new ClientWriter(channel, method, context, response); - } -}; -} // namespace internal - -/// Synchronous (blocking) client-side API for doing client-streaming RPCs, -/// where the outgoing message stream coming from the client has messages of -/// type \a W. -template -class ClientWriter : public ClientWriterInterface { - public: - /// See the \a ClientStreamingInterface.WaitForInitialMetadata method for - /// semantics. - /// - // Side effect: - /// Once complete, the initial metadata read from the server will be - /// accessible through the \a ClientContext used to construct this object. - void WaitForInitialMetadata() { - GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); - - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> - ops; - ops.RecvInitialMetadata(context_); - call_.PerformOps(&ops); - cq_.Pluck(&ops); // status ignored - } - - /// See the WriterInterface.Write(const W& msg, WriteOptions options) method - /// for semantics. - /// - /// Side effect: - /// Also sends initial metadata if not already sent (using the - /// \a ClientContext associated with this call). - using ::grpc::internal::WriterInterface::Write; - bool Write(const W& msg, WriteOptions options) override { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpClientSendClose> - ops; - - if (options.is_last_message()) { - options.set_buffer_hint(); - ops.ClientSendClose(); - } - if (context_->initial_metadata_corked_) { - ops.SendInitialMetadata(&context_->send_initial_metadata_, - context_->initial_metadata_flags()); - context_->set_initial_metadata_corked(false); - } - if (!ops.SendMessagePtr(&msg, options).ok()) { - return false; - } - - call_.PerformOps(&ops); - return cq_.Pluck(&ops); - } - - bool WritesDone() override { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpClientSendClose> ops; - ops.ClientSendClose(); - call_.PerformOps(&ops); - return cq_.Pluck(&ops); - } - - /// See the ClientStreamingInterface.Finish method for semantics. - /// Side effects: - /// - Also receives initial metadata if not already received. - /// - Attempts to fill in the \a response parameter passed - /// to the constructor of this instance with the response - /// message from the server. - Status Finish() override { - Status status; - if (!context_->initial_metadata_received_) { - finish_ops_.RecvInitialMetadata(context_); - } - finish_ops_.ClientRecvStatus(context_, &status); - call_.PerformOps(&finish_ops_); - GPR_CODEGEN_ASSERT(cq_.Pluck(&finish_ops_)); - return status; - } - - private: - friend class internal::ClientWriterFactory; - - /// Block to create a stream (i.e. send request headers and other initial - /// metadata to the server). Note that \a context will be used to fill - /// in custom initial metadata. \a response will be filled in with the - /// single expected response message from the server upon a successful - /// call to the \a Finish method of this instance. - template - ClientWriter(ChannelInterface* channel, - const ::grpc::internal::RpcMethod& method, - ::grpc_impl::ClientContext* context, R* response) - : context_(context), - cq_(grpc_completion_queue_attributes{ - GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING, - nullptr}), // Pluckable cq - call_(channel->CreateCall(method, context, &cq_)) { - finish_ops_.RecvMessage(response); - finish_ops_.AllowNoMessage(); - - if (!context_->initial_metadata_corked_) { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> - ops; - ops.SendInitialMetadata(&context->send_initial_metadata_, - context->initial_metadata_flags()); - call_.PerformOps(&ops); - cq_.Pluck(&ops); - } - } - - ::grpc_impl::ClientContext* context_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpGenericRecvMessage, - ::grpc::internal::CallOpClientRecvStatus> - finish_ops_; - ::grpc_impl::CompletionQueue cq_; - ::grpc::internal::Call call_; -}; - -/// Client-side interface for bi-directional streaming with -/// client-to-server stream messages of type \a W and -/// server-to-client stream messages of type \a R. -template -class ClientReaderWriterInterface : public internal::ClientStreamingInterface, - public internal::WriterInterface, - public internal::ReaderInterface { - public: - /// Block to wait for initial metadata from server. The received metadata - /// can only be accessed after this call returns. Should only be called before - /// the first read. Calling this method is optional, and if it is not called - /// the metadata will be available in ClientContext after the first read. - virtual void WaitForInitialMetadata() = 0; - - /// Half close writing from the client. (signal that the stream of messages - /// coming from the clinet is complete). - /// Blocks until currently-pending writes are completed. - /// Thread-safe with respect to \a ReaderInterface::Read - /// - /// \return Whether the writes were successful. - virtual bool WritesDone() = 0; -}; - -namespace internal { +using ClientWriter = ::grpc_impl::ClientWriter; template -class ClientReaderWriterFactory { - public: - static ClientReaderWriter* Create( - ::grpc::ChannelInterface* channel, - const ::grpc::internal::RpcMethod& method, - ::grpc_impl::ClientContext* context) { - return new ClientReaderWriter(channel, method, context); - } -}; -} // namespace internal - -/// Synchronous (blocking) client-side API for bi-directional streaming RPCs, -/// where the outgoing message stream coming from the client has messages of -/// type \a W, and the incoming messages stream coming from the server has -/// messages of type \a R. +using ClientReaderWriterInterface = + ::grpc_impl::ClientReaderWriterInterface; template -class ClientReaderWriter final : public ClientReaderWriterInterface { - public: - /// Block waiting to read initial metadata from the server. - /// This call is optional, but if it is used, it cannot be used concurrently - /// with or after the \a Finish method. - /// - /// Once complete, the initial metadata read from the server will be - /// accessible through the \a ClientContext used to construct this object. - void WaitForInitialMetadata() override { - GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); - - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> - ops; - ops.RecvInitialMetadata(context_); - call_.PerformOps(&ops); - cq_.Pluck(&ops); // status ignored - } - - bool NextMessageSize(uint32_t* sz) override { - *sz = call_.max_receive_message_size(); - return true; - } - - /// See the \a ReaderInterface.Read method for semantics. - /// Side effect: - /// Also receives initial metadata if not already received (updates the \a - /// ClientContext associated with this call in that case). - bool Read(R* msg) override { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpRecvMessage> - ops; - if (!context_->initial_metadata_received_) { - ops.RecvInitialMetadata(context_); - } - ops.RecvMessage(msg); - call_.PerformOps(&ops); - return cq_.Pluck(&ops) && ops.got_message; - } - - /// See the \a WriterInterface.Write method for semantics. - /// - /// Side effect: - /// Also sends initial metadata if not already sent (using the - /// \a ClientContext associated with this call to fill in values). - using ::grpc::internal::WriterInterface::Write; - bool Write(const W& msg, WriteOptions options) override { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpClientSendClose> - ops; - - if (options.is_last_message()) { - options.set_buffer_hint(); - ops.ClientSendClose(); - } - if (context_->initial_metadata_corked_) { - ops.SendInitialMetadata(&context_->send_initial_metadata_, - context_->initial_metadata_flags()); - context_->set_initial_metadata_corked(false); - } - if (!ops.SendMessagePtr(&msg, options).ok()) { - return false; - } - - call_.PerformOps(&ops); - return cq_.Pluck(&ops); - } - - bool WritesDone() override { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpClientSendClose> ops; - ops.ClientSendClose(); - call_.PerformOps(&ops); - return cq_.Pluck(&ops); - } - - /// See the ClientStreamingInterface.Finish method for semantics. - /// - /// Side effect: - /// - the \a ClientContext associated with this call is updated with - /// possible trailing metadata sent from the server. - Status Finish() override { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpClientRecvStatus> - ops; - if (!context_->initial_metadata_received_) { - ops.RecvInitialMetadata(context_); - } - Status status; - ops.ClientRecvStatus(context_, &status); - call_.PerformOps(&ops); - GPR_CODEGEN_ASSERT(cq_.Pluck(&ops)); - return status; - } - - private: - friend class internal::ClientReaderWriterFactory; - - ::grpc_impl::ClientContext* context_; - ::grpc_impl::CompletionQueue cq_; - ::grpc::internal::Call call_; - - /// Block to create a stream and write the initial metadata and \a request - /// out. Note that \a context will be used to fill in custom initial metadata - /// used to send to the server when starting the call. - ClientReaderWriter(::grpc::ChannelInterface* channel, - const ::grpc::internal::RpcMethod& method, - ::grpc_impl::ClientContext* context) - : context_(context), - cq_(grpc_completion_queue_attributes{ - GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING, - nullptr}), // Pluckable cq - call_(channel->CreateCall(method, context, &cq_)) { - if (!context_->initial_metadata_corked_) { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> - ops; - ops.SendInitialMetadata(&context->send_initial_metadata_, - context->initial_metadata_flags()); - call_.PerformOps(&ops); - cq_.Pluck(&ops); - } - } -}; - -/// Server-side interface for streaming reads of message of type \a R. +using ClientReaderWriter = ::grpc_impl::ClientReaderWriter; template -class ServerReaderInterface : public internal::ServerStreamingInterface, - public internal::ReaderInterface {}; - -/// Synchronous (blocking) server-side API for doing client-streaming RPCs, -/// where the incoming message stream coming from the client has messages of -/// type \a R. +using ServerReaderInterface = ::grpc_impl::ServerReaderInterface; template -class ServerReader final : public ServerReaderInterface { - public: - /// See the \a ServerStreamingInterface.SendInitialMetadata method - /// for semantics. Note that initial metadata will be affected by the - /// \a ServerContext associated with this call. - void SendInitialMetadata() override { - GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); - - internal::CallOpSet ops; - ops.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - ops.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - call_->PerformOps(&ops); - call_->cq()->Pluck(&ops); - } - - bool NextMessageSize(uint32_t* sz) override { - *sz = call_->max_receive_message_size(); - return true; - } - - bool Read(R* msg) override { - internal::CallOpSet> ops; - ops.RecvMessage(msg); - call_->PerformOps(&ops); - return call_->cq()->Pluck(&ops) && ops.got_message; - } - - private: - internal::Call* const call_; - ::grpc_impl::ServerContext* const ctx_; - - template - friend class internal::ClientStreamingHandler; - - ServerReader(internal::Call* call, ::grpc_impl::ServerContext* ctx) - : call_(call), ctx_(ctx) {} -}; - -/// Server-side interface for streaming writes of message of type \a W. +using ServerReader = ::grpc_impl::ServerReader; template -class ServerWriterInterface : public internal::ServerStreamingInterface, - public internal::WriterInterface {}; - -/// Synchronous (blocking) server-side API for doing for doing a -/// server-streaming RPCs, where the outgoing message stream coming from the -/// server has messages of type \a W. +using ServerWriterInterface = ::grpc_impl::ServerWriterInterface; template -class ServerWriter final : public ServerWriterInterface { - public: - /// See the \a ServerStreamingInterface.SendInitialMetadata method - /// for semantics. - /// Note that initial metadata will be affected by the - /// \a ServerContext associated with this call. - void SendInitialMetadata() override { - GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); - - internal::CallOpSet ops; - ops.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - ops.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - call_->PerformOps(&ops); - call_->cq()->Pluck(&ops); - } - - /// See the \a WriterInterface.Write method for semantics. - /// - /// Side effect: - /// Also sends initial metadata if not already sent (using the - /// \a ClientContext associated with this call to fill in values). - using internal::WriterInterface::Write; - bool Write(const W& msg, WriteOptions options) override { - if (options.is_last_message()) { - options.set_buffer_hint(); - } - - if (!ctx_->pending_ops_.SendMessagePtr(&msg, options).ok()) { - return false; - } - if (!ctx_->sent_initial_metadata_) { - ctx_->pending_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - ctx_->pending_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - } - call_->PerformOps(&ctx_->pending_ops_); - // if this is the last message we defer the pluck until AFTER we start - // the trailing md op. This prevents hangs. See - // https://github.com/grpc/grpc/issues/11546 - if (options.is_last_message()) { - ctx_->has_pending_ops_ = true; - return true; - } - ctx_->has_pending_ops_ = false; - return call_->cq()->Pluck(&ctx_->pending_ops_); - } - - private: - internal::Call* const call_; - ::grpc_impl::ServerContext* const ctx_; - - template - friend class internal::ServerStreamingHandler; - - ServerWriter(internal::Call* call, ::grpc_impl::ServerContext* ctx) - : call_(call), ctx_(ctx) {} -}; - -/// Server-side interface for bi-directional streaming. +using ServerWriter = ::grpc_impl::ServerWriter; template -class ServerReaderWriterInterface : public internal::ServerStreamingInterface, - public internal::WriterInterface, - public internal::ReaderInterface {}; - -/// Actual implementation of bi-directional streaming -namespace internal { -template -class ServerReaderWriterBody final { - public: - ServerReaderWriterBody(Call* call, ::grpc_impl::ServerContext* ctx) - : call_(call), ctx_(ctx) {} - - void SendInitialMetadata() { - GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); - - CallOpSet ops; - ops.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - ops.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - call_->PerformOps(&ops); - call_->cq()->Pluck(&ops); - } - - bool NextMessageSize(uint32_t* sz) { - *sz = call_->max_receive_message_size(); - return true; - } - - bool Read(R* msg) { - CallOpSet> ops; - ops.RecvMessage(msg); - call_->PerformOps(&ops); - return call_->cq()->Pluck(&ops) && ops.got_message; - } - - bool Write(const W& msg, WriteOptions options) { - if (options.is_last_message()) { - options.set_buffer_hint(); - } - if (!ctx_->pending_ops_.SendMessagePtr(&msg, options).ok()) { - return false; - } - if (!ctx_->sent_initial_metadata_) { - ctx_->pending_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - ctx_->pending_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - } - call_->PerformOps(&ctx_->pending_ops_); - // if this is the last message we defer the pluck until AFTER we start - // the trailing md op. This prevents hangs. See - // https://github.com/grpc/grpc/issues/11546 - if (options.is_last_message()) { - ctx_->has_pending_ops_ = true; - return true; - } - ctx_->has_pending_ops_ = false; - return call_->cq()->Pluck(&ctx_->pending_ops_); - } - - private: - Call* const call_; - ::grpc_impl::ServerContext* const ctx_; -}; - -} // namespace internal - -/// Synchronous (blocking) server-side API for a bidirectional -/// streaming call, where the incoming message stream coming from the client has -/// messages of type \a R, and the outgoing message streaming coming from -/// the server has messages of type \a W. +using ServerReaderWriterInterface = + ::grpc_impl::ServerReaderWriterInterface; template -class ServerReaderWriter final : public ServerReaderWriterInterface { - public: - /// See the \a ServerStreamingInterface.SendInitialMetadata method - /// for semantics. Note that initial metadata will be affected by the - /// \a ServerContext associated with this call. - void SendInitialMetadata() override { body_.SendInitialMetadata(); } - - bool NextMessageSize(uint32_t* sz) override { - return body_.NextMessageSize(sz); - } - - bool Read(R* msg) override { return body_.Read(msg); } - - /// See the \a WriterInterface.Write(const W& msg, WriteOptions options) - /// method for semantics. - /// Side effect: - /// Also sends initial metadata if not already sent (using the \a - /// ServerContext associated with this call). - using internal::WriterInterface::Write; - bool Write(const W& msg, WriteOptions options) override { - return body_.Write(msg, options); - } - - private: - internal::ServerReaderWriterBody body_; - - friend class internal::TemplatedBidiStreamingHandler, - false>; - ServerReaderWriter(internal::Call* call, ::grpc_impl::ServerContext* ctx) - : body_(call, ctx) {} -}; - -/// A class to represent a flow-controlled unary call. This is something -/// of a hybrid between conventional unary and streaming. This is invoked -/// through a unary call on the client side, but the server responds to it -/// as though it were a single-ping-pong streaming call. The server can use -/// the \a NextMessageSize method to determine an upper-bound on the size of -/// the message. A key difference relative to streaming: ServerUnaryStreamer -/// must have exactly 1 Read and exactly 1 Write, in that order, to function -/// correctly. Otherwise, the RPC is in error. +using ServerReaderWriter = ::grpc_impl::ServerReaderWriter; template -class ServerUnaryStreamer final - : public ServerReaderWriterInterface { - public: - /// Block to send initial metadata to client. - /// Implicit input parameter: - /// - the \a ServerContext associated with this call will be used for - /// sending initial metadata. - void SendInitialMetadata() override { body_.SendInitialMetadata(); } - - /// Get an upper bound on the request message size from the client. - bool NextMessageSize(uint32_t* sz) override { - return body_.NextMessageSize(sz); - } - - /// Read a message of type \a R into \a msg. Completion will be notified by \a - /// tag on the associated completion queue. - /// This is thread-safe with respect to \a Write or \a WritesDone methods. It - /// should not be called concurrently with other streaming APIs - /// on the same stream. It is not meaningful to call it concurrently - /// with another \a ReaderInterface::Read on the same stream since reads on - /// the same stream are delivered in order. - /// - /// \param[out] msg Where to eventually store the read message. - /// \param[in] tag The tag identifying the operation. - bool Read(RequestType* request) override { - if (read_done_) { - return false; - } - read_done_ = true; - return body_.Read(request); - } - - /// Block to write \a msg to the stream with WriteOptions \a options. - /// This is thread-safe with respect to \a ReaderInterface::Read - /// - /// \param msg The message to be written to the stream. - /// \param options The WriteOptions affecting the write operation. - /// - /// \return \a true on success, \a false when the stream has been closed. - using internal::WriterInterface::Write; - bool Write(const ResponseType& response, WriteOptions options) override { - if (write_done_ || !read_done_) { - return false; - } - write_done_ = true; - return body_.Write(response, options); - } - - private: - internal::ServerReaderWriterBody body_; - bool read_done_; - bool write_done_; - - friend class internal::TemplatedBidiStreamingHandler< - ServerUnaryStreamer, true>; - ServerUnaryStreamer(internal::Call* call, ::grpc_impl::ServerContext* ctx) - : body_(call, ctx), read_done_(false), write_done_(false) {} -}; - -/// A class to represent a flow-controlled server-side streaming call. -/// This is something of a hybrid between server-side and bidi streaming. -/// This is invoked through a server-side streaming call on the client side, -/// but the server responds to it as though it were a bidi streaming call that -/// must first have exactly 1 Read and then any number of Writes. +using ServerUnaryStreamer = + ::grpc_impl::ServerUnaryStreamer; template -class ServerSplitStreamer final - : public ServerReaderWriterInterface { - public: - /// Block to send initial metadata to client. - /// Implicit input parameter: - /// - the \a ServerContext associated with this call will be used for - /// sending initial metadata. - void SendInitialMetadata() override { body_.SendInitialMetadata(); } - - /// Get an upper bound on the request message size from the client. - bool NextMessageSize(uint32_t* sz) override { - return body_.NextMessageSize(sz); - } - - /// Read a message of type \a R into \a msg. Completion will be notified by \a - /// tag on the associated completion queue. - /// This is thread-safe with respect to \a Write or \a WritesDone methods. It - /// should not be called concurrently with other streaming APIs - /// on the same stream. It is not meaningful to call it concurrently - /// with another \a ReaderInterface::Read on the same stream since reads on - /// the same stream are delivered in order. - /// - /// \param[out] msg Where to eventually store the read message. - /// \param[in] tag The tag identifying the operation. - bool Read(RequestType* request) override { - if (read_done_) { - return false; - } - read_done_ = true; - return body_.Read(request); - } - - /// Block to write \a msg to the stream with WriteOptions \a options. - /// This is thread-safe with respect to \a ReaderInterface::Read - /// - /// \param msg The message to be written to the stream. - /// \param options The WriteOptions affecting the write operation. - /// - /// \return \a true on success, \a false when the stream has been closed. - using internal::WriterInterface::Write; - bool Write(const ResponseType& response, WriteOptions options) override { - return read_done_ && body_.Write(response, options); - } - - private: - internal::ServerReaderWriterBody body_; - bool read_done_; - - friend class internal::TemplatedBidiStreamingHandler< - ServerSplitStreamer, false>; - ServerSplitStreamer(internal::Call* call, ::grpc_impl::ServerContext* ctx) - : body_(call, ctx), read_done_(false) {} -}; +using ServerSplitStreamer = + ::grpc_impl::ServerSplitStreamer; } // namespace grpc diff --git a/include/grpcpp/impl/codegen/sync_stream_impl.h b/include/grpcpp/impl/codegen/sync_stream_impl.h new file mode 100644 index 00000000000..dc764e0e27b --- /dev/null +++ b/include/grpcpp/impl/codegen/sync_stream_impl.h @@ -0,0 +1,944 @@ +/* + * + * 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_SYNC_STREAM_IMPL_H +#define GRPCPP_IMPL_CODEGEN_SYNC_STREAM_IMPL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace grpc_impl { + +namespace internal { +/// Common interface for all synchronous client side streaming. +class ClientStreamingInterface { + public: + virtual ~ClientStreamingInterface() {} + + /// Block waiting until the stream finishes and a final status of the call is + /// available. + /// + /// It is appropriate to call this method when both: + /// * the calling code (client-side) has no more message to send + /// (this can be declared implicitly by calling this method, or + /// explicitly through an earlier call to WritesDone method of the + /// class in use, e.g. \a ClientWriterInterface::WritesDone or + /// \a ClientReaderWriterInterface::WritesDone). + /// * there are no more messages to be received from the server (which can + /// be known implicitly, or explicitly from an earlier call to \a + /// ReaderInterface::Read that returned "false"). + /// + /// This function will return either: + /// - when all incoming messages have been read and the server has + /// returned status. + /// - when the server has returned a non-OK status. + /// - OR when the call failed for some reason and the library generated a + /// status. + /// + /// Return values: + /// - \a Status contains the status code, message and details for the call + /// - the \a ClientContext associated with this call is updated with + /// possible trailing metadata sent from the server. + virtual ::grpc::Status Finish() = 0; +}; + +/// Common interface for all synchronous server side streaming. +class ServerStreamingInterface { + public: + virtual ~ServerStreamingInterface() {} + + /// Block to send initial metadata to client. + /// This call is optional, but if it is used, it cannot be used concurrently + /// with or after the \a Finish method. + /// + /// The initial metadata that will be sent to the client will be + /// taken from the \a ServerContext associated with the call. + virtual void SendInitialMetadata() = 0; +}; + +/// An interface that yields a sequence of messages of type \a R. +template +class ReaderInterface { + public: + virtual ~ReaderInterface() {} + + /// Get an upper bound on the next message size available for reading on this + /// stream. + virtual bool NextMessageSize(uint32_t* sz) = 0; + + /// Block to read a message and parse to \a msg. Returns \a true on success. + /// This is thread-safe with respect to \a Write or \WritesDone methods on + /// the same stream. It should not be called concurrently with another \a + /// Read on the same stream as the order of delivery will not be defined. + /// + /// \param[out] msg The read message. + /// + /// \return \a false when there will be no more incoming messages, either + /// because the other side has called \a WritesDone() or the stream has failed + /// (or been cancelled). + virtual bool Read(R* msg) = 0; +}; + +/// An interface that can be fed a sequence of messages of type \a W. +template +class WriterInterface { + public: + virtual ~WriterInterface() {} + + /// Block to write \a msg to the stream with WriteOptions \a options. + /// This is thread-safe with respect to \a ReaderInterface::Read + /// + /// \param msg The message to be written to the stream. + /// \param options The WriteOptions affecting the write operation. + /// + /// \return \a true on success, \a false when the stream has been closed. + virtual bool Write(const W& msg, ::grpc::WriteOptions options) = 0; + + /// Block to write \a msg to the stream with default write options. + /// This is thread-safe with respect to \a ReaderInterface::Read + /// + /// \param msg The message to be written to the stream. + /// + /// \return \a true on success, \a false when the stream has been closed. + inline bool Write(const W& msg) { return Write(msg, ::grpc::WriteOptions()); } + + /// Write \a msg and coalesce it with the writing of trailing metadata, using + /// WriteOptions \a options. + /// + /// For client, WriteLast is equivalent of performing Write and WritesDone in + /// a single step. \a msg and trailing metadata are coalesced and sent on wire + /// by calling this function. For server, WriteLast buffers the \a msg. + /// The writing of \a msg is held until the service handler returns, + /// where \a msg and trailing metadata are coalesced and sent on wire. + /// Note that WriteLast can only buffer \a msg up to the flow control window + /// size. If \a msg size is larger than the window size, it will be sent on + /// wire without buffering. + /// + /// \param[in] msg The message to be written to the stream. + /// \param[in] options The WriteOptions to be used to write this message. + void WriteLast(const W& msg, ::grpc::WriteOptions options) { + Write(msg, options.set_last_message()); + } +}; + +} // namespace internal + +/// Client-side interface for streaming reads of message of type \a R. +template +class ClientReaderInterface : public internal::ClientStreamingInterface, + public internal::ReaderInterface { + public: + /// Block to wait for initial metadata from server. The received metadata + /// can only be accessed after this call returns. Should only be called before + /// the first read. Calling this method is optional, and if it is not called + /// the metadata will be available in ClientContext after the first read. + virtual void WaitForInitialMetadata() = 0; +}; + +namespace internal { +template +class ClientReaderFactory { + public: + template + static ClientReader* Create(::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context, + const W& request) { + return new ClientReader(channel, method, context, request); + } +}; +} // namespace internal + +/// Synchronous (blocking) client-side API for doing server-streaming RPCs, +/// where the stream of messages coming from the server has messages +/// of type \a R. +template +class ClientReader final : public ClientReaderInterface { + public: + /// See the \a ClientStreamingInterface.WaitForInitialMetadata method for + /// semantics. + /// + // Side effect: + /// Once complete, the initial metadata read from + /// the server will be accessible through the \a ClientContext used to + /// construct this object. + void WaitForInitialMetadata() override { + GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); + + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> + ops; + ops.RecvInitialMetadata(context_); + call_.PerformOps(&ops); + cq_.Pluck(&ops); /// status ignored + } + + bool NextMessageSize(uint32_t* sz) override { + *sz = call_.max_receive_message_size(); + return true; + } + + /// See the \a ReaderInterface.Read method for semantics. + /// Side effect: + /// This also receives initial metadata from the server, if not + /// already received (if initial metadata is received, it can be then + /// accessed through the \a ClientContext associated with this call). + bool Read(R* msg) override { + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpRecvMessage> + ops; + if (!context_->initial_metadata_received_) { + ops.RecvInitialMetadata(context_); + } + ops.RecvMessage(msg); + call_.PerformOps(&ops); + return cq_.Pluck(&ops) && ops.got_message; + } + + /// See the \a ClientStreamingInterface.Finish method for semantics. + /// + /// Side effect: + /// The \a ClientContext associated with this call is updated with + /// possible metadata received from the server. + ::grpc::Status Finish() override { + ::grpc::internal::CallOpSet<::grpc::internal::CallOpClientRecvStatus> ops; + ::grpc::Status status; + ops.ClientRecvStatus(context_, &status); + call_.PerformOps(&ops); + GPR_CODEGEN_ASSERT(cq_.Pluck(&ops)); + return status; + } + + private: + friend class internal::ClientReaderFactory; + ::grpc_impl::ClientContext* context_; + ::grpc_impl::CompletionQueue cq_; + ::grpc::internal::Call call_; + + /// Block to create a stream and write the initial metadata and \a request + /// out. Note that \a context will be used to fill in custom initial + /// metadata used to send to the server when starting the call. + template + ClientReader(::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context, const W& request) + : context_(context), + cq_(grpc_completion_queue_attributes{ + GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING, + nullptr}), // Pluckable cq + call_(channel->CreateCall(method, context, &cq_)) { + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpClientSendClose> + ops; + ops.SendInitialMetadata(&context->send_initial_metadata_, + context->initial_metadata_flags()); + // TODO(ctiller): don't assert + GPR_CODEGEN_ASSERT(ops.SendMessagePtr(&request).ok()); + ops.ClientSendClose(); + call_.PerformOps(&ops); + cq_.Pluck(&ops); + } +}; + +/// Client-side interface for streaming writes of message type \a W. +template +class ClientWriterInterface : public internal::ClientStreamingInterface, + public internal::WriterInterface { + public: + /// Half close writing from the client. (signal that the stream of messages + /// coming from the client is complete). + /// Blocks until currently-pending writes are completed. + /// Thread safe with respect to \a ReaderInterface::Read operations only + /// + /// \return Whether the writes were successful. + virtual bool WritesDone() = 0; +}; + +namespace internal { +template +class ClientWriterFactory { + public: + template + static ClientWriter* Create(::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context, + R* response) { + return new ClientWriter(channel, method, context, response); + } +}; +} // namespace internal + +/// Synchronous (blocking) client-side API for doing client-streaming RPCs, +/// where the outgoing message stream coming from the client has messages of +/// type \a W. +template +class ClientWriter : public ClientWriterInterface { + public: + /// See the \a ClientStreamingInterface.WaitForInitialMetadata method for + /// semantics. + /// + // Side effect: + /// Once complete, the initial metadata read from the server will be + /// accessible through the \a ClientContext used to construct this object. + void WaitForInitialMetadata() { + GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); + + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> + ops; + ops.RecvInitialMetadata(context_); + call_.PerformOps(&ops); + cq_.Pluck(&ops); // status ignored + } + + /// See the WriterInterface.Write(const W& msg, WriteOptions options) method + /// for semantics. + /// + /// Side effect: + /// Also sends initial metadata if not already sent (using the + /// \a ClientContext associated with this call). + using internal::WriterInterface::Write; + bool Write(const W& msg, ::grpc::WriteOptions options) override { + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpClientSendClose> + ops; + + if (options.is_last_message()) { + options.set_buffer_hint(); + ops.ClientSendClose(); + } + if (context_->initial_metadata_corked_) { + ops.SendInitialMetadata(&context_->send_initial_metadata_, + context_->initial_metadata_flags()); + context_->set_initial_metadata_corked(false); + } + if (!ops.SendMessagePtr(&msg, options).ok()) { + return false; + } + + call_.PerformOps(&ops); + return cq_.Pluck(&ops); + } + + bool WritesDone() override { + ::grpc::internal::CallOpSet<::grpc::internal::CallOpClientSendClose> ops; + ops.ClientSendClose(); + call_.PerformOps(&ops); + return cq_.Pluck(&ops); + } + + /// See the ClientStreamingInterface.Finish method for semantics. + /// Side effects: + /// - Also receives initial metadata if not already received. + /// - Attempts to fill in the \a response parameter passed + /// to the constructor of this instance with the response + /// message from the server. + ::grpc::Status Finish() override { + ::grpc::Status status; + if (!context_->initial_metadata_received_) { + finish_ops_.RecvInitialMetadata(context_); + } + finish_ops_.ClientRecvStatus(context_, &status); + call_.PerformOps(&finish_ops_); + GPR_CODEGEN_ASSERT(cq_.Pluck(&finish_ops_)); + return status; + } + + private: + friend class internal::ClientWriterFactory; + + /// Block to create a stream (i.e. send request headers and other initial + /// metadata to the server). Note that \a context will be used to fill + /// in custom initial metadata. \a response will be filled in with the + /// single expected response message from the server upon a successful + /// call to the \a Finish method of this instance. + template + ClientWriter(::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context, R* response) + : context_(context), + cq_(grpc_completion_queue_attributes{ + GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING, + nullptr}), // Pluckable cq + call_(channel->CreateCall(method, context, &cq_)) { + finish_ops_.RecvMessage(response); + finish_ops_.AllowNoMessage(); + + if (!context_->initial_metadata_corked_) { + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> + ops; + ops.SendInitialMetadata(&context->send_initial_metadata_, + context->initial_metadata_flags()); + call_.PerformOps(&ops); + cq_.Pluck(&ops); + } + } + + ::grpc_impl::ClientContext* context_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpGenericRecvMessage, + ::grpc::internal::CallOpClientRecvStatus> + finish_ops_; + ::grpc_impl::CompletionQueue cq_; + ::grpc::internal::Call call_; +}; + +/// Client-side interface for bi-directional streaming with +/// client-to-server stream messages of type \a W and +/// server-to-client stream messages of type \a R. +template +class ClientReaderWriterInterface : public internal::ClientStreamingInterface, + public internal::WriterInterface, + public internal::ReaderInterface { + public: + /// Block to wait for initial metadata from server. The received metadata + /// can only be accessed after this call returns. Should only be called before + /// the first read. Calling this method is optional, and if it is not called + /// the metadata will be available in ClientContext after the first read. + virtual void WaitForInitialMetadata() = 0; + + /// Half close writing from the client. (signal that the stream of messages + /// coming from the clinet is complete). + /// Blocks until currently-pending writes are completed. + /// Thread-safe with respect to \a ReaderInterface::Read + /// + /// \return Whether the writes were successful. + virtual bool WritesDone() = 0; +}; + +namespace internal { +template +class ClientReaderWriterFactory { + public: + static ClientReaderWriter* Create( + ::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context) { + return new ClientReaderWriter(channel, method, context); + } +}; +} // namespace internal + +/// Synchronous (blocking) client-side API for bi-directional streaming RPCs, +/// where the outgoing message stream coming from the client has messages of +/// type \a W, and the incoming messages stream coming from the server has +/// messages of type \a R. +template +class ClientReaderWriter final : public ClientReaderWriterInterface { + public: + /// Block waiting to read initial metadata from the server. + /// This call is optional, but if it is used, it cannot be used concurrently + /// with or after the \a Finish method. + /// + /// Once complete, the initial metadata read from the server will be + /// accessible through the \a ClientContext used to construct this object. + void WaitForInitialMetadata() override { + GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); + + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> + ops; + ops.RecvInitialMetadata(context_); + call_.PerformOps(&ops); + cq_.Pluck(&ops); // status ignored + } + + bool NextMessageSize(uint32_t* sz) override { + *sz = call_.max_receive_message_size(); + return true; + } + + /// See the \a ReaderInterface.Read method for semantics. + /// Side effect: + /// Also receives initial metadata if not already received (updates the \a + /// ClientContext associated with this call in that case). + bool Read(R* msg) override { + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpRecvMessage> + ops; + if (!context_->initial_metadata_received_) { + ops.RecvInitialMetadata(context_); + } + ops.RecvMessage(msg); + call_.PerformOps(&ops); + return cq_.Pluck(&ops) && ops.got_message; + } + + /// See the \a WriterInterface.Write method for semantics. + /// + /// Side effect: + /// Also sends initial metadata if not already sent (using the + /// \a ClientContext associated with this call to fill in values). + using internal::WriterInterface::Write; + bool Write(const W& msg, ::grpc::WriteOptions options) override { + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpClientSendClose> + ops; + + if (options.is_last_message()) { + options.set_buffer_hint(); + ops.ClientSendClose(); + } + if (context_->initial_metadata_corked_) { + ops.SendInitialMetadata(&context_->send_initial_metadata_, + context_->initial_metadata_flags()); + context_->set_initial_metadata_corked(false); + } + if (!ops.SendMessagePtr(&msg, options).ok()) { + return false; + } + + call_.PerformOps(&ops); + return cq_.Pluck(&ops); + } + + bool WritesDone() override { + ::grpc::internal::CallOpSet<::grpc::internal::CallOpClientSendClose> ops; + ops.ClientSendClose(); + call_.PerformOps(&ops); + return cq_.Pluck(&ops); + } + + /// See the ClientStreamingInterface.Finish method for semantics. + /// + /// Side effect: + /// - the \a ClientContext associated with this call is updated with + /// possible trailing metadata sent from the server. + ::grpc::Status Finish() override { + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpClientRecvStatus> + ops; + if (!context_->initial_metadata_received_) { + ops.RecvInitialMetadata(context_); + } + ::grpc::Status status; + ops.ClientRecvStatus(context_, &status); + call_.PerformOps(&ops); + GPR_CODEGEN_ASSERT(cq_.Pluck(&ops)); + return status; + } + + private: + friend class internal::ClientReaderWriterFactory; + + ::grpc_impl::ClientContext* context_; + ::grpc_impl::CompletionQueue cq_; + ::grpc::internal::Call call_; + + /// Block to create a stream and write the initial metadata and \a request + /// out. Note that \a context will be used to fill in custom initial metadata + /// used to send to the server when starting the call. + ClientReaderWriter(::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context) + : context_(context), + cq_(grpc_completion_queue_attributes{ + GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING, + nullptr}), // Pluckable cq + call_(channel->CreateCall(method, context, &cq_)) { + if (!context_->initial_metadata_corked_) { + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> + ops; + ops.SendInitialMetadata(&context->send_initial_metadata_, + context->initial_metadata_flags()); + call_.PerformOps(&ops); + cq_.Pluck(&ops); + } + } +}; + +/// Server-side interface for streaming reads of message of type \a R. +template +class ServerReaderInterface : public internal::ServerStreamingInterface, + public internal::ReaderInterface {}; + +/// Synchronous (blocking) server-side API for doing client-streaming RPCs, +/// where the incoming message stream coming from the client has messages of +/// type \a R. +template +class ServerReader final : public ServerReaderInterface { + public: + /// See the \a ServerStreamingInterface.SendInitialMetadata method + /// for semantics. Note that initial metadata will be affected by the + /// \a ServerContext associated with this call. + void SendInitialMetadata() override { + GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); + + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> + ops; + ops.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + ops.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + call_->PerformOps(&ops); + call_->cq()->Pluck(&ops); + } + + bool NextMessageSize(uint32_t* sz) override { + *sz = call_->max_receive_message_size(); + return true; + } + + bool Read(R* msg) override { + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage> ops; + ops.RecvMessage(msg); + call_->PerformOps(&ops); + return call_->cq()->Pluck(&ops) && ops.got_message; + } + + private: + ::grpc::internal::Call* const call_; + ServerContext* const ctx_; + + template + friend class ::grpc::internal::ClientStreamingHandler; + + ServerReader(::grpc::internal::Call* call, ::grpc_impl::ServerContext* ctx) + : call_(call), ctx_(ctx) {} +}; + +/// Server-side interface for streaming writes of message of type \a W. +template +class ServerWriterInterface : public internal::ServerStreamingInterface, + public internal::WriterInterface {}; + +/// Synchronous (blocking) server-side API for doing for doing a +/// server-streaming RPCs, where the outgoing message stream coming from the +/// server has messages of type \a W. +template +class ServerWriter final : public ServerWriterInterface { + public: + /// See the \a ServerStreamingInterface.SendInitialMetadata method + /// for semantics. + /// Note that initial metadata will be affected by the + /// \a ServerContext associated with this call. + void SendInitialMetadata() override { + GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); + + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> + ops; + ops.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + ops.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + call_->PerformOps(&ops); + call_->cq()->Pluck(&ops); + } + + /// See the \a WriterInterface.Write method for semantics. + /// + /// Side effect: + /// Also sends initial metadata if not already sent (using the + /// \a ClientContext associated with this call to fill in values). + using internal::WriterInterface::Write; + bool Write(const W& msg, ::grpc::WriteOptions options) override { + if (options.is_last_message()) { + options.set_buffer_hint(); + } + + if (!ctx_->pending_ops_.SendMessagePtr(&msg, options).ok()) { + return false; + } + if (!ctx_->sent_initial_metadata_) { + ctx_->pending_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + ctx_->pending_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + } + call_->PerformOps(&ctx_->pending_ops_); + // if this is the last message we defer the pluck until AFTER we start + // the trailing md op. This prevents hangs. See + // https://github.com/grpc/grpc/issues/11546 + if (options.is_last_message()) { + ctx_->has_pending_ops_ = true; + return true; + } + ctx_->has_pending_ops_ = false; + return call_->cq()->Pluck(&ctx_->pending_ops_); + } + + private: + ::grpc::internal::Call* const call_; + ::grpc_impl::ServerContext* const ctx_; + + template + friend class ::grpc::internal::ServerStreamingHandler; + + ServerWriter(::grpc::internal::Call* call, ::grpc_impl::ServerContext* ctx) + : call_(call), ctx_(ctx) {} +}; + +/// Server-side interface for bi-directional streaming. +template +class ServerReaderWriterInterface : public internal::ServerStreamingInterface, + public internal::WriterInterface, + public internal::ReaderInterface {}; + +/// Actual implementation of bi-directional streaming +namespace internal { +template +class ServerReaderWriterBody final { + public: + ServerReaderWriterBody(grpc::internal::Call* call, + ::grpc_impl::ServerContext* ctx) + : call_(call), ctx_(ctx) {} + + void SendInitialMetadata() { + GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); + + grpc::internal::CallOpSet ops; + ops.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + ops.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + call_->PerformOps(&ops); + call_->cq()->Pluck(&ops); + } + + bool NextMessageSize(uint32_t* sz) { + *sz = call_->max_receive_message_size(); + return true; + } + + bool Read(R* msg) { + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage> ops; + ops.RecvMessage(msg); + call_->PerformOps(&ops); + return call_->cq()->Pluck(&ops) && ops.got_message; + } + + bool Write(const W& msg, ::grpc::WriteOptions options) { + if (options.is_last_message()) { + options.set_buffer_hint(); + } + if (!ctx_->pending_ops_.SendMessagePtr(&msg, options).ok()) { + return false; + } + if (!ctx_->sent_initial_metadata_) { + ctx_->pending_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + ctx_->pending_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + } + call_->PerformOps(&ctx_->pending_ops_); + // if this is the last message we defer the pluck until AFTER we start + // the trailing md op. This prevents hangs. See + // https://github.com/grpc/grpc/issues/11546 + if (options.is_last_message()) { + ctx_->has_pending_ops_ = true; + return true; + } + ctx_->has_pending_ops_ = false; + return call_->cq()->Pluck(&ctx_->pending_ops_); + } + + private: + grpc::internal::Call* const call_; + ::grpc_impl::ServerContext* const ctx_; +}; + +} // namespace internal + +/// Synchronous (blocking) server-side API for a bidirectional +/// streaming call, where the incoming message stream coming from the client has +/// messages of type \a R, and the outgoing message streaming coming from +/// the server has messages of type \a W. +template +class ServerReaderWriter final : public ServerReaderWriterInterface { + public: + /// See the \a ServerStreamingInterface.SendInitialMetadata method + /// for semantics. Note that initial metadata will be affected by the + /// \a ServerContext associated with this call. + void SendInitialMetadata() override { body_.SendInitialMetadata(); } + + bool NextMessageSize(uint32_t* sz) override { + return body_.NextMessageSize(sz); + } + + bool Read(R* msg) override { return body_.Read(msg); } + + /// See the \a WriterInterface.Write(const W& msg, WriteOptions options) + /// method for semantics. + /// Side effect: + /// Also sends initial metadata if not already sent (using the \a + /// ServerContext associated with this call). + using internal::WriterInterface::Write; + bool Write(const W& msg, ::grpc::WriteOptions options) override { + return body_.Write(msg, options); + } + + private: + internal::ServerReaderWriterBody body_; + + friend class ::grpc::internal::TemplatedBidiStreamingHandler< + ServerReaderWriter, false>; + ServerReaderWriter(::grpc::internal::Call* call, + ::grpc_impl::ServerContext* ctx) + : body_(call, ctx) {} +}; + +/// A class to represent a flow-controlled unary call. This is something +/// of a hybrid between conventional unary and streaming. This is invoked +/// through a unary call on the client side, but the server responds to it +/// as though it were a single-ping-pong streaming call. The server can use +/// the \a NextMessageSize method to determine an upper-bound on the size of +/// the message. A key difference relative to streaming: ServerUnaryStreamer +/// must have exactly 1 Read and exactly 1 Write, in that order, to function +/// correctly. Otherwise, the RPC is in error. +template +class ServerUnaryStreamer final + : public ServerReaderWriterInterface { + public: + /// Block to send initial metadata to client. + /// Implicit input parameter: + /// - the \a ServerContext associated with this call will be used for + /// sending initial metadata. + void SendInitialMetadata() override { body_.SendInitialMetadata(); } + + /// Get an upper bound on the request message size from the client. + bool NextMessageSize(uint32_t* sz) override { + return body_.NextMessageSize(sz); + } + + /// Read a message of type \a R into \a msg. Completion will be notified by \a + /// tag on the associated completion queue. + /// This is thread-safe with respect to \a Write or \a WritesDone methods. It + /// should not be called concurrently with other streaming APIs + /// on the same stream. It is not meaningful to call it concurrently + /// with another \a ReaderInterface::Read on the same stream since reads on + /// the same stream are delivered in order. + /// + /// \param[out] msg Where to eventually store the read message. + /// \param[in] tag The tag identifying the operation. + bool Read(RequestType* request) override { + if (read_done_) { + return false; + } + read_done_ = true; + return body_.Read(request); + } + + /// Block to write \a msg to the stream with WriteOptions \a options. + /// This is thread-safe with respect to \a ReaderInterface::Read + /// + /// \param msg The message to be written to the stream. + /// \param options The WriteOptions affecting the write operation. + /// + /// \return \a true on success, \a false when the stream has been closed. + using internal::WriterInterface::Write; + bool Write(const ResponseType& response, + ::grpc::WriteOptions options) override { + if (write_done_ || !read_done_) { + return false; + } + write_done_ = true; + return body_.Write(response, options); + } + + private: + internal::ServerReaderWriterBody body_; + bool read_done_; + bool write_done_; + + friend class ::grpc::internal::TemplatedBidiStreamingHandler< + ServerUnaryStreamer, true>; + ServerUnaryStreamer(::grpc::internal::Call* call, + ::grpc_impl::ServerContext* ctx) + : body_(call, ctx), read_done_(false), write_done_(false) {} +}; + +/// A class to represent a flow-controlled server-side streaming call. +/// This is something of a hybrid between server-side and bidi streaming. +/// This is invoked through a server-side streaming call on the client side, +/// but the server responds to it as though it were a bidi streaming call that +/// must first have exactly 1 Read and then any number of Writes. +template +class ServerSplitStreamer final + : public ServerReaderWriterInterface { + public: + /// Block to send initial metadata to client. + /// Implicit input parameter: + /// - the \a ServerContext associated with this call will be used for + /// sending initial metadata. + void SendInitialMetadata() override { body_.SendInitialMetadata(); } + + /// Get an upper bound on the request message size from the client. + bool NextMessageSize(uint32_t* sz) override { + return body_.NextMessageSize(sz); + } + + /// Read a message of type \a R into \a msg. Completion will be notified by \a + /// tag on the associated completion queue. + /// This is thread-safe with respect to \a Write or \a WritesDone methods. It + /// should not be called concurrently with other streaming APIs + /// on the same stream. It is not meaningful to call it concurrently + /// with another \a ReaderInterface::Read on the same stream since reads on + /// the same stream are delivered in order. + /// + /// \param[out] msg Where to eventually store the read message. + /// \param[in] tag The tag identifying the operation. + bool Read(RequestType* request) override { + if (read_done_) { + return false; + } + read_done_ = true; + return body_.Read(request); + } + + /// Block to write \a msg to the stream with WriteOptions \a options. + /// This is thread-safe with respect to \a ReaderInterface::Read + /// + /// \param msg The message to be written to the stream. + /// \param options The WriteOptions affecting the write operation. + /// + /// \return \a true on success, \a false when the stream has been closed. + using internal::WriterInterface::Write; + bool Write(const ResponseType& response, + ::grpc::WriteOptions options) override { + return read_done_ && body_.Write(response, options); + } + + private: + internal::ServerReaderWriterBody body_; + bool read_done_; + + friend class ::grpc::internal::TemplatedBidiStreamingHandler< + ServerSplitStreamer, false>; + ServerSplitStreamer(::grpc::internal::Call* call, + ::grpc_impl::ServerContext* ctx) + : body_(call, ctx), read_done_(false) {} +}; + +} // namespace grpc_impl + +#endif // GRPCPP_IMPL_CODEGEN_SYNC_STREAM_IMPL_H diff --git a/include/grpcpp/support/async_stream_impl.h b/include/grpcpp/support/async_stream_impl.h new file mode 100644 index 00000000000..cff700d3fa9 --- /dev/null +++ b/include/grpcpp/support/async_stream_impl.h @@ -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_ASYNC_STREAM_IMPL_H +#define GRPCPP_SUPPORT_ASYNC_STREAM_IMPL_H + +#include + +#endif // GRPCPP_SUPPORT_ASYNC_STREAM_IMPL_H diff --git a/include/grpcpp/support/async_unary_call_impl.h b/include/grpcpp/support/async_unary_call_impl.h new file mode 100644 index 00000000000..488fe87515a --- /dev/null +++ b/include/grpcpp/support/async_unary_call_impl.h @@ -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_ASYNC_UNARY_CALL_IMPL_H +#define GRPCPP_SUPPORT_ASYNC_UNARY_CALL_IMPL_H + +#include + +#endif // GRPCPP_SUPPORT_ASYNC_UNARY_CALL_IMPL_H diff --git a/include/grpcpp/support/client_callback_impl.h b/include/grpcpp/support/client_callback_impl.h new file mode 100644 index 00000000000..ed8df412496 --- /dev/null +++ b/include/grpcpp/support/client_callback_impl.h @@ -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_CLIENT_CALLBACK_IMPL_H +#define GRPCPP_SUPPORT_CLIENT_CALLBACK_IMPL_H + +#include + +#endif // GRPCPP_SUPPORT_CLIENT_CALLBACK_IMPL_H diff --git a/include/grpcpp/support/server_callback_impl.h b/include/grpcpp/support/server_callback_impl.h new file mode 100644 index 00000000000..a91c8141dd8 --- /dev/null +++ b/include/grpcpp/support/server_callback_impl.h @@ -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_SERVER_CALLBACK_IMPL_H +#define GRPCPP_SUPPORT_SERVER_CALLBACK_IMPL_H + +#include + +#endif // GRPCPP_SUPPORT_SERVER_CALLBACK_IMPL_H diff --git a/include/grpcpp/support/sync_stream_impl.h b/include/grpcpp/support/sync_stream_impl.h new file mode 100644 index 00000000000..a00e425acfc --- /dev/null +++ b/include/grpcpp/support/sync_stream_impl.h @@ -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_SYNC_STREAM_IMPL_H +#define GRPCPP_SUPPORT_SYNC_STREAM_IMPL_H + +#include + +#endif // GRPCPP_SUPPORT_SYNC_STREAM_IMPL_H diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc index 358efe9fd79..044647d9a81 100644 --- a/src/compiler/cpp_generator.cc +++ b/src/compiler/cpp_generator.cc @@ -143,6 +143,7 @@ grpc::string GetHeaderIncludes(grpc_generator::File* file, "grpcpp/impl/codegen/async_unary_call.h", "grpcpp/impl/codegen/client_callback.h", "grpcpp/impl/codegen/client_context.h", + "grpcpp/impl/codegen/completion_queue.h", "grpcpp/impl/codegen/method_handler_impl.h", "grpcpp/impl/codegen/proto_utils.h", "grpcpp/impl/codegen/rpc_method.h", @@ -946,11 +947,12 @@ void PrintHeaderServerCallbackMethodsHelper( " abort();\n" " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" "}\n"); - printer->Print(*vars, - "virtual ::grpc::experimental::ServerReadReactor< " - "$RealRequest$, $RealResponse$>* $Method$() {\n" - " return new ::grpc::internal::UnimplementedReadReactor<\n" - " $RealRequest$, $RealResponse$>;}\n"); + printer->Print( + *vars, + "virtual ::grpc::experimental::ServerReadReactor< " + "$RealRequest$, $RealResponse$>* $Method$() {\n" + " return new ::grpc_impl::internal::UnimplementedReadReactor<\n" + " $RealRequest$, $RealResponse$>;}\n"); } else if (ServerOnlyStreaming(method)) { printer->Print( *vars, @@ -962,11 +964,12 @@ void PrintHeaderServerCallbackMethodsHelper( " abort();\n" " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" "}\n"); - printer->Print(*vars, - "virtual ::grpc::experimental::ServerWriteReactor< " - "$RealRequest$, $RealResponse$>* $Method$() {\n" - " return new ::grpc::internal::UnimplementedWriteReactor<\n" - " $RealRequest$, $RealResponse$>;}\n"); + printer->Print( + *vars, + "virtual ::grpc::experimental::ServerWriteReactor< " + "$RealRequest$, $RealResponse$>* $Method$() {\n" + " return new ::grpc_impl::internal::UnimplementedWriteReactor<\n" + " $RealRequest$, $RealResponse$>;}\n"); } else if (method->BidiStreaming()) { printer->Print( *vars, @@ -978,11 +981,12 @@ void PrintHeaderServerCallbackMethodsHelper( " abort();\n" " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" "}\n"); - printer->Print(*vars, - "virtual ::grpc::experimental::ServerBidiReactor< " - "$RealRequest$, $RealResponse$>* $Method$() {\n" - " return new ::grpc::internal::UnimplementedBidiReactor<\n" - " $RealRequest$, $RealResponse$>;}\n"); + printer->Print( + *vars, + "virtual ::grpc::experimental::ServerBidiReactor< " + "$RealRequest$, $RealResponse$>* $Method$() {\n" + " return new ::grpc_impl::internal::UnimplementedBidiReactor<\n" + " $RealRequest$, $RealResponse$>;}\n"); } } @@ -1010,7 +1014,7 @@ void PrintHeaderServerMethodCallback( printer->Print( *vars, " ::grpc::Service::experimental().MarkMethodCallback($Idx$,\n" - " new ::grpc::internal::CallbackUnaryHandler< " + " new ::grpc_impl::internal::CallbackUnaryHandler< " "$RealRequest$, $RealResponse$>(\n" " [this](::grpc::ServerContext* context,\n" " const $RealRequest$* request,\n" @@ -1024,7 +1028,7 @@ void PrintHeaderServerMethodCallback( "void SetMessageAllocatorFor_$Method$(\n" " ::grpc::experimental::MessageAllocator< " "$RealRequest$, $RealResponse$>* allocator) {\n" - " static_cast<::grpc::internal::CallbackUnaryHandler< " + " static_cast<::grpc_impl::internal::CallbackUnaryHandler< " "$RealRequest$, $RealResponse$>*>(\n" " ::grpc::Service::experimental().GetHandler($Idx$))\n" " ->SetMessageAllocator(allocator);\n"); @@ -1032,21 +1036,21 @@ void PrintHeaderServerMethodCallback( printer->Print( *vars, " ::grpc::Service::experimental().MarkMethodCallback($Idx$,\n" - " new ::grpc::internal::CallbackClientStreamingHandler< " + " new ::grpc_impl::internal::CallbackClientStreamingHandler< " "$RealRequest$, $RealResponse$>(\n" " [this] { return this->$Method$(); }));\n"); } else if (ServerOnlyStreaming(method)) { printer->Print( *vars, " ::grpc::Service::experimental().MarkMethodCallback($Idx$,\n" - " new ::grpc::internal::CallbackServerStreamingHandler< " + " new ::grpc_impl::internal::CallbackServerStreamingHandler< " "$RealRequest$, $RealResponse$>(\n" " [this] { return this->$Method$(); }));\n"); } else if (method->BidiStreaming()) { printer->Print( *vars, " ::grpc::Service::experimental().MarkMethodCallback($Idx$,\n" - " new ::grpc::internal::CallbackBidiHandler< " + " new ::grpc_impl::internal::CallbackBidiHandler< " "$RealRequest$, $RealResponse$>(\n" " [this] { return this->$Method$(); }));\n"); } @@ -1084,7 +1088,7 @@ void PrintHeaderServerMethodRawCallback( printer->Print( *vars, " ::grpc::Service::experimental().MarkMethodRawCallback($Idx$,\n" - " new ::grpc::internal::CallbackUnaryHandler< " + " new ::grpc_impl::internal::CallbackUnaryHandler< " "$RealRequest$, $RealResponse$>(\n" " [this](::grpc::ServerContext* context,\n" " const $RealRequest$* request,\n" @@ -1098,21 +1102,21 @@ void PrintHeaderServerMethodRawCallback( printer->Print( *vars, " ::grpc::Service::experimental().MarkMethodRawCallback($Idx$,\n" - " new ::grpc::internal::CallbackClientStreamingHandler< " + " new ::grpc_impl::internal::CallbackClientStreamingHandler< " "$RealRequest$, $RealResponse$>(\n" " [this] { return this->$Method$(); }));\n"); } else if (ServerOnlyStreaming(method)) { printer->Print( *vars, " ::grpc::Service::experimental().MarkMethodRawCallback($Idx$,\n" - " new ::grpc::internal::CallbackServerStreamingHandler< " + " new ::grpc_impl::internal::CallbackServerStreamingHandler< " "$RealRequest$, $RealResponse$>(\n" " [this] { return this->$Method$(); }));\n"); } else if (method->BidiStreaming()) { printer->Print( *vars, " ::grpc::Service::experimental().MarkMethodRawCallback($Idx$,\n" - " new ::grpc::internal::CallbackBidiHandler< " + " new ::grpc_impl::internal::CallbackBidiHandler< " "$RealRequest$, $RealResponse$>(\n" " [this] { return this->$Method$(); }));\n"); } @@ -1705,7 +1709,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, "const $Request$* request, $Response$* response, " "std::function f) {\n"); printer->Print(*vars, - " ::grpc::internal::CallbackUnaryCall" + " ::grpc_impl::internal::CallbackUnaryCall" "(stub_->channel_.get(), stub_->rpcmethod_$Method$_, " "context, request, response, std::move(f));\n}\n\n"); @@ -1715,7 +1719,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, "const ::grpc::ByteBuffer* request, $Response$* response, " "std::function f) {\n"); printer->Print(*vars, - " ::grpc::internal::CallbackUnaryCall" + " ::grpc_impl::internal::CallbackUnaryCall" "(stub_->channel_.get(), stub_->rpcmethod_$Method$_, " "context, request, response, std::move(f));\n}\n\n"); @@ -1725,7 +1729,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, "const $Request$* request, $Response$* response, " "::grpc::experimental::ClientUnaryReactor* reactor) {\n"); printer->Print(*vars, - " ::grpc::internal::ClientCallbackUnaryFactory::Create" + " ::grpc_impl::internal::ClientCallbackUnaryFactory::Create" "(stub_->channel_.get(), stub_->rpcmethod_$Method$_, " "context, request, response, reactor);\n}\n\n"); @@ -1735,7 +1739,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, "const ::grpc::ByteBuffer* request, $Response$* response, " "::grpc::experimental::ClientUnaryReactor* reactor) {\n"); printer->Print(*vars, - " ::grpc::internal::ClientCallbackUnaryFactory::Create" + " ::grpc_impl::internal::ClientCallbackUnaryFactory::Create" "(stub_->channel_.get(), stub_->rpcmethod_$Method$_, " "context, request, response, reactor);\n}\n\n"); @@ -1751,7 +1755,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, printer->Print( *vars, " return " - "::grpc::internal::ClientAsyncResponseReaderFactory< $Response$>" + "::grpc_impl::internal::ClientAsyncResponseReaderFactory< $Response$>" "::Create(channel_.get(), cq, " "rpcmethod_$Method$_, " "context, request, $AsyncStart$);\n" @@ -1762,13 +1766,13 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, "::grpc::ClientWriter< $Request$>* " "$ns$$Service$::Stub::$Method$Raw(" "::grpc::ClientContext* context, $Response$* response) {\n"); - printer->Print( - *vars, - " return ::grpc::internal::ClientWriterFactory< $Request$>::Create(" - "channel_.get(), " - "rpcmethod_$Method$_, " - "context, response);\n" - "}\n\n"); + printer->Print(*vars, + " return ::grpc_impl::internal::ClientWriterFactory< " + "$Request$>::Create(" + "channel_.get(), " + "rpcmethod_$Method$_, " + "context, response);\n" + "}\n\n"); printer->Print( *vars, @@ -1777,7 +1781,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, "$Response$* response, " "::grpc::experimental::ClientWriteReactor< $Request$>* reactor) {\n"); printer->Print(*vars, - " ::grpc::internal::ClientCallbackWriterFactory< " + " ::grpc_impl::internal::ClientCallbackWriterFactory< " "$Request$>::Create(" "stub_->channel_.get(), " "stub_->rpcmethod_$Method$_, " @@ -1796,7 +1800,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); printer->Print( *vars, - " return ::grpc::internal::ClientAsyncWriterFactory< $Request$>" + " return ::grpc_impl::internal::ClientAsyncWriterFactory< $Request$>" "::Create(channel_.get(), cq, " "rpcmethod_$Method$_, " "context, response, $AsyncStart$$AsyncCreateArgs$);\n" @@ -1808,13 +1812,13 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, "::grpc::ClientReader< $Response$>* " "$ns$$Service$::Stub::$Method$Raw(" "::grpc::ClientContext* context, const $Request$& request) {\n"); - printer->Print( - *vars, - " return ::grpc::internal::ClientReaderFactory< $Response$>::Create(" - "channel_.get(), " - "rpcmethod_$Method$_, " - "context, request);\n" - "}\n\n"); + printer->Print(*vars, + " return ::grpc_impl::internal::ClientReaderFactory< " + "$Response$>::Create(" + "channel_.get(), " + "rpcmethod_$Method$_, " + "context, request);\n" + "}\n\n"); printer->Print( *vars, @@ -1823,7 +1827,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, "$Request$* request, " "::grpc::experimental::ClientReadReactor< $Response$>* reactor) {\n"); printer->Print(*vars, - " ::grpc::internal::ClientCallbackReaderFactory< " + " ::grpc_impl::internal::ClientCallbackReaderFactory< " "$Response$>::Create(" "stub_->channel_.get(), " "stub_->rpcmethod_$Method$_, " @@ -1843,7 +1847,8 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); printer->Print( *vars, - " return ::grpc::internal::ClientAsyncReaderFactory< $Response$>" + " return ::grpc_impl::internal::ClientAsyncReaderFactory< " + "$Response$>" "::Create(channel_.get(), cq, " "rpcmethod_$Method$_, " "context, request, $AsyncStart$$AsyncCreateArgs$);\n" @@ -1855,7 +1860,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, "::grpc::ClientReaderWriter< $Request$, $Response$>* " "$ns$$Service$::Stub::$Method$Raw(::grpc::ClientContext* context) {\n"); printer->Print(*vars, - " return ::grpc::internal::ClientReaderWriterFactory< " + " return ::grpc_impl::internal::ClientReaderWriterFactory< " "$Request$, $Response$>::Create(" "channel_.get(), " "rpcmethod_$Method$_, " @@ -1868,13 +1873,14 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, "ClientContext* context, " "::grpc::experimental::ClientBidiReactor< $Request$,$Response$>* " "reactor) {\n"); - printer->Print(*vars, - " ::grpc::internal::ClientCallbackReaderWriterFactory< " - "$Request$,$Response$>::Create(" - "stub_->channel_.get(), " - "stub_->rpcmethod_$Method$_, " - "context, reactor);\n" - "}\n\n"); + printer->Print( + *vars, + " ::grpc_impl::internal::ClientCallbackReaderWriterFactory< " + "$Request$,$Response$>::Create(" + "stub_->channel_.get(), " + "stub_->rpcmethod_$Method$_, " + "context, reactor);\n" + "}\n\n"); for (auto async_prefix : async_prefixes) { (*vars)["AsyncPrefix"] = async_prefix.prefix; @@ -1888,7 +1894,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); printer->Print(*vars, " return " - "::grpc::internal::ClientAsyncReaderWriterFactory< " + "::grpc_impl::internal::ClientAsyncReaderWriterFactory< " "$Request$, $Response$>::Create(" "channel_.get(), cq, " "rpcmethod_$Method$_, " @@ -2279,7 +2285,8 @@ void PrintMockClientMethods(grpc_generator::Printer* printer, printer->Print( *vars, "MOCK_METHOD$MockArgs$($AsyncPrefix$$Method$Raw, " - "::grpc::ClientAsyncReaderWriterInterface<$Request$, $Response$>*" + "::grpc::ClientAsyncReaderWriterInterface<$Request$, " + "$Response$>*" "(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq" "$AsyncMethodParams$));\n"); } diff --git a/src/cpp/client/generic_stub.cc b/src/cpp/client/generic_stub.cc index 41631c794f2..e7d3df7a497 100644 --- a/src/cpp/client/generic_stub.cc +++ b/src/cpp/client/generic_stub.cc @@ -27,11 +27,10 @@ namespace grpc_impl { namespace { std::unique_ptr CallInternal( grpc::ChannelInterface* channel, grpc::ClientContext* context, - const grpc::string& method, grpc::CompletionQueue* cq, bool start, - void* tag) { + const grpc::string& method, CompletionQueue* cq, bool start, void* tag) { return std::unique_ptr( - grpc::internal::ClientAsyncReaderWriterFactory:: + internal::ClientAsyncReaderWriterFactory:: Create(channel, cq, grpc::internal::RpcMethod( method.c_str(), grpc::internal::RpcMethod::BIDI_STREAMING), @@ -43,14 +42,14 @@ std::unique_ptr CallInternal( // begin a call to a named method std::unique_ptr GenericStub::Call( grpc::ClientContext* context, const grpc::string& method, - grpc::CompletionQueue* cq, void* tag) { + CompletionQueue* cq, void* tag) { return CallInternal(channel_.get(), context, method, cq, true, tag); } // setup a call to a named method std::unique_ptr GenericStub::PrepareCall( grpc::ClientContext* context, const grpc::string& method, - grpc::CompletionQueue* cq) { + CompletionQueue* cq) { return CallInternal(channel_.get(), context, method, cq, false, nullptr); } @@ -59,21 +58,20 @@ std::unique_ptr GenericStub::PrepareUnaryCall(grpc::ClientContext* context, const grpc::string& method, const grpc::ByteBuffer& request, - grpc::CompletionQueue* cq) { + CompletionQueue* cq) { return std::unique_ptr( - grpc::internal::ClientAsyncResponseReaderFactory< - grpc::ByteBuffer>::Create(channel_.get(), cq, - grpc::internal::RpcMethod( - method.c_str(), - grpc::internal::RpcMethod::NORMAL_RPC), - context, request, false)); + internal::ClientAsyncResponseReaderFactory::Create( + channel_.get(), cq, + grpc::internal::RpcMethod(method.c_str(), + grpc::internal::RpcMethod::NORMAL_RPC), + context, request, false)); } void GenericStub::experimental_type::UnaryCall( grpc::ClientContext* context, const grpc::string& method, const grpc::ByteBuffer* request, grpc::ByteBuffer* response, std::function on_completion) { - grpc::internal::CallbackUnaryCall( + internal::CallbackUnaryCall( stub_->channel_.get(), grpc::internal::RpcMethod(method.c_str(), grpc::internal::RpcMethod::NORMAL_RPC), @@ -82,9 +80,9 @@ void GenericStub::experimental_type::UnaryCall( void GenericStub::experimental_type::PrepareBidiStreamingCall( grpc::ClientContext* context, const grpc::string& method, - grpc::experimental::ClientBidiReactor* + experimental::ClientBidiReactor* reactor) { - grpc::internal::ClientCallbackReaderWriterFactory< + internal::ClientCallbackReaderWriterFactory< grpc::ByteBuffer, grpc::ByteBuffer>::Create(stub_->channel_.get(), grpc::internal::RpcMethod( diff --git a/src/cpp/server/async_generic_service.cc b/src/cpp/server/async_generic_service.cc index 30613768295..556447a7f40 100644 --- a/src/cpp/server/async_generic_service.cc +++ b/src/cpp/server/async_generic_service.cc @@ -24,8 +24,8 @@ namespace grpc { void AsyncGenericService::RequestCall( GenericServerContext* ctx, GenericServerAsyncReaderWriter* reader_writer, - CompletionQueue* call_cq, ServerCompletionQueue* notification_cq, - void* tag) { + ::grpc_impl::CompletionQueue* call_cq, + ::grpc_impl::ServerCompletionQueue* notification_cq, void* tag) { server_->RequestAsyncGenericCall(ctx, reader_writer, call_cq, notification_cq, tag); } diff --git a/src/cpp/server/health/default_health_check_service.h b/src/cpp/server/health/default_health_check_service.h index 4b926efdfe8..14a54d53ee0 100644 --- a/src/cpp/server/health/default_health_check_service.h +++ b/src/cpp/server/health/default_health_check_service.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include diff --git a/src/cpp/server/server_builder.cc b/src/cpp/server/server_builder.cc index 1ba9ae1c9dc..1d68c2bdaea 100644 --- a/src/cpp/server/server_builder.cc +++ b/src/cpp/server/server_builder.cc @@ -69,14 +69,14 @@ ServerBuilder::~ServerBuilder() { } } -std::unique_ptr ServerBuilder::AddCompletionQueue( +std::unique_ptr ServerBuilder::AddCompletionQueue( bool is_frequently_polled) { - grpc::ServerCompletionQueue* cq = new grpc::ServerCompletionQueue( + ServerCompletionQueue* cq = new ServerCompletionQueue( GRPC_CQ_NEXT, is_frequently_polled ? GRPC_CQ_DEFAULT_POLLING : GRPC_CQ_NON_LISTENING, nullptr); cqs_.push_back(cq); - return std::unique_ptr(cq); + return std::unique_ptr(cq); } ServerBuilder& ServerBuilder::RegisterService(grpc::Service* service) { @@ -266,10 +266,9 @@ std::unique_ptr ServerBuilder::BuildAndStart() { // This is different from the completion queues added to the server via // ServerBuilder's AddCompletionQueue() method (those completion queues // are in 'cqs_' member variable of ServerBuilder object) - std::shared_ptr>> - sync_server_cqs( - std::make_shared< - std::vector>>()); + std::shared_ptr>> + sync_server_cqs(std::make_shared< + std::vector>>()); bool has_frequently_polled_cqs = false; for (auto it = cqs_.begin(); it != cqs_.end(); ++it) { @@ -298,7 +297,7 @@ std::unique_ptr ServerBuilder::BuildAndStart() { // Create completion queues to listen to incoming rpc requests for (int i = 0; i < sync_server_settings_.num_cqs; i++) { sync_server_cqs->emplace_back( - new grpc::ServerCompletionQueue(GRPC_CQ_NEXT, polling_type, nullptr)); + new ServerCompletionQueue(GRPC_CQ_NEXT, polling_type, nullptr)); } } diff --git a/src/cpp/server/server_context.cc b/src/cpp/server/server_context.cc index ba834237ae9..1e27fad3988 100644 --- a/src/cpp/server/server_context.cc +++ b/src/cpp/server/server_context.cc @@ -45,8 +45,7 @@ class ServerContext::CompletionOp final public: // initial refs: one in the server context, one in the cq // must ref the call before calling constructor and after deleting this - CompletionOp(::grpc::internal::Call* call, - ::grpc::internal::ServerReactor* reactor) + CompletionOp(::grpc::internal::Call* call, internal::ServerReactor* reactor) : call_(*call), reactor_(reactor), has_tag_(false), @@ -152,7 +151,7 @@ class ServerContext::CompletionOp final } ::grpc::internal::Call call_; - ::grpc::internal::ServerReactor* const reactor_; + internal::ServerReactor* const reactor_; bool has_tag_; void* tag_; void* core_cq_tag_; @@ -294,9 +293,9 @@ void ServerContext::Clear() { } } -void ServerContext::BeginCompletionOp( - ::grpc::internal::Call* call, std::function callback, - ::grpc::internal::ServerReactor* reactor) { +void ServerContext::BeginCompletionOp(::grpc::internal::Call* call, + std::function callback, + internal::ServerReactor* reactor) { GPR_ASSERT(!completion_op_); if (rpc_info_) { rpc_info_->Ref(); diff --git a/test/cpp/codegen/compiler_test_golden b/test/cpp/codegen/compiler_test_golden index 035955023b8..34fb5bfb53f 100644 --- a/test/cpp/codegen/compiler_test_golden +++ b/test/cpp/codegen/compiler_test_golden @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -336,7 +337,7 @@ class ServiceA final { public: ExperimentalWithCallbackMethod_MethodA1() { ::grpc::Service::experimental().MarkMethodCallback(0, - new ::grpc::internal::CallbackUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>( + new ::grpc_impl::internal::CallbackUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>( [this](::grpc::ServerContext* context, const ::grpc::testing::Request* request, ::grpc::testing::Response* response, @@ -346,7 +347,7 @@ class ServiceA final { } void SetMessageAllocatorFor_MethodA1( ::grpc::experimental::MessageAllocator< ::grpc::testing::Request, ::grpc::testing::Response>* allocator) { - static_cast<::grpc::internal::CallbackUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>*>( + static_cast<::grpc_impl::internal::CallbackUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>*>( ::grpc::Service::experimental().GetHandler(0)) ->SetMessageAllocator(allocator); } @@ -367,7 +368,7 @@ class ServiceA final { public: ExperimentalWithCallbackMethod_MethodA2() { ::grpc::Service::experimental().MarkMethodCallback(1, - new ::grpc::internal::CallbackClientStreamingHandler< ::grpc::testing::Request, ::grpc::testing::Response>( + new ::grpc_impl::internal::CallbackClientStreamingHandler< ::grpc::testing::Request, ::grpc::testing::Response>( [this] { return this->MethodA2(); })); } ~ExperimentalWithCallbackMethod_MethodA2() override { @@ -379,7 +380,7 @@ class ServiceA final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } virtual ::grpc::experimental::ServerReadReactor< ::grpc::testing::Request, ::grpc::testing::Response>* MethodA2() { - return new ::grpc::internal::UnimplementedReadReactor< + return new ::grpc_impl::internal::UnimplementedReadReactor< ::grpc::testing::Request, ::grpc::testing::Response>;} }; template @@ -389,7 +390,7 @@ class ServiceA final { public: ExperimentalWithCallbackMethod_MethodA3() { ::grpc::Service::experimental().MarkMethodCallback(2, - new ::grpc::internal::CallbackServerStreamingHandler< ::grpc::testing::Request, ::grpc::testing::Response>( + new ::grpc_impl::internal::CallbackServerStreamingHandler< ::grpc::testing::Request, ::grpc::testing::Response>( [this] { return this->MethodA3(); })); } ~ExperimentalWithCallbackMethod_MethodA3() override { @@ -401,7 +402,7 @@ class ServiceA final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } virtual ::grpc::experimental::ServerWriteReactor< ::grpc::testing::Request, ::grpc::testing::Response>* MethodA3() { - return new ::grpc::internal::UnimplementedWriteReactor< + return new ::grpc_impl::internal::UnimplementedWriteReactor< ::grpc::testing::Request, ::grpc::testing::Response>;} }; template @@ -411,7 +412,7 @@ class ServiceA final { public: ExperimentalWithCallbackMethod_MethodA4() { ::grpc::Service::experimental().MarkMethodCallback(3, - new ::grpc::internal::CallbackBidiHandler< ::grpc::testing::Request, ::grpc::testing::Response>( + new ::grpc_impl::internal::CallbackBidiHandler< ::grpc::testing::Request, ::grpc::testing::Response>( [this] { return this->MethodA4(); })); } ~ExperimentalWithCallbackMethod_MethodA4() override { @@ -423,7 +424,7 @@ class ServiceA final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } virtual ::grpc::experimental::ServerBidiReactor< ::grpc::testing::Request, ::grpc::testing::Response>* MethodA4() { - return new ::grpc::internal::UnimplementedBidiReactor< + return new ::grpc_impl::internal::UnimplementedBidiReactor< ::grpc::testing::Request, ::grpc::testing::Response>;} }; typedef ExperimentalWithCallbackMethod_MethodA1 > > > ExperimentalCallbackService; @@ -582,7 +583,7 @@ class ServiceA final { public: ExperimentalWithRawCallbackMethod_MethodA1() { ::grpc::Service::experimental().MarkMethodRawCallback(0, - new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( + new ::grpc_impl::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this](::grpc::ServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response, @@ -607,7 +608,7 @@ class ServiceA final { public: ExperimentalWithRawCallbackMethod_MethodA2() { ::grpc::Service::experimental().MarkMethodRawCallback(1, - new ::grpc::internal::CallbackClientStreamingHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( + new ::grpc_impl::internal::CallbackClientStreamingHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this] { return this->MethodA2(); })); } ~ExperimentalWithRawCallbackMethod_MethodA2() override { @@ -619,7 +620,7 @@ class ServiceA final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } virtual ::grpc::experimental::ServerReadReactor< ::grpc::ByteBuffer, ::grpc::ByteBuffer>* MethodA2() { - return new ::grpc::internal::UnimplementedReadReactor< + return new ::grpc_impl::internal::UnimplementedReadReactor< ::grpc::ByteBuffer, ::grpc::ByteBuffer>;} }; template @@ -629,7 +630,7 @@ class ServiceA final { public: ExperimentalWithRawCallbackMethod_MethodA3() { ::grpc::Service::experimental().MarkMethodRawCallback(2, - new ::grpc::internal::CallbackServerStreamingHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( + new ::grpc_impl::internal::CallbackServerStreamingHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this] { return this->MethodA3(); })); } ~ExperimentalWithRawCallbackMethod_MethodA3() override { @@ -641,7 +642,7 @@ class ServiceA final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } virtual ::grpc::experimental::ServerWriteReactor< ::grpc::ByteBuffer, ::grpc::ByteBuffer>* MethodA3() { - return new ::grpc::internal::UnimplementedWriteReactor< + return new ::grpc_impl::internal::UnimplementedWriteReactor< ::grpc::ByteBuffer, ::grpc::ByteBuffer>;} }; template @@ -651,7 +652,7 @@ class ServiceA final { public: ExperimentalWithRawCallbackMethod_MethodA4() { ::grpc::Service::experimental().MarkMethodRawCallback(3, - new ::grpc::internal::CallbackBidiHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( + new ::grpc_impl::internal::CallbackBidiHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this] { return this->MethodA4(); })); } ~ExperimentalWithRawCallbackMethod_MethodA4() override { @@ -663,7 +664,7 @@ class ServiceA final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } virtual ::grpc::experimental::ServerBidiReactor< ::grpc::ByteBuffer, ::grpc::ByteBuffer>* MethodA4() { - return new ::grpc::internal::UnimplementedBidiReactor< + return new ::grpc_impl::internal::UnimplementedBidiReactor< ::grpc::ByteBuffer, ::grpc::ByteBuffer>;} }; template @@ -814,7 +815,7 @@ class ServiceB final { public: ExperimentalWithCallbackMethod_MethodB1() { ::grpc::Service::experimental().MarkMethodCallback(0, - new ::grpc::internal::CallbackUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>( + new ::grpc_impl::internal::CallbackUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>( [this](::grpc::ServerContext* context, const ::grpc::testing::Request* request, ::grpc::testing::Response* response, @@ -824,7 +825,7 @@ class ServiceB final { } void SetMessageAllocatorFor_MethodB1( ::grpc::experimental::MessageAllocator< ::grpc::testing::Request, ::grpc::testing::Response>* allocator) { - static_cast<::grpc::internal::CallbackUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>*>( + static_cast<::grpc_impl::internal::CallbackUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>*>( ::grpc::Service::experimental().GetHandler(0)) ->SetMessageAllocator(allocator); } @@ -883,7 +884,7 @@ class ServiceB final { public: ExperimentalWithRawCallbackMethod_MethodB1() { ::grpc::Service::experimental().MarkMethodRawCallback(0, - new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( + new ::grpc_impl::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this](::grpc::ServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response, diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++ index 501be844410..bdb36ae1a7b 100644 --- a/tools/doxygen/Doxyfile.c++ +++ b/tools/doxygen/Doxyfile.c++ @@ -947,7 +947,9 @@ include/grpcpp/impl/channel_argument_option.h \ include/grpcpp/impl/client_unary_call.h \ include/grpcpp/impl/codegen/async_generic_service.h \ include/grpcpp/impl/codegen/async_stream.h \ +include/grpcpp/impl/codegen/async_stream_impl.h \ include/grpcpp/impl/codegen/async_unary_call.h \ +include/grpcpp/impl/codegen/async_unary_call_impl.h \ include/grpcpp/impl/codegen/byte_buffer.h \ include/grpcpp/impl/codegen/call.h \ include/grpcpp/impl/codegen/call_hook.h \ @@ -956,6 +958,7 @@ include/grpcpp/impl/codegen/call_op_set_interface.h \ include/grpcpp/impl/codegen/callback_common.h \ include/grpcpp/impl/codegen/channel_interface.h \ include/grpcpp/impl/codegen/client_callback.h \ +include/grpcpp/impl/codegen/client_callback_impl.h \ include/grpcpp/impl/codegen/client_context.h \ include/grpcpp/impl/codegen/client_context_impl.h \ include/grpcpp/impl/codegen/client_interceptor.h \ @@ -983,6 +986,7 @@ include/grpcpp/impl/codegen/rpc_service_method.h \ include/grpcpp/impl/codegen/security/auth_context.h \ include/grpcpp/impl/codegen/serialization_traits.h \ include/grpcpp/impl/codegen/server_callback.h \ +include/grpcpp/impl/codegen/server_callback_impl.h \ include/grpcpp/impl/codegen/server_context.h \ include/grpcpp/impl/codegen/server_context_impl.h \ include/grpcpp/impl/codegen/server_interceptor.h \ @@ -995,6 +999,7 @@ include/grpcpp/impl/codegen/string_ref.h \ include/grpcpp/impl/codegen/stub_options.h \ include/grpcpp/impl/codegen/sync.h \ include/grpcpp/impl/codegen/sync_stream.h \ +include/grpcpp/impl/codegen/sync_stream_impl.h \ include/grpcpp/impl/codegen/time.h \ include/grpcpp/impl/grpc_library.h \ include/grpcpp/impl/method_handler_impl.h \ @@ -1024,11 +1029,14 @@ include/grpcpp/server_impl.h \ include/grpcpp/server_posix.h \ include/grpcpp/server_posix_impl.h \ include/grpcpp/support/async_stream.h \ +include/grpcpp/support/async_stream_impl.h \ include/grpcpp/support/async_unary_call.h \ +include/grpcpp/support/async_unary_call_impl.h \ include/grpcpp/support/byte_buffer.h \ include/grpcpp/support/channel_arguments.h \ include/grpcpp/support/channel_arguments_impl.h \ include/grpcpp/support/client_callback.h \ +include/grpcpp/support/client_callback_impl.h \ include/grpcpp/support/client_interceptor.h \ include/grpcpp/support/config.h \ include/grpcpp/support/interceptor.h \ @@ -1036,6 +1044,7 @@ 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 \ +include/grpcpp/support/server_callback_impl.h \ include/grpcpp/support/server_interceptor.h \ include/grpcpp/support/slice.h \ include/grpcpp/support/status.h \ @@ -1043,6 +1052,7 @@ include/grpcpp/support/status_code_enum.h \ include/grpcpp/support/string_ref.h \ include/grpcpp/support/stub_options.h \ include/grpcpp/support/sync_stream.h \ +include/grpcpp/support/sync_stream_impl.h \ include/grpcpp/support/time.h \ include/grpcpp/support/validate_service_config.h diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index f1dd2e54e1d..1abe2523b3c 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -948,7 +948,9 @@ include/grpcpp/impl/channel_argument_option.h \ include/grpcpp/impl/client_unary_call.h \ include/grpcpp/impl/codegen/async_generic_service.h \ include/grpcpp/impl/codegen/async_stream.h \ +include/grpcpp/impl/codegen/async_stream_impl.h \ include/grpcpp/impl/codegen/async_unary_call.h \ +include/grpcpp/impl/codegen/async_unary_call_impl.h \ include/grpcpp/impl/codegen/byte_buffer.h \ include/grpcpp/impl/codegen/call.h \ include/grpcpp/impl/codegen/call_hook.h \ @@ -957,6 +959,7 @@ include/grpcpp/impl/codegen/call_op_set_interface.h \ include/grpcpp/impl/codegen/callback_common.h \ include/grpcpp/impl/codegen/channel_interface.h \ include/grpcpp/impl/codegen/client_callback.h \ +include/grpcpp/impl/codegen/client_callback_impl.h \ include/grpcpp/impl/codegen/client_context.h \ include/grpcpp/impl/codegen/client_context_impl.h \ include/grpcpp/impl/codegen/client_interceptor.h \ @@ -985,6 +988,7 @@ include/grpcpp/impl/codegen/rpc_service_method.h \ include/grpcpp/impl/codegen/security/auth_context.h \ include/grpcpp/impl/codegen/serialization_traits.h \ include/grpcpp/impl/codegen/server_callback.h \ +include/grpcpp/impl/codegen/server_callback_impl.h \ include/grpcpp/impl/codegen/server_context.h \ include/grpcpp/impl/codegen/server_context_impl.h \ include/grpcpp/impl/codegen/server_interceptor.h \ @@ -997,6 +1001,7 @@ include/grpcpp/impl/codegen/string_ref.h \ include/grpcpp/impl/codegen/stub_options.h \ include/grpcpp/impl/codegen/sync.h \ include/grpcpp/impl/codegen/sync_stream.h \ +include/grpcpp/impl/codegen/sync_stream_impl.h \ include/grpcpp/impl/codegen/time.h \ include/grpcpp/impl/grpc_library.h \ include/grpcpp/impl/method_handler_impl.h \ @@ -1026,11 +1031,14 @@ include/grpcpp/server_impl.h \ include/grpcpp/server_posix.h \ include/grpcpp/server_posix_impl.h \ include/grpcpp/support/async_stream.h \ +include/grpcpp/support/async_stream_impl.h \ include/grpcpp/support/async_unary_call.h \ +include/grpcpp/support/async_unary_call_impl.h \ include/grpcpp/support/byte_buffer.h \ include/grpcpp/support/channel_arguments.h \ include/grpcpp/support/channel_arguments_impl.h \ include/grpcpp/support/client_callback.h \ +include/grpcpp/support/client_callback_impl.h \ include/grpcpp/support/client_interceptor.h \ include/grpcpp/support/config.h \ include/grpcpp/support/interceptor.h \ @@ -1038,6 +1046,7 @@ 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 \ +include/grpcpp/support/server_callback_impl.h \ include/grpcpp/support/server_interceptor.h \ include/grpcpp/support/slice.h \ include/grpcpp/support/status.h \ @@ -1045,6 +1054,7 @@ include/grpcpp/support/status_code_enum.h \ include/grpcpp/support/string_ref.h \ include/grpcpp/support/stub_options.h \ include/grpcpp/support/sync_stream.h \ +include/grpcpp/support/sync_stream_impl.h \ include/grpcpp/support/time.h \ include/grpcpp/support/validate_service_config.h \ src/core/ext/filters/client_channel/health/health.pb.c \ diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index d263e4fed22..51cb18b0932 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -10170,7 +10170,9 @@ "include/grpc++/impl/codegen/time.h", "include/grpcpp/impl/codegen/async_generic_service.h", "include/grpcpp/impl/codegen/async_stream.h", + "include/grpcpp/impl/codegen/async_stream_impl.h", "include/grpcpp/impl/codegen/async_unary_call.h", + "include/grpcpp/impl/codegen/async_unary_call_impl.h", "include/grpcpp/impl/codegen/byte_buffer.h", "include/grpcpp/impl/codegen/call.h", "include/grpcpp/impl/codegen/call_hook.h", @@ -10179,6 +10181,7 @@ "include/grpcpp/impl/codegen/callback_common.h", "include/grpcpp/impl/codegen/channel_interface.h", "include/grpcpp/impl/codegen/client_callback.h", + "include/grpcpp/impl/codegen/client_callback_impl.h", "include/grpcpp/impl/codegen/client_context.h", "include/grpcpp/impl/codegen/client_context_impl.h", "include/grpcpp/impl/codegen/client_interceptor.h", @@ -10201,6 +10204,7 @@ "include/grpcpp/impl/codegen/security/auth_context.h", "include/grpcpp/impl/codegen/serialization_traits.h", "include/grpcpp/impl/codegen/server_callback.h", + "include/grpcpp/impl/codegen/server_callback_impl.h", "include/grpcpp/impl/codegen/server_context.h", "include/grpcpp/impl/codegen/server_context_impl.h", "include/grpcpp/impl/codegen/server_interceptor.h", @@ -10212,6 +10216,7 @@ "include/grpcpp/impl/codegen/string_ref.h", "include/grpcpp/impl/codegen/stub_options.h", "include/grpcpp/impl/codegen/sync_stream.h", + "include/grpcpp/impl/codegen/sync_stream_impl.h", "include/grpcpp/impl/codegen/time.h" ], "is_filegroup": true, @@ -10250,7 +10255,9 @@ "include/grpc++/impl/codegen/time.h", "include/grpcpp/impl/codegen/async_generic_service.h", "include/grpcpp/impl/codegen/async_stream.h", + "include/grpcpp/impl/codegen/async_stream_impl.h", "include/grpcpp/impl/codegen/async_unary_call.h", + "include/grpcpp/impl/codegen/async_unary_call_impl.h", "include/grpcpp/impl/codegen/byte_buffer.h", "include/grpcpp/impl/codegen/call.h", "include/grpcpp/impl/codegen/call_hook.h", @@ -10259,6 +10266,7 @@ "include/grpcpp/impl/codegen/callback_common.h", "include/grpcpp/impl/codegen/channel_interface.h", "include/grpcpp/impl/codegen/client_callback.h", + "include/grpcpp/impl/codegen/client_callback_impl.h", "include/grpcpp/impl/codegen/client_context.h", "include/grpcpp/impl/codegen/client_context_impl.h", "include/grpcpp/impl/codegen/client_interceptor.h", @@ -10281,6 +10289,7 @@ "include/grpcpp/impl/codegen/security/auth_context.h", "include/grpcpp/impl/codegen/serialization_traits.h", "include/grpcpp/impl/codegen/server_callback.h", + "include/grpcpp/impl/codegen/server_callback_impl.h", "include/grpcpp/impl/codegen/server_context.h", "include/grpcpp/impl/codegen/server_context_impl.h", "include/grpcpp/impl/codegen/server_interceptor.h", @@ -10292,6 +10301,7 @@ "include/grpcpp/impl/codegen/string_ref.h", "include/grpcpp/impl/codegen/stub_options.h", "include/grpcpp/impl/codegen/sync_stream.h", + "include/grpcpp/impl/codegen/sync_stream_impl.h", "include/grpcpp/impl/codegen/time.h" ], "third_party": false, @@ -10441,11 +10451,14 @@ "include/grpcpp/server_posix.h", "include/grpcpp/server_posix_impl.h", "include/grpcpp/support/async_stream.h", + "include/grpcpp/support/async_stream_impl.h", "include/grpcpp/support/async_unary_call.h", + "include/grpcpp/support/async_unary_call_impl.h", "include/grpcpp/support/byte_buffer.h", "include/grpcpp/support/channel_arguments.h", "include/grpcpp/support/channel_arguments_impl.h", "include/grpcpp/support/client_callback.h", + "include/grpcpp/support/client_callback_impl.h", "include/grpcpp/support/client_interceptor.h", "include/grpcpp/support/config.h", "include/grpcpp/support/interceptor.h", @@ -10453,6 +10466,7 @@ "include/grpcpp/support/proto_buffer_reader.h", "include/grpcpp/support/proto_buffer_writer.h", "include/grpcpp/support/server_callback.h", + "include/grpcpp/support/server_callback_impl.h", "include/grpcpp/support/server_interceptor.h", "include/grpcpp/support/slice.h", "include/grpcpp/support/status.h", @@ -10460,6 +10474,7 @@ "include/grpcpp/support/string_ref.h", "include/grpcpp/support/stub_options.h", "include/grpcpp/support/sync_stream.h", + "include/grpcpp/support/sync_stream_impl.h", "include/grpcpp/support/time.h", "include/grpcpp/support/validate_service_config.h", "src/cpp/client/create_channel_internal.h", @@ -10569,11 +10584,14 @@ "include/grpcpp/server_posix.h", "include/grpcpp/server_posix_impl.h", "include/grpcpp/support/async_stream.h", + "include/grpcpp/support/async_stream_impl.h", "include/grpcpp/support/async_unary_call.h", + "include/grpcpp/support/async_unary_call_impl.h", "include/grpcpp/support/byte_buffer.h", "include/grpcpp/support/channel_arguments.h", "include/grpcpp/support/channel_arguments_impl.h", "include/grpcpp/support/client_callback.h", + "include/grpcpp/support/client_callback_impl.h", "include/grpcpp/support/client_interceptor.h", "include/grpcpp/support/config.h", "include/grpcpp/support/interceptor.h", @@ -10581,6 +10599,7 @@ "include/grpcpp/support/proto_buffer_reader.h", "include/grpcpp/support/proto_buffer_writer.h", "include/grpcpp/support/server_callback.h", + "include/grpcpp/support/server_callback_impl.h", "include/grpcpp/support/server_interceptor.h", "include/grpcpp/support/slice.h", "include/grpcpp/support/status.h", @@ -10588,6 +10607,7 @@ "include/grpcpp/support/string_ref.h", "include/grpcpp/support/stub_options.h", "include/grpcpp/support/sync_stream.h", + "include/grpcpp/support/sync_stream_impl.h", "include/grpcpp/support/time.h", "include/grpcpp/support/validate_service_config.h", "src/cpp/client/channel_cc.cc", From bf994e48d90679f8571ba69781d9d5a31037f34b Mon Sep 17 00:00:00 2001 From: Moiz Haidry Date: Mon, 1 Jul 2019 10:38:23 -0700 Subject: [PATCH 2/4] Move grpc async, callback and sync implementation to grpc_impl namespace --- BUILD | 10 + BUILD.gn | 10 + CMakeLists.txt | 40 + Makefile | 40 + build.yaml | 10 + gRPC-C++.podspec | 10 + include/grpcpp/channel_impl.h | 13 +- include/grpcpp/generic/generic_stub_impl.h | 41 +- .../impl/codegen/async_generic_service.h | 28 +- include/grpcpp/impl/codegen/async_stream.h | 1102 +-------------- .../grpcpp/impl/codegen/async_stream_impl.h | 1134 ++++++++++++++++ .../grpcpp/impl/codegen/async_unary_call.h | 291 +--- .../impl/codegen/async_unary_call_impl.h | 315 +++++ include/grpcpp/impl/codegen/byte_buffer.h | 19 +- include/grpcpp/impl/codegen/call_op_set.h | 2 +- .../grpcpp/impl/codegen/channel_interface.h | 47 +- include/grpcpp/impl/codegen/client_callback.h | 1003 +------------- .../impl/codegen/client_callback_impl.h | 1067 +++++++++++++++ .../grpcpp/impl/codegen/client_context_impl.h | 52 +- .../grpcpp/impl/codegen/client_unary_call.h | 4 +- .../impl/codegen/completion_queue_impl.h | 17 +- include/grpcpp/impl/codegen/server_callback.h | 1133 +--------------- .../impl/codegen/server_callback_impl.h | 1186 +++++++++++++++++ .../grpcpp/impl/codegen/server_context_impl.h | 54 +- include/grpcpp/impl/codegen/service_type.h | 20 +- include/grpcpp/impl/codegen/sync_stream.h | 914 +------------ .../grpcpp/impl/codegen/sync_stream_impl.h | 944 +++++++++++++ include/grpcpp/support/async_stream_impl.h | 24 + .../grpcpp/support/async_unary_call_impl.h | 24 + include/grpcpp/support/client_callback_impl.h | 24 + include/grpcpp/support/server_callback_impl.h | 24 + include/grpcpp/support/sync_stream_impl.h | 24 + src/compiler/cpp_generator.cc | 121 +- src/cpp/client/generic_stub.cc | 30 +- src/cpp/server/async_generic_service.cc | 4 +- .../health/default_health_check_service.h | 1 + src/cpp/server/server_builder.cc | 15 +- src/cpp/server/server_context.cc | 11 +- test/cpp/codegen/compiler_test_golden | 37 +- tools/doxygen/Doxyfile.c++ | 10 + tools/doxygen/Doxyfile.c++.internal | 10 + .../generated/sources_and_headers.json | 20 + 42 files changed, 5258 insertions(+), 4627 deletions(-) create mode 100644 include/grpcpp/impl/codegen/async_stream_impl.h create mode 100644 include/grpcpp/impl/codegen/async_unary_call_impl.h create mode 100644 include/grpcpp/impl/codegen/client_callback_impl.h create mode 100644 include/grpcpp/impl/codegen/server_callback_impl.h create mode 100644 include/grpcpp/impl/codegen/sync_stream_impl.h create mode 100644 include/grpcpp/support/async_stream_impl.h create mode 100644 include/grpcpp/support/async_unary_call_impl.h create mode 100644 include/grpcpp/support/client_callback_impl.h create mode 100644 include/grpcpp/support/server_callback_impl.h create mode 100644 include/grpcpp/support/sync_stream_impl.h diff --git a/BUILD b/BUILD index f7c97beaaaf..851e5011006 100644 --- a/BUILD +++ b/BUILD @@ -268,11 +268,14 @@ GRPCXX_PUBLIC_HDRS = [ "include/grpcpp/server_posix.h", "include/grpcpp/server_posix_impl.h", "include/grpcpp/support/async_stream.h", + "include/grpcpp/support/async_stream_impl.h", "include/grpcpp/support/async_unary_call.h", + "include/grpcpp/support/async_unary_call_impl.h", "include/grpcpp/support/byte_buffer.h", "include/grpcpp/support/channel_arguments.h", "include/grpcpp/support/channel_arguments_impl.h", "include/grpcpp/support/client_callback.h", + "include/grpcpp/support/client_callback_impl.h", "include/grpcpp/support/client_interceptor.h", "include/grpcpp/support/config.h", "include/grpcpp/support/interceptor.h", @@ -280,6 +283,7 @@ GRPCXX_PUBLIC_HDRS = [ "include/grpcpp/support/proto_buffer_reader.h", "include/grpcpp/support/proto_buffer_writer.h", "include/grpcpp/support/server_callback.h", + "include/grpcpp/support/server_callback_impl.h", "include/grpcpp/support/server_interceptor.h", "include/grpcpp/support/slice.h", "include/grpcpp/support/status.h", @@ -287,6 +291,7 @@ GRPCXX_PUBLIC_HDRS = [ "include/grpcpp/support/string_ref.h", "include/grpcpp/support/stub_options.h", "include/grpcpp/support/sync_stream.h", + "include/grpcpp/support/sync_stream_impl.h", "include/grpcpp/support/time.h", "include/grpcpp/support/validate_service_config.h", ] @@ -2157,7 +2162,9 @@ grpc_cc_library( "include/grpc++/impl/codegen/time.h", "include/grpcpp/impl/codegen/async_generic_service.h", "include/grpcpp/impl/codegen/async_stream.h", + "include/grpcpp/impl/codegen/async_stream_impl.h", "include/grpcpp/impl/codegen/async_unary_call.h", + "include/grpcpp/impl/codegen/async_unary_call_impl.h", "include/grpcpp/impl/codegen/byte_buffer.h", "include/grpcpp/impl/codegen/call.h", "include/grpcpp/impl/codegen/call_hook.h", @@ -2166,6 +2173,7 @@ grpc_cc_library( "include/grpcpp/impl/codegen/callback_common.h", "include/grpcpp/impl/codegen/channel_interface.h", "include/grpcpp/impl/codegen/client_callback.h", + "include/grpcpp/impl/codegen/client_callback_impl.h", "include/grpcpp/impl/codegen/client_context.h", "include/grpcpp/impl/codegen/client_context_impl.h", "include/grpcpp/impl/codegen/client_interceptor.h", @@ -2188,6 +2196,7 @@ grpc_cc_library( "include/grpcpp/impl/codegen/security/auth_context.h", "include/grpcpp/impl/codegen/serialization_traits.h", "include/grpcpp/impl/codegen/server_callback.h", + "include/grpcpp/impl/codegen/server_callback_impl.h", "include/grpcpp/impl/codegen/server_context.h", "include/grpcpp/impl/codegen/server_context_impl.h", "include/grpcpp/impl/codegen/server_interceptor.h", @@ -2199,6 +2208,7 @@ grpc_cc_library( "include/grpcpp/impl/codegen/string_ref.h", "include/grpcpp/impl/codegen/stub_options.h", "include/grpcpp/impl/codegen/sync_stream.h", + "include/grpcpp/impl/codegen/sync_stream_impl.h", "include/grpcpp/impl/codegen/time.h", ], deps = [ diff --git a/BUILD.gn b/BUILD.gn index 08625e9bd12..940c9b25c72 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1046,7 +1046,9 @@ config("grpc_config") { "include/grpcpp/impl/client_unary_call.h", "include/grpcpp/impl/codegen/async_generic_service.h", "include/grpcpp/impl/codegen/async_stream.h", + "include/grpcpp/impl/codegen/async_stream_impl.h", "include/grpcpp/impl/codegen/async_unary_call.h", + "include/grpcpp/impl/codegen/async_unary_call_impl.h", "include/grpcpp/impl/codegen/byte_buffer.h", "include/grpcpp/impl/codegen/call.h", "include/grpcpp/impl/codegen/call_hook.h", @@ -1055,6 +1057,7 @@ config("grpc_config") { "include/grpcpp/impl/codegen/callback_common.h", "include/grpcpp/impl/codegen/channel_interface.h", "include/grpcpp/impl/codegen/client_callback.h", + "include/grpcpp/impl/codegen/client_callback_impl.h", "include/grpcpp/impl/codegen/client_context.h", "include/grpcpp/impl/codegen/client_context_impl.h", "include/grpcpp/impl/codegen/client_interceptor.h", @@ -1083,6 +1086,7 @@ config("grpc_config") { "include/grpcpp/impl/codegen/security/auth_context.h", "include/grpcpp/impl/codegen/serialization_traits.h", "include/grpcpp/impl/codegen/server_callback.h", + "include/grpcpp/impl/codegen/server_callback_impl.h", "include/grpcpp/impl/codegen/server_context.h", "include/grpcpp/impl/codegen/server_context_impl.h", "include/grpcpp/impl/codegen/server_interceptor.h", @@ -1095,6 +1099,7 @@ config("grpc_config") { "include/grpcpp/impl/codegen/stub_options.h", "include/grpcpp/impl/codegen/sync.h", "include/grpcpp/impl/codegen/sync_stream.h", + "include/grpcpp/impl/codegen/sync_stream_impl.h", "include/grpcpp/impl/codegen/time.h", "include/grpcpp/impl/grpc_library.h", "include/grpcpp/impl/method_handler_impl.h", @@ -1124,11 +1129,14 @@ config("grpc_config") { "include/grpcpp/server_posix.h", "include/grpcpp/server_posix_impl.h", "include/grpcpp/support/async_stream.h", + "include/grpcpp/support/async_stream_impl.h", "include/grpcpp/support/async_unary_call.h", + "include/grpcpp/support/async_unary_call_impl.h", "include/grpcpp/support/byte_buffer.h", "include/grpcpp/support/channel_arguments.h", "include/grpcpp/support/channel_arguments_impl.h", "include/grpcpp/support/client_callback.h", + "include/grpcpp/support/client_callback_impl.h", "include/grpcpp/support/client_interceptor.h", "include/grpcpp/support/config.h", "include/grpcpp/support/interceptor.h", @@ -1136,6 +1144,7 @@ config("grpc_config") { "include/grpcpp/support/proto_buffer_reader.h", "include/grpcpp/support/proto_buffer_writer.h", "include/grpcpp/support/server_callback.h", + "include/grpcpp/support/server_callback_impl.h", "include/grpcpp/support/server_interceptor.h", "include/grpcpp/support/slice.h", "include/grpcpp/support/status.h", @@ -1143,6 +1152,7 @@ config("grpc_config") { "include/grpcpp/support/string_ref.h", "include/grpcpp/support/stub_options.h", "include/grpcpp/support/sync_stream.h", + "include/grpcpp/support/sync_stream_impl.h", "include/grpcpp/support/time.h", "include/grpcpp/support/validate_service_config.h", "src/core/ext/transport/inproc/inproc_transport.h", diff --git a/CMakeLists.txt b/CMakeLists.txt index 90737ecfe29..4653b8f6013 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3221,11 +3221,14 @@ foreach(_hdr include/grpcpp/server_posix.h include/grpcpp/server_posix_impl.h include/grpcpp/support/async_stream.h + include/grpcpp/support/async_stream_impl.h include/grpcpp/support/async_unary_call.h + include/grpcpp/support/async_unary_call_impl.h include/grpcpp/support/byte_buffer.h include/grpcpp/support/channel_arguments.h include/grpcpp/support/channel_arguments_impl.h include/grpcpp/support/client_callback.h + include/grpcpp/support/client_callback_impl.h include/grpcpp/support/client_interceptor.h include/grpcpp/support/config.h include/grpcpp/support/interceptor.h @@ -3233,6 +3236,7 @@ foreach(_hdr include/grpcpp/support/proto_buffer_reader.h include/grpcpp/support/proto_buffer_writer.h include/grpcpp/support/server_callback.h + include/grpcpp/support/server_callback_impl.h include/grpcpp/support/server_interceptor.h include/grpcpp/support/slice.h include/grpcpp/support/status.h @@ -3240,6 +3244,7 @@ foreach(_hdr include/grpcpp/support/string_ref.h include/grpcpp/support/stub_options.h include/grpcpp/support/sync_stream.h + include/grpcpp/support/sync_stream_impl.h include/grpcpp/support/time.h include/grpcpp/support/validate_service_config.h include/grpc/support/alloc.h @@ -3325,7 +3330,9 @@ foreach(_hdr include/grpc++/impl/codegen/time.h include/grpcpp/impl/codegen/async_generic_service.h include/grpcpp/impl/codegen/async_stream.h + include/grpcpp/impl/codegen/async_stream_impl.h include/grpcpp/impl/codegen/async_unary_call.h + include/grpcpp/impl/codegen/async_unary_call_impl.h include/grpcpp/impl/codegen/byte_buffer.h include/grpcpp/impl/codegen/call.h include/grpcpp/impl/codegen/call_hook.h @@ -3334,6 +3341,7 @@ foreach(_hdr include/grpcpp/impl/codegen/callback_common.h include/grpcpp/impl/codegen/channel_interface.h include/grpcpp/impl/codegen/client_callback.h + include/grpcpp/impl/codegen/client_callback_impl.h include/grpcpp/impl/codegen/client_context.h include/grpcpp/impl/codegen/client_context_impl.h include/grpcpp/impl/codegen/client_interceptor.h @@ -3356,6 +3364,7 @@ foreach(_hdr include/grpcpp/impl/codegen/security/auth_context.h include/grpcpp/impl/codegen/serialization_traits.h include/grpcpp/impl/codegen/server_callback.h + include/grpcpp/impl/codegen/server_callback_impl.h include/grpcpp/impl/codegen/server_context.h include/grpcpp/impl/codegen/server_context_impl.h include/grpcpp/impl/codegen/server_interceptor.h @@ -3367,6 +3376,7 @@ foreach(_hdr include/grpcpp/impl/codegen/string_ref.h include/grpcpp/impl/codegen/stub_options.h include/grpcpp/impl/codegen/sync_stream.h + include/grpcpp/impl/codegen/sync_stream_impl.h include/grpcpp/impl/codegen/time.h include/grpcpp/impl/codegen/sync.h include/grpc++/impl/codegen/proto_utils.h @@ -3846,11 +3856,14 @@ foreach(_hdr include/grpcpp/server_posix.h include/grpcpp/server_posix_impl.h include/grpcpp/support/async_stream.h + include/grpcpp/support/async_stream_impl.h include/grpcpp/support/async_unary_call.h + include/grpcpp/support/async_unary_call_impl.h include/grpcpp/support/byte_buffer.h include/grpcpp/support/channel_arguments.h include/grpcpp/support/channel_arguments_impl.h include/grpcpp/support/client_callback.h + include/grpcpp/support/client_callback_impl.h include/grpcpp/support/client_interceptor.h include/grpcpp/support/config.h include/grpcpp/support/interceptor.h @@ -3858,6 +3871,7 @@ foreach(_hdr include/grpcpp/support/proto_buffer_reader.h include/grpcpp/support/proto_buffer_writer.h include/grpcpp/support/server_callback.h + include/grpcpp/support/server_callback_impl.h include/grpcpp/support/server_interceptor.h include/grpcpp/support/slice.h include/grpcpp/support/status.h @@ -3865,6 +3879,7 @@ foreach(_hdr include/grpcpp/support/string_ref.h include/grpcpp/support/stub_options.h include/grpcpp/support/sync_stream.h + include/grpcpp/support/sync_stream_impl.h include/grpcpp/support/time.h include/grpcpp/support/validate_service_config.h include/grpc/support/alloc.h @@ -3950,7 +3965,9 @@ foreach(_hdr include/grpc++/impl/codegen/time.h include/grpcpp/impl/codegen/async_generic_service.h include/grpcpp/impl/codegen/async_stream.h + include/grpcpp/impl/codegen/async_stream_impl.h include/grpcpp/impl/codegen/async_unary_call.h + include/grpcpp/impl/codegen/async_unary_call_impl.h include/grpcpp/impl/codegen/byte_buffer.h include/grpcpp/impl/codegen/call.h include/grpcpp/impl/codegen/call_hook.h @@ -3959,6 +3976,7 @@ foreach(_hdr include/grpcpp/impl/codegen/callback_common.h include/grpcpp/impl/codegen/channel_interface.h include/grpcpp/impl/codegen/client_callback.h + include/grpcpp/impl/codegen/client_callback_impl.h include/grpcpp/impl/codegen/client_context.h include/grpcpp/impl/codegen/client_context_impl.h include/grpcpp/impl/codegen/client_interceptor.h @@ -3981,6 +3999,7 @@ foreach(_hdr include/grpcpp/impl/codegen/security/auth_context.h include/grpcpp/impl/codegen/serialization_traits.h include/grpcpp/impl/codegen/server_callback.h + include/grpcpp/impl/codegen/server_callback_impl.h include/grpcpp/impl/codegen/server_context.h include/grpcpp/impl/codegen/server_context_impl.h include/grpcpp/impl/codegen/server_interceptor.h @@ -3992,6 +4011,7 @@ foreach(_hdr include/grpcpp/impl/codegen/string_ref.h include/grpcpp/impl/codegen/stub_options.h include/grpcpp/impl/codegen/sync_stream.h + include/grpcpp/impl/codegen/sync_stream_impl.h include/grpcpp/impl/codegen/time.h include/grpcpp/impl/codegen/sync.h include/grpc/census.h @@ -4387,7 +4407,9 @@ foreach(_hdr include/grpc++/impl/codegen/time.h include/grpcpp/impl/codegen/async_generic_service.h include/grpcpp/impl/codegen/async_stream.h + include/grpcpp/impl/codegen/async_stream_impl.h include/grpcpp/impl/codegen/async_unary_call.h + include/grpcpp/impl/codegen/async_unary_call_impl.h include/grpcpp/impl/codegen/byte_buffer.h include/grpcpp/impl/codegen/call.h include/grpcpp/impl/codegen/call_hook.h @@ -4396,6 +4418,7 @@ foreach(_hdr include/grpcpp/impl/codegen/callback_common.h include/grpcpp/impl/codegen/channel_interface.h include/grpcpp/impl/codegen/client_callback.h + include/grpcpp/impl/codegen/client_callback_impl.h include/grpcpp/impl/codegen/client_context.h include/grpcpp/impl/codegen/client_context_impl.h include/grpcpp/impl/codegen/client_interceptor.h @@ -4418,6 +4441,7 @@ foreach(_hdr include/grpcpp/impl/codegen/security/auth_context.h include/grpcpp/impl/codegen/serialization_traits.h include/grpcpp/impl/codegen/server_callback.h + include/grpcpp/impl/codegen/server_callback_impl.h include/grpcpp/impl/codegen/server_context.h include/grpcpp/impl/codegen/server_context_impl.h include/grpcpp/impl/codegen/server_interceptor.h @@ -4429,6 +4453,7 @@ foreach(_hdr include/grpcpp/impl/codegen/string_ref.h include/grpcpp/impl/codegen/stub_options.h include/grpcpp/impl/codegen/sync_stream.h + include/grpcpp/impl/codegen/sync_stream_impl.h include/grpcpp/impl/codegen/time.h include/grpc/impl/codegen/byte_buffer.h include/grpc/impl/codegen/byte_buffer_reader.h @@ -4588,7 +4613,9 @@ foreach(_hdr include/grpc++/impl/codegen/time.h include/grpcpp/impl/codegen/async_generic_service.h include/grpcpp/impl/codegen/async_stream.h + include/grpcpp/impl/codegen/async_stream_impl.h include/grpcpp/impl/codegen/async_unary_call.h + include/grpcpp/impl/codegen/async_unary_call_impl.h include/grpcpp/impl/codegen/byte_buffer.h include/grpcpp/impl/codegen/call.h include/grpcpp/impl/codegen/call_hook.h @@ -4597,6 +4624,7 @@ foreach(_hdr include/grpcpp/impl/codegen/callback_common.h include/grpcpp/impl/codegen/channel_interface.h include/grpcpp/impl/codegen/client_callback.h + include/grpcpp/impl/codegen/client_callback_impl.h include/grpcpp/impl/codegen/client_context.h include/grpcpp/impl/codegen/client_context_impl.h include/grpcpp/impl/codegen/client_interceptor.h @@ -4619,6 +4647,7 @@ foreach(_hdr include/grpcpp/impl/codegen/security/auth_context.h include/grpcpp/impl/codegen/serialization_traits.h include/grpcpp/impl/codegen/server_callback.h + include/grpcpp/impl/codegen/server_callback_impl.h include/grpcpp/impl/codegen/server_context.h include/grpcpp/impl/codegen/server_context_impl.h include/grpcpp/impl/codegen/server_interceptor.h @@ -4630,6 +4659,7 @@ foreach(_hdr include/grpcpp/impl/codegen/string_ref.h include/grpcpp/impl/codegen/stub_options.h include/grpcpp/impl/codegen/sync_stream.h + include/grpcpp/impl/codegen/sync_stream_impl.h include/grpcpp/impl/codegen/time.h include/grpc/impl/codegen/byte_buffer.h include/grpc/impl/codegen/byte_buffer_reader.h @@ -4846,11 +4876,14 @@ foreach(_hdr include/grpcpp/server_posix.h include/grpcpp/server_posix_impl.h include/grpcpp/support/async_stream.h + include/grpcpp/support/async_stream_impl.h include/grpcpp/support/async_unary_call.h + include/grpcpp/support/async_unary_call_impl.h include/grpcpp/support/byte_buffer.h include/grpcpp/support/channel_arguments.h include/grpcpp/support/channel_arguments_impl.h include/grpcpp/support/client_callback.h + include/grpcpp/support/client_callback_impl.h include/grpcpp/support/client_interceptor.h include/grpcpp/support/config.h include/grpcpp/support/interceptor.h @@ -4858,6 +4891,7 @@ foreach(_hdr include/grpcpp/support/proto_buffer_reader.h include/grpcpp/support/proto_buffer_writer.h include/grpcpp/support/server_callback.h + include/grpcpp/support/server_callback_impl.h include/grpcpp/support/server_interceptor.h include/grpcpp/support/slice.h include/grpcpp/support/status.h @@ -4865,6 +4899,7 @@ foreach(_hdr include/grpcpp/support/string_ref.h include/grpcpp/support/stub_options.h include/grpcpp/support/sync_stream.h + include/grpcpp/support/sync_stream_impl.h include/grpcpp/support/time.h include/grpcpp/support/validate_service_config.h include/grpc/support/alloc.h @@ -4950,7 +4985,9 @@ foreach(_hdr include/grpc++/impl/codegen/time.h include/grpcpp/impl/codegen/async_generic_service.h include/grpcpp/impl/codegen/async_stream.h + include/grpcpp/impl/codegen/async_stream_impl.h include/grpcpp/impl/codegen/async_unary_call.h + include/grpcpp/impl/codegen/async_unary_call_impl.h include/grpcpp/impl/codegen/byte_buffer.h include/grpcpp/impl/codegen/call.h include/grpcpp/impl/codegen/call_hook.h @@ -4959,6 +4996,7 @@ foreach(_hdr include/grpcpp/impl/codegen/callback_common.h include/grpcpp/impl/codegen/channel_interface.h include/grpcpp/impl/codegen/client_callback.h + include/grpcpp/impl/codegen/client_callback_impl.h include/grpcpp/impl/codegen/client_context.h include/grpcpp/impl/codegen/client_context_impl.h include/grpcpp/impl/codegen/client_interceptor.h @@ -4981,6 +5019,7 @@ foreach(_hdr include/grpcpp/impl/codegen/security/auth_context.h include/grpcpp/impl/codegen/serialization_traits.h include/grpcpp/impl/codegen/server_callback.h + include/grpcpp/impl/codegen/server_callback_impl.h include/grpcpp/impl/codegen/server_context.h include/grpcpp/impl/codegen/server_context_impl.h include/grpcpp/impl/codegen/server_interceptor.h @@ -4992,6 +5031,7 @@ foreach(_hdr include/grpcpp/impl/codegen/string_ref.h include/grpcpp/impl/codegen/stub_options.h include/grpcpp/impl/codegen/sync_stream.h + include/grpcpp/impl/codegen/sync_stream_impl.h include/grpcpp/impl/codegen/time.h include/grpcpp/impl/codegen/sync.h ) diff --git a/Makefile b/Makefile index d5b4f55d8d8..6369a52c49c 100644 --- a/Makefile +++ b/Makefile @@ -5588,11 +5588,14 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/server_posix.h \ include/grpcpp/server_posix_impl.h \ include/grpcpp/support/async_stream.h \ + include/grpcpp/support/async_stream_impl.h \ include/grpcpp/support/async_unary_call.h \ + include/grpcpp/support/async_unary_call_impl.h \ include/grpcpp/support/byte_buffer.h \ include/grpcpp/support/channel_arguments.h \ include/grpcpp/support/channel_arguments_impl.h \ include/grpcpp/support/client_callback.h \ + include/grpcpp/support/client_callback_impl.h \ include/grpcpp/support/client_interceptor.h \ include/grpcpp/support/config.h \ include/grpcpp/support/interceptor.h \ @@ -5600,6 +5603,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/support/proto_buffer_reader.h \ include/grpcpp/support/proto_buffer_writer.h \ include/grpcpp/support/server_callback.h \ + include/grpcpp/support/server_callback_impl.h \ include/grpcpp/support/server_interceptor.h \ include/grpcpp/support/slice.h \ include/grpcpp/support/status.h \ @@ -5607,6 +5611,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/support/string_ref.h \ include/grpcpp/support/stub_options.h \ include/grpcpp/support/sync_stream.h \ + include/grpcpp/support/sync_stream_impl.h \ include/grpcpp/support/time.h \ include/grpcpp/support/validate_service_config.h \ include/grpc/support/alloc.h \ @@ -5692,7 +5697,9 @@ PUBLIC_HEADERS_CXX += \ include/grpc++/impl/codegen/time.h \ include/grpcpp/impl/codegen/async_generic_service.h \ include/grpcpp/impl/codegen/async_stream.h \ + include/grpcpp/impl/codegen/async_stream_impl.h \ include/grpcpp/impl/codegen/async_unary_call.h \ + include/grpcpp/impl/codegen/async_unary_call_impl.h \ include/grpcpp/impl/codegen/byte_buffer.h \ include/grpcpp/impl/codegen/call.h \ include/grpcpp/impl/codegen/call_hook.h \ @@ -5701,6 +5708,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/callback_common.h \ include/grpcpp/impl/codegen/channel_interface.h \ include/grpcpp/impl/codegen/client_callback.h \ + include/grpcpp/impl/codegen/client_callback_impl.h \ include/grpcpp/impl/codegen/client_context.h \ include/grpcpp/impl/codegen/client_context_impl.h \ include/grpcpp/impl/codegen/client_interceptor.h \ @@ -5723,6 +5731,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/security/auth_context.h \ include/grpcpp/impl/codegen/serialization_traits.h \ include/grpcpp/impl/codegen/server_callback.h \ + include/grpcpp/impl/codegen/server_callback_impl.h \ include/grpcpp/impl/codegen/server_context.h \ include/grpcpp/impl/codegen/server_context_impl.h \ include/grpcpp/impl/codegen/server_interceptor.h \ @@ -5734,6 +5743,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/string_ref.h \ include/grpcpp/impl/codegen/stub_options.h \ include/grpcpp/impl/codegen/sync_stream.h \ + include/grpcpp/impl/codegen/sync_stream_impl.h \ include/grpcpp/impl/codegen/time.h \ include/grpcpp/impl/codegen/sync.h \ include/grpc++/impl/codegen/proto_utils.h \ @@ -6218,11 +6228,14 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/server_posix.h \ include/grpcpp/server_posix_impl.h \ include/grpcpp/support/async_stream.h \ + include/grpcpp/support/async_stream_impl.h \ include/grpcpp/support/async_unary_call.h \ + include/grpcpp/support/async_unary_call_impl.h \ include/grpcpp/support/byte_buffer.h \ include/grpcpp/support/channel_arguments.h \ include/grpcpp/support/channel_arguments_impl.h \ include/grpcpp/support/client_callback.h \ + include/grpcpp/support/client_callback_impl.h \ include/grpcpp/support/client_interceptor.h \ include/grpcpp/support/config.h \ include/grpcpp/support/interceptor.h \ @@ -6230,6 +6243,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/support/proto_buffer_reader.h \ include/grpcpp/support/proto_buffer_writer.h \ include/grpcpp/support/server_callback.h \ + include/grpcpp/support/server_callback_impl.h \ include/grpcpp/support/server_interceptor.h \ include/grpcpp/support/slice.h \ include/grpcpp/support/status.h \ @@ -6237,6 +6251,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/support/string_ref.h \ include/grpcpp/support/stub_options.h \ include/grpcpp/support/sync_stream.h \ + include/grpcpp/support/sync_stream_impl.h \ include/grpcpp/support/time.h \ include/grpcpp/support/validate_service_config.h \ include/grpc/support/alloc.h \ @@ -6322,7 +6337,9 @@ PUBLIC_HEADERS_CXX += \ include/grpc++/impl/codegen/time.h \ include/grpcpp/impl/codegen/async_generic_service.h \ include/grpcpp/impl/codegen/async_stream.h \ + include/grpcpp/impl/codegen/async_stream_impl.h \ include/grpcpp/impl/codegen/async_unary_call.h \ + include/grpcpp/impl/codegen/async_unary_call_impl.h \ include/grpcpp/impl/codegen/byte_buffer.h \ include/grpcpp/impl/codegen/call.h \ include/grpcpp/impl/codegen/call_hook.h \ @@ -6331,6 +6348,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/callback_common.h \ include/grpcpp/impl/codegen/channel_interface.h \ include/grpcpp/impl/codegen/client_callback.h \ + include/grpcpp/impl/codegen/client_callback_impl.h \ include/grpcpp/impl/codegen/client_context.h \ include/grpcpp/impl/codegen/client_context_impl.h \ include/grpcpp/impl/codegen/client_interceptor.h \ @@ -6353,6 +6371,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/security/auth_context.h \ include/grpcpp/impl/codegen/serialization_traits.h \ include/grpcpp/impl/codegen/server_callback.h \ + include/grpcpp/impl/codegen/server_callback_impl.h \ include/grpcpp/impl/codegen/server_context.h \ include/grpcpp/impl/codegen/server_context_impl.h \ include/grpcpp/impl/codegen/server_interceptor.h \ @@ -6364,6 +6383,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/string_ref.h \ include/grpcpp/impl/codegen/stub_options.h \ include/grpcpp/impl/codegen/sync_stream.h \ + include/grpcpp/impl/codegen/sync_stream_impl.h \ include/grpcpp/impl/codegen/time.h \ include/grpcpp/impl/codegen/sync.h \ include/grpc/census.h \ @@ -6731,7 +6751,9 @@ PUBLIC_HEADERS_CXX += \ include/grpc++/impl/codegen/time.h \ include/grpcpp/impl/codegen/async_generic_service.h \ include/grpcpp/impl/codegen/async_stream.h \ + include/grpcpp/impl/codegen/async_stream_impl.h \ include/grpcpp/impl/codegen/async_unary_call.h \ + include/grpcpp/impl/codegen/async_unary_call_impl.h \ include/grpcpp/impl/codegen/byte_buffer.h \ include/grpcpp/impl/codegen/call.h \ include/grpcpp/impl/codegen/call_hook.h \ @@ -6740,6 +6762,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/callback_common.h \ include/grpcpp/impl/codegen/channel_interface.h \ include/grpcpp/impl/codegen/client_callback.h \ + include/grpcpp/impl/codegen/client_callback_impl.h \ include/grpcpp/impl/codegen/client_context.h \ include/grpcpp/impl/codegen/client_context_impl.h \ include/grpcpp/impl/codegen/client_interceptor.h \ @@ -6762,6 +6785,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/security/auth_context.h \ include/grpcpp/impl/codegen/serialization_traits.h \ include/grpcpp/impl/codegen/server_callback.h \ + include/grpcpp/impl/codegen/server_callback_impl.h \ include/grpcpp/impl/codegen/server_context.h \ include/grpcpp/impl/codegen/server_context_impl.h \ include/grpcpp/impl/codegen/server_interceptor.h \ @@ -6773,6 +6797,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/string_ref.h \ include/grpcpp/impl/codegen/stub_options.h \ include/grpcpp/impl/codegen/sync_stream.h \ + include/grpcpp/impl/codegen/sync_stream_impl.h \ include/grpcpp/impl/codegen/time.h \ include/grpc/impl/codegen/byte_buffer.h \ include/grpc/impl/codegen/byte_buffer_reader.h \ @@ -6903,7 +6928,9 @@ PUBLIC_HEADERS_CXX += \ include/grpc++/impl/codegen/time.h \ include/grpcpp/impl/codegen/async_generic_service.h \ include/grpcpp/impl/codegen/async_stream.h \ + include/grpcpp/impl/codegen/async_stream_impl.h \ include/grpcpp/impl/codegen/async_unary_call.h \ + include/grpcpp/impl/codegen/async_unary_call_impl.h \ include/grpcpp/impl/codegen/byte_buffer.h \ include/grpcpp/impl/codegen/call.h \ include/grpcpp/impl/codegen/call_hook.h \ @@ -6912,6 +6939,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/callback_common.h \ include/grpcpp/impl/codegen/channel_interface.h \ include/grpcpp/impl/codegen/client_callback.h \ + include/grpcpp/impl/codegen/client_callback_impl.h \ include/grpcpp/impl/codegen/client_context.h \ include/grpcpp/impl/codegen/client_context_impl.h \ include/grpcpp/impl/codegen/client_interceptor.h \ @@ -6934,6 +6962,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/security/auth_context.h \ include/grpcpp/impl/codegen/serialization_traits.h \ include/grpcpp/impl/codegen/server_callback.h \ + include/grpcpp/impl/codegen/server_callback_impl.h \ include/grpcpp/impl/codegen/server_context.h \ include/grpcpp/impl/codegen/server_context_impl.h \ include/grpcpp/impl/codegen/server_interceptor.h \ @@ -6945,6 +6974,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/string_ref.h \ include/grpcpp/impl/codegen/stub_options.h \ include/grpcpp/impl/codegen/sync_stream.h \ + include/grpcpp/impl/codegen/sync_stream_impl.h \ include/grpcpp/impl/codegen/time.h \ include/grpc/impl/codegen/byte_buffer.h \ include/grpc/impl/codegen/byte_buffer_reader.h \ @@ -7167,11 +7197,14 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/server_posix.h \ include/grpcpp/server_posix_impl.h \ include/grpcpp/support/async_stream.h \ + include/grpcpp/support/async_stream_impl.h \ include/grpcpp/support/async_unary_call.h \ + include/grpcpp/support/async_unary_call_impl.h \ include/grpcpp/support/byte_buffer.h \ include/grpcpp/support/channel_arguments.h \ include/grpcpp/support/channel_arguments_impl.h \ include/grpcpp/support/client_callback.h \ + include/grpcpp/support/client_callback_impl.h \ include/grpcpp/support/client_interceptor.h \ include/grpcpp/support/config.h \ include/grpcpp/support/interceptor.h \ @@ -7179,6 +7212,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/support/proto_buffer_reader.h \ include/grpcpp/support/proto_buffer_writer.h \ include/grpcpp/support/server_callback.h \ + include/grpcpp/support/server_callback_impl.h \ include/grpcpp/support/server_interceptor.h \ include/grpcpp/support/slice.h \ include/grpcpp/support/status.h \ @@ -7186,6 +7220,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/support/string_ref.h \ include/grpcpp/support/stub_options.h \ include/grpcpp/support/sync_stream.h \ + include/grpcpp/support/sync_stream_impl.h \ include/grpcpp/support/time.h \ include/grpcpp/support/validate_service_config.h \ include/grpc/support/alloc.h \ @@ -7271,7 +7306,9 @@ PUBLIC_HEADERS_CXX += \ include/grpc++/impl/codegen/time.h \ include/grpcpp/impl/codegen/async_generic_service.h \ include/grpcpp/impl/codegen/async_stream.h \ + include/grpcpp/impl/codegen/async_stream_impl.h \ include/grpcpp/impl/codegen/async_unary_call.h \ + include/grpcpp/impl/codegen/async_unary_call_impl.h \ include/grpcpp/impl/codegen/byte_buffer.h \ include/grpcpp/impl/codegen/call.h \ include/grpcpp/impl/codegen/call_hook.h \ @@ -7280,6 +7317,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/callback_common.h \ include/grpcpp/impl/codegen/channel_interface.h \ include/grpcpp/impl/codegen/client_callback.h \ + include/grpcpp/impl/codegen/client_callback_impl.h \ include/grpcpp/impl/codegen/client_context.h \ include/grpcpp/impl/codegen/client_context_impl.h \ include/grpcpp/impl/codegen/client_interceptor.h \ @@ -7302,6 +7340,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/security/auth_context.h \ include/grpcpp/impl/codegen/serialization_traits.h \ include/grpcpp/impl/codegen/server_callback.h \ + include/grpcpp/impl/codegen/server_callback_impl.h \ include/grpcpp/impl/codegen/server_context.h \ include/grpcpp/impl/codegen/server_context_impl.h \ include/grpcpp/impl/codegen/server_interceptor.h \ @@ -7313,6 +7352,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/string_ref.h \ include/grpcpp/impl/codegen/stub_options.h \ include/grpcpp/impl/codegen/sync_stream.h \ + include/grpcpp/impl/codegen/sync_stream_impl.h \ include/grpcpp/impl/codegen/time.h \ include/grpcpp/impl/codegen/sync.h \ diff --git a/build.yaml b/build.yaml index 74482dab439..8d7445152f5 100644 --- a/build.yaml +++ b/build.yaml @@ -1251,7 +1251,9 @@ filegroups: - include/grpc++/impl/codegen/time.h - include/grpcpp/impl/codegen/async_generic_service.h - include/grpcpp/impl/codegen/async_stream.h + - include/grpcpp/impl/codegen/async_stream_impl.h - include/grpcpp/impl/codegen/async_unary_call.h + - include/grpcpp/impl/codegen/async_unary_call_impl.h - include/grpcpp/impl/codegen/byte_buffer.h - include/grpcpp/impl/codegen/call.h - include/grpcpp/impl/codegen/call_hook.h @@ -1260,6 +1262,7 @@ filegroups: - include/grpcpp/impl/codegen/callback_common.h - include/grpcpp/impl/codegen/channel_interface.h - include/grpcpp/impl/codegen/client_callback.h + - include/grpcpp/impl/codegen/client_callback_impl.h - include/grpcpp/impl/codegen/client_context.h - include/grpcpp/impl/codegen/client_context_impl.h - include/grpcpp/impl/codegen/client_interceptor.h @@ -1282,6 +1285,7 @@ filegroups: - include/grpcpp/impl/codegen/security/auth_context.h - include/grpcpp/impl/codegen/serialization_traits.h - include/grpcpp/impl/codegen/server_callback.h + - include/grpcpp/impl/codegen/server_callback_impl.h - include/grpcpp/impl/codegen/server_context.h - include/grpcpp/impl/codegen/server_context_impl.h - include/grpcpp/impl/codegen/server_interceptor.h @@ -1293,6 +1297,7 @@ filegroups: - include/grpcpp/impl/codegen/string_ref.h - include/grpcpp/impl/codegen/stub_options.h - include/grpcpp/impl/codegen/sync_stream.h + - include/grpcpp/impl/codegen/sync_stream_impl.h - include/grpcpp/impl/codegen/time.h uses: - grpc_codegen @@ -1411,11 +1416,14 @@ filegroups: - include/grpcpp/server_posix.h - include/grpcpp/server_posix_impl.h - include/grpcpp/support/async_stream.h + - include/grpcpp/support/async_stream_impl.h - include/grpcpp/support/async_unary_call.h + - include/grpcpp/support/async_unary_call_impl.h - include/grpcpp/support/byte_buffer.h - include/grpcpp/support/channel_arguments.h - include/grpcpp/support/channel_arguments_impl.h - include/grpcpp/support/client_callback.h + - include/grpcpp/support/client_callback_impl.h - include/grpcpp/support/client_interceptor.h - include/grpcpp/support/config.h - include/grpcpp/support/interceptor.h @@ -1423,6 +1431,7 @@ filegroups: - include/grpcpp/support/proto_buffer_reader.h - include/grpcpp/support/proto_buffer_writer.h - include/grpcpp/support/server_callback.h + - include/grpcpp/support/server_callback_impl.h - include/grpcpp/support/server_interceptor.h - include/grpcpp/support/slice.h - include/grpcpp/support/status.h @@ -1430,6 +1439,7 @@ filegroups: - include/grpcpp/support/string_ref.h - include/grpcpp/support/stub_options.h - include/grpcpp/support/sync_stream.h + - include/grpcpp/support/sync_stream_impl.h - include/grpcpp/support/time.h - include/grpcpp/support/validate_service_config.h headers: diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index a09173dc8f0..6933fd2c05b 100644 --- a/gRPC-C++.podspec +++ b/gRPC-C++.podspec @@ -129,11 +129,14 @@ Pod::Spec.new do |s| 'include/grpcpp/server_posix.h', 'include/grpcpp/server_posix_impl.h', 'include/grpcpp/support/async_stream.h', + 'include/grpcpp/support/async_stream_impl.h', 'include/grpcpp/support/async_unary_call.h', + 'include/grpcpp/support/async_unary_call_impl.h', 'include/grpcpp/support/byte_buffer.h', 'include/grpcpp/support/channel_arguments.h', 'include/grpcpp/support/channel_arguments_impl.h', 'include/grpcpp/support/client_callback.h', + 'include/grpcpp/support/client_callback_impl.h', 'include/grpcpp/support/client_interceptor.h', 'include/grpcpp/support/config.h', 'include/grpcpp/support/interceptor.h', @@ -141,6 +144,7 @@ Pod::Spec.new do |s| 'include/grpcpp/support/proto_buffer_reader.h', 'include/grpcpp/support/proto_buffer_writer.h', 'include/grpcpp/support/server_callback.h', + 'include/grpcpp/support/server_callback_impl.h', 'include/grpcpp/support/server_interceptor.h', 'include/grpcpp/support/slice.h', 'include/grpcpp/support/status.h', @@ -148,11 +152,14 @@ Pod::Spec.new do |s| 'include/grpcpp/support/string_ref.h', 'include/grpcpp/support/stub_options.h', 'include/grpcpp/support/sync_stream.h', + 'include/grpcpp/support/sync_stream_impl.h', 'include/grpcpp/support/time.h', 'include/grpcpp/support/validate_service_config.h', 'include/grpcpp/impl/codegen/async_generic_service.h', 'include/grpcpp/impl/codegen/async_stream.h', + 'include/grpcpp/impl/codegen/async_stream_impl.h', 'include/grpcpp/impl/codegen/async_unary_call.h', + 'include/grpcpp/impl/codegen/async_unary_call_impl.h', 'include/grpcpp/impl/codegen/byte_buffer.h', 'include/grpcpp/impl/codegen/call.h', 'include/grpcpp/impl/codegen/call_hook.h', @@ -161,6 +168,7 @@ Pod::Spec.new do |s| 'include/grpcpp/impl/codegen/callback_common.h', 'include/grpcpp/impl/codegen/channel_interface.h', 'include/grpcpp/impl/codegen/client_callback.h', + 'include/grpcpp/impl/codegen/client_callback_impl.h', 'include/grpcpp/impl/codegen/client_context.h', 'include/grpcpp/impl/codegen/client_context_impl.h', 'include/grpcpp/impl/codegen/client_interceptor.h', @@ -183,6 +191,7 @@ Pod::Spec.new do |s| 'include/grpcpp/impl/codegen/security/auth_context.h', 'include/grpcpp/impl/codegen/serialization_traits.h', 'include/grpcpp/impl/codegen/server_callback.h', + 'include/grpcpp/impl/codegen/server_callback_impl.h', 'include/grpcpp/impl/codegen/server_context.h', 'include/grpcpp/impl/codegen/server_context_impl.h', 'include/grpcpp/impl/codegen/server_interceptor.h', @@ -194,6 +203,7 @@ Pod::Spec.new do |s| 'include/grpcpp/impl/codegen/string_ref.h', 'include/grpcpp/impl/codegen/stub_options.h', 'include/grpcpp/impl/codegen/sync_stream.h', + 'include/grpcpp/impl/codegen/sync_stream_impl.h', 'include/grpcpp/impl/codegen/time.h', 'include/grpcpp/impl/codegen/sync.h' end diff --git a/include/grpcpp/channel_impl.h b/include/grpcpp/channel_impl.h index a7eee2b8981..9ff3118645f 100644 --- a/include/grpcpp/channel_impl.h +++ b/include/grpcpp/channel_impl.h @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include @@ -86,22 +86,23 @@ class Channel final : public ::grpc::ChannelInterface, ::grpc::internal::Call CreateCall(const ::grpc::internal::RpcMethod& method, ::grpc_impl::ClientContext* context, - ::grpc::CompletionQueue* cq) override; + ::grpc_impl::CompletionQueue* cq) override; void PerformOpsOnCall(::grpc::internal::CallOpSetInterface* ops, ::grpc::internal::Call* call) override; void* RegisterMethod(const char* method) override; void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed, gpr_timespec deadline, - ::grpc::CompletionQueue* cq, void* tag) override; + ::grpc_impl::CompletionQueue* cq, + void* tag) override; bool WaitForStateChangeImpl(grpc_connectivity_state last_observed, gpr_timespec deadline) override; - ::grpc::CompletionQueue* CallbackCQ() override; + ::grpc_impl::CompletionQueue* CallbackCQ() override; ::grpc::internal::Call CreateCallInternal( const ::grpc::internal::RpcMethod& method, - ::grpc_impl::ClientContext* context, ::grpc::CompletionQueue* cq, + ::grpc_impl::ClientContext* context, ::grpc_impl::CompletionQueue* cq, size_t interceptor_pos) override; const grpc::string host_; @@ -114,7 +115,7 @@ class Channel final : public ::grpc::ChannelInterface, // with this channel (if any). It is set on the first call to CallbackCQ(). // It is _not owned_ by the channel; ownership belongs with its internal // shutdown callback tag (invoked when the CQ is fully shutdown). - ::grpc::CompletionQueue* callback_cq_ = nullptr; + ::grpc_impl::CompletionQueue* callback_cq_ = nullptr; std::vector< std::unique_ptr<::grpc::experimental::ClientInterceptorFactoryInterface>> diff --git a/include/grpcpp/generic/generic_stub_impl.h b/include/grpcpp/generic/generic_stub_impl.h index fdbc0d0a272..e670fcaa654 100644 --- a/include/grpcpp/generic/generic_stub_impl.h +++ b/include/grpcpp/generic/generic_stub_impl.h @@ -22,17 +22,20 @@ #include #include -#include -#include +#include +#include #include -#include +#include #include +#include + namespace grpc { -typedef ClientAsyncReaderWriter +typedef ::grpc_impl::ClientAsyncReaderWriter GenericClientAsyncReaderWriter; -typedef ClientAsyncResponseReader GenericClientAsyncResponseReader; +typedef ::grpc_impl::ClientAsyncResponseReader + GenericClientAsyncResponseReader; } // namespace grpc namespace grpc_impl { class CompletionQueue; @@ -50,15 +53,15 @@ class GenericStub final { /// succeeded (i.e. the call won't proceed if the return value is nullptr). std::unique_ptr PrepareCall( grpc::ClientContext* context, const grpc::string& method, - grpc::CompletionQueue* cq); + CompletionQueue* cq); /// Setup a unary call to a named method \a method using \a context, and don't /// start it. Let it be started explicitly with StartCall. /// The return value only indicates whether or not registration of the call /// succeeded (i.e. the call won't proceed if the return value is nullptr). std::unique_ptr PrepareUnaryCall( - grpc::ClientContext* context, const grpc::string& method, - const grpc::ByteBuffer& request, grpc::CompletionQueue* cq); + grpc_impl::ClientContext* context, const grpc::string& method, + const grpc::ByteBuffer& request, CompletionQueue* cq); /// DEPRECATED for multi-threaded use /// Begin a call to a named method \a method using \a context. @@ -67,8 +70,8 @@ class GenericStub final { /// The return value only indicates whether or not registration of the call /// succeeded (i.e. the call won't proceed if the return value is nullptr). std::unique_ptr Call( - grpc::ClientContext* context, const grpc::string& method, - grpc::CompletionQueue* cq, void* tag); + grpc_impl::ClientContext* context, const grpc::string& method, + CompletionQueue* cq, void* tag); /// NOTE: class experimental_type is not part of the public API of this class /// TODO(vjpai): Move these contents to the public API of GenericStub when @@ -79,23 +82,25 @@ class GenericStub final { /// 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, + void UnaryCall(grpc_impl::ClientContext* context, + const grpc::string& method, const grpc::ByteBuffer* request, + grpc::ByteBuffer* response, std::function 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); + void UnaryCall(grpc_impl::ClientContext* context, + const grpc::string& method, const grpc::ByteBuffer* request, + grpc::ByteBuffer* response, + grpc_impl::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. void PrepareBidiStreamingCall( - grpc::ClientContext* context, const grpc::string& method, - grpc::experimental::ClientBidiReactor* reactor); + grpc_impl::ClientContext* context, const grpc::string& method, + grpc_impl::experimental::ClientBidiReactor* reactor); private: GenericStub* stub_; diff --git a/include/grpcpp/impl/codegen/async_generic_service.h b/include/grpcpp/impl/codegen/async_generic_service.h index d8e6f49b2f3..7c720ce3c23 100644 --- a/include/grpcpp/impl/codegen/async_generic_service.h +++ b/include/grpcpp/impl/codegen/async_generic_service.h @@ -19,19 +19,21 @@ #ifndef GRPCPP_IMPL_CODEGEN_ASYNC_GENERIC_SERVICE_H #define GRPCPP_IMPL_CODEGEN_ASYNC_GENERIC_SERVICE_H -#include +#include #include -#include +#include struct grpc_server; namespace grpc { -typedef ServerAsyncReaderWriter +typedef ::grpc_impl::ServerAsyncReaderWriter GenericServerAsyncReaderWriter; -typedef ServerAsyncResponseWriter GenericServerAsyncResponseWriter; -typedef ServerAsyncReader GenericServerAsyncReader; -typedef ServerAsyncWriter GenericServerAsyncWriter; +typedef ::grpc_impl::ServerAsyncResponseWriter + GenericServerAsyncResponseWriter; +typedef ::grpc_impl::ServerAsyncReader + GenericServerAsyncReader; +typedef ::grpc_impl::ServerAsyncWriter GenericServerAsyncWriter; class GenericServerContext final : public ::grpc_impl::ServerContext { public: @@ -75,8 +77,9 @@ class AsyncGenericService final { void RequestCall(GenericServerContext* ctx, GenericServerAsyncReaderWriter* reader_writer, - CompletionQueue* call_cq, - ServerCompletionQueue* notification_cq, void* tag); + ::grpc_impl::CompletionQueue* call_cq, + ::grpc_impl::ServerCompletionQueue* notification_cq, + void* tag); private: friend class grpc_impl::Server; @@ -91,7 +94,8 @@ namespace experimental { /// GenericServerContext rather than a ServerContext. All other reaction and /// operation initiation APIs are the same as ServerBidiReactor. class ServerGenericBidiReactor - : public ServerBidiReactor { + : public ::grpc_impl::experimental::ServerBidiReactor { public: /// Similar to ServerBidiReactor::OnStarted except for argument type. /// @@ -137,8 +141,10 @@ class CallbackGenericService { private: friend class ::grpc_impl::Server; - internal::CallbackBidiHandler* Handler() { - return new internal::CallbackBidiHandler( + ::grpc_impl::internal::CallbackBidiHandler* + Handler() { + return new ::grpc_impl::internal::CallbackBidiHandler( [this] { return CreateReactor(); }); } diff --git a/include/grpcpp/impl/codegen/async_stream.h b/include/grpcpp/impl/codegen/async_stream.h index 417dceb587f..14dfe67962e 100644 --- a/include/grpcpp/impl/codegen/async_stream.h +++ b/include/grpcpp/impl/codegen/async_stream.h @@ -19,1117 +19,47 @@ #ifndef GRPCPP_IMPL_CODEGEN_ASYNC_STREAM_H #define GRPCPP_IMPL_CODEGEN_ASYNC_STREAM_H -#include -#include -#include -#include -#include -#include +#include namespace grpc { - -namespace internal { -/// Common interface for all client side asynchronous streaming. -class ClientAsyncStreamingInterface { - public: - virtual ~ClientAsyncStreamingInterface() {} - - /// Start the call that was set up by the constructor, but only if the - /// constructor was invoked through the "Prepare" API which doesn't actually - /// start the call - virtual void StartCall(void* tag) = 0; - - /// Request notification of the reading of the initial metadata. Completion - /// will be notified by \a tag on the associated completion queue. - /// This call is optional, but if it is used, it cannot be used concurrently - /// with or after the \a AsyncReaderInterface::Read method. - /// - /// \param[in] tag Tag identifying this request. - virtual void ReadInitialMetadata(void* tag) = 0; - - /// Indicate that the stream is to be finished and request notification for - /// when the call has been ended. - /// Should not be used concurrently with other operations. - /// - /// It is appropriate to call this method when both: - /// * the client side has no more message to send - /// (this can be declared implicitly by calling this method, or - /// explicitly through an earlier call to the WritesDone method - /// of the class in use, e.g. \a ClientAsyncWriterInterface::WritesDone or - /// \a ClientAsyncReaderWriterInterface::WritesDone). - /// * there are no more messages to be received from the server (this can - /// be known implicitly by the calling code, or explicitly from an - /// earlier call to \a AsyncReaderInterface::Read that yielded a failed - /// result, e.g. cq->Next(&read_tag, &ok) filled in 'ok' with 'false'). - /// - /// The tag will be returned when either: - /// - all incoming messages have been read and the server has returned - /// a status. - /// - the server has returned a non-OK status. - /// - the call failed for some reason and the library generated a - /// status. - /// - /// Note that implementations of this method attempt to receive initial - /// metadata from the server if initial metadata hasn't yet been received. - /// - /// \param[in] tag Tag identifying this request. - /// \param[out] status To be updated with the operation status. - virtual void Finish(Status* status, void* tag) = 0; -}; - -/// An interface that yields a sequence of messages of type \a R. -template -class AsyncReaderInterface { - public: - virtual ~AsyncReaderInterface() {} - - /// Read a message of type \a R into \a msg. Completion will be notified by \a - /// tag on the associated completion queue. - /// This is thread-safe with respect to \a Write or \a WritesDone methods. It - /// should not be called concurrently with other streaming APIs - /// on the same stream. It is not meaningful to call it concurrently - /// with another \a AsyncReaderInterface::Read on the same stream since reads - /// on the same stream are delivered in order. - /// - /// \param[out] msg Where to eventually store the read message. - /// \param[in] tag The tag identifying the operation. - /// - /// Side effect: note that this method attempt to receive initial metadata for - /// a stream if it hasn't yet been received. - virtual void Read(R* msg, void* tag) = 0; -}; - -/// An interface that can be fed a sequence of messages of type \a W. -template -class AsyncWriterInterface { - public: - virtual ~AsyncWriterInterface() {} - - /// Request the writing of \a msg with identifying tag \a tag. - /// - /// Only one write may be outstanding at any given time. This means that - /// after calling Write, one must wait to receive \a tag from the completion - /// queue BEFORE calling Write again. - /// This is thread-safe with respect to \a AsyncReaderInterface::Read - /// - /// gRPC doesn't take ownership or a reference to \a msg, so it is safe to - /// to deallocate once Write returns. - /// - /// \param[in] msg The message to be written. - /// \param[in] tag The tag identifying the operation. - virtual void Write(const W& msg, void* tag) = 0; - - /// Request the writing of \a msg using WriteOptions \a options with - /// identifying tag \a tag. - /// - /// Only one write may be outstanding at any given time. This means that - /// after calling Write, one must wait to receive \a tag from the completion - /// queue BEFORE calling Write again. - /// WriteOptions \a options is used to set the write options of this message. - /// This is thread-safe with respect to \a AsyncReaderInterface::Read - /// - /// gRPC doesn't take ownership or a reference to \a msg, so it is safe to - /// to deallocate once Write returns. - /// - /// \param[in] msg The message to be written. - /// \param[in] options The WriteOptions to be used to write this message. - /// \param[in] tag The tag identifying the operation. - virtual void Write(const W& msg, WriteOptions options, void* tag) = 0; - - /// Request the writing of \a msg and coalesce it with the writing - /// of trailing metadata, using WriteOptions \a options with - /// identifying tag \a tag. - /// - /// For client, WriteLast is equivalent of performing Write and - /// WritesDone in a single step. - /// For server, WriteLast buffers the \a msg. The writing of \a msg is held - /// until Finish is called, where \a msg and trailing metadata are coalesced - /// and write is initiated. Note that WriteLast can only buffer \a msg up to - /// the flow control window size. If \a msg size is larger than the window - /// size, it will be sent on wire without buffering. - /// - /// gRPC doesn't take ownership or a reference to \a msg, so it is safe to - /// to deallocate once Write returns. - /// - /// \param[in] msg The message to be written. - /// \param[in] options The WriteOptions to be used to write this message. - /// \param[in] tag The tag identifying the operation. - void WriteLast(const W& msg, WriteOptions options, void* tag) { - Write(msg, options.set_last_message(), tag); - } -}; - -} // namespace internal - template -class ClientAsyncReaderInterface - : public internal::ClientAsyncStreamingInterface, - public internal::AsyncReaderInterface {}; +using ClientAsyncReaderInterface = ::grpc_impl::ClientAsyncReaderInterface; -namespace internal { template -class ClientAsyncReaderFactory { - public: - /// Create a stream object. - /// Write the first request out if \a start is set. - /// \a tag will be notified on \a cq when the call has been started and - /// \a request has been written out. If \a start is not set, \a tag must be - /// nullptr and the actual call must be initiated by StartCall - /// Note that \a context will be used to fill in custom initial metadata - /// used to send to the server when starting the call. - template - static ClientAsyncReader* Create(ChannelInterface* channel, - CompletionQueue* cq, - const ::grpc::internal::RpcMethod& method, - ::grpc_impl::ClientContext* context, - const W& request, bool start, void* tag) { - ::grpc::internal::Call call = channel->CreateCall(method, context, cq); - return new (g_core_codegen_interface->grpc_call_arena_alloc( - call.call(), sizeof(ClientAsyncReader))) - ClientAsyncReader(call, context, request, start, tag); - } -}; -} // namespace internal - -/// Async client-side API for doing server-streaming RPCs, -/// where the incoming message stream coming from the server has -/// messages of type \a R. -template -class ClientAsyncReader final : public ClientAsyncReaderInterface { - public: - // always allocated against a call arena, no memory free required - static void operator delete(void* ptr, std::size_t size) { - assert(size == sizeof(ClientAsyncReader)); - } - - // 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(void* tag) override { - assert(!started_); - started_ = true; - StartCallInternal(tag); - } - - /// See the \a ClientAsyncStreamingInterface.ReadInitialMetadata - /// method for semantics. - /// - /// Side effect: - /// - upon receiving initial metadata from the server, - /// the \a ClientContext associated with this call is updated, and the - /// calling code can access the received metadata through the - /// \a ClientContext. - void ReadInitialMetadata(void* tag) override { - assert(started_); - GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); - - meta_ops_.set_output_tag(tag); - meta_ops_.RecvInitialMetadata(context_); - call_.PerformOps(&meta_ops_); - } - - void Read(R* msg, void* tag) override { - assert(started_); - read_ops_.set_output_tag(tag); - if (!context_->initial_metadata_received_) { - read_ops_.RecvInitialMetadata(context_); - } - read_ops_.RecvMessage(msg); - call_.PerformOps(&read_ops_); - } - - /// See the \a ClientAsyncStreamingInterface.Finish method for semantics. - /// - /// Side effect: - /// - the \a ClientContext associated with this call is updated with - /// possible initial and trailing metadata received from the server. - void Finish(Status* status, void* tag) override { - assert(started_); - finish_ops_.set_output_tag(tag); - if (!context_->initial_metadata_received_) { - finish_ops_.RecvInitialMetadata(context_); - } - finish_ops_.ClientRecvStatus(context_, status); - call_.PerformOps(&finish_ops_); - } +using ClientAsyncReader = ::grpc_impl::ClientAsyncReader; - private: - friend class internal::ClientAsyncReaderFactory; - template - ClientAsyncReader(::grpc::internal::Call call, - ::grpc_impl::ClientContext* context, const W& request, - bool start, void* tag) - : context_(context), call_(call), started_(start) { - // TODO(ctiller): don't assert - GPR_CODEGEN_ASSERT(init_ops_.SendMessage(request).ok()); - init_ops_.ClientSendClose(); - if (start) { - StartCallInternal(tag); - } else { - assert(tag == nullptr); - } - } - - void StartCallInternal(void* tag) { - init_ops_.SendInitialMetadata(&context_->send_initial_metadata_, - context_->initial_metadata_flags()); - init_ops_.set_output_tag(tag); - call_.PerformOps(&init_ops_); - } - - ::grpc_impl::ClientContext* context_; - ::grpc::internal::Call call_; - bool started_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpClientSendClose> - init_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> - meta_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpRecvMessage> - read_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpClientRecvStatus> - finish_ops_; -}; - -/// Common interface for client side asynchronous writing. template -class ClientAsyncWriterInterface - : public internal::ClientAsyncStreamingInterface, - public internal::AsyncWriterInterface { - public: - /// Signal the client is done with the writes (half-close the client stream). - /// Thread-safe with respect to \a AsyncReaderInterface::Read - /// - /// \param[in] tag The tag identifying the operation. - virtual void WritesDone(void* tag) = 0; -}; +using ClientAsyncWriterInterface = ::grpc_impl::ClientAsyncWriterInterface; -namespace internal { template -class ClientAsyncWriterFactory { - public: - /// Create a stream object. - /// Start the RPC if \a start is set - /// \a tag will be notified on \a cq when the call has been started (i.e. - /// intitial metadata sent) and \a request has been written out. - /// If \a start is not set, \a tag must be nullptr and the actual call - /// must be initiated by StartCall - /// Note that \a context will be used to fill in custom initial metadata - /// used to send to the server when starting the call. - /// \a response will be filled in with the single expected response - /// message from the server upon a successful call to the \a Finish - /// method of this instance. - template - static ClientAsyncWriter* Create(ChannelInterface* channel, - CompletionQueue* cq, - const ::grpc::internal::RpcMethod& method, - ::grpc_impl::ClientContext* context, - R* response, bool start, void* tag) { - ::grpc::internal::Call call = channel->CreateCall(method, context, cq); - return new (g_core_codegen_interface->grpc_call_arena_alloc( - call.call(), sizeof(ClientAsyncWriter))) - ClientAsyncWriter(call, context, response, start, tag); - } -}; -} // namespace internal - -/// Async API on the client side for doing client-streaming RPCs, -/// where the outgoing message stream going to the server contains -/// messages of type \a W. -template -class ClientAsyncWriter final : public ClientAsyncWriterInterface { - public: - // always allocated against a call arena, no memory free required - static void operator delete(void* ptr, std::size_t size) { - assert(size == sizeof(ClientAsyncWriter)); - } - - // 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(void* tag) override { - assert(!started_); - started_ = true; - StartCallInternal(tag); - } - - /// See the \a ClientAsyncStreamingInterface.ReadInitialMetadata method for - /// semantics. - /// - /// Side effect: - /// - upon receiving initial metadata from the server, the \a ClientContext - /// associated with this call is updated, and the calling code can access - /// the received metadata through the \a ClientContext. - void ReadInitialMetadata(void* tag) override { - assert(started_); - GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); - - meta_ops_.set_output_tag(tag); - meta_ops_.RecvInitialMetadata(context_); - call_.PerformOps(&meta_ops_); - } - - void Write(const W& msg, void* tag) override { - assert(started_); - write_ops_.set_output_tag(tag); - // TODO(ctiller): don't assert - GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok()); - call_.PerformOps(&write_ops_); - } - - void Write(const W& msg, WriteOptions options, void* tag) override { - assert(started_); - write_ops_.set_output_tag(tag); - if (options.is_last_message()) { - options.set_buffer_hint(); - write_ops_.ClientSendClose(); - } - // TODO(ctiller): don't assert - GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok()); - call_.PerformOps(&write_ops_); - } +using ClientAsyncWriter = ::grpc_impl::ClientAsyncWriter; - void WritesDone(void* tag) override { - assert(started_); - write_ops_.set_output_tag(tag); - write_ops_.ClientSendClose(); - call_.PerformOps(&write_ops_); - } - - /// See the \a ClientAsyncStreamingInterface.Finish method for semantics. - /// - /// Side effect: - /// - the \a ClientContext associated with this call is updated with - /// possible initial and trailing metadata received from the server. - /// - attempts to fill in the \a response parameter passed to this class's - /// constructor with the server's response message. - void Finish(Status* status, void* tag) override { - assert(started_); - finish_ops_.set_output_tag(tag); - if (!context_->initial_metadata_received_) { - finish_ops_.RecvInitialMetadata(context_); - } - finish_ops_.ClientRecvStatus(context_, status); - call_.PerformOps(&finish_ops_); - } - - private: - friend class internal::ClientAsyncWriterFactory; - template - ClientAsyncWriter(::grpc::internal::Call call, - ::grpc_impl::ClientContext* context, R* response, - bool start, void* tag) - : context_(context), call_(call), started_(start) { - finish_ops_.RecvMessage(response); - finish_ops_.AllowNoMessage(); - if (start) { - StartCallInternal(tag); - } else { - assert(tag == nullptr); - } - } - - void StartCallInternal(void* tag) { - write_ops_.SendInitialMetadata(&context_->send_initial_metadata_, - context_->initial_metadata_flags()); - // if corked bit is set in context, we just keep the initial metadata - // buffered up to coalesce with later message send. No op is performed. - if (!context_->initial_metadata_corked_) { - write_ops_.set_output_tag(tag); - call_.PerformOps(&write_ops_); - } - } - - ::grpc_impl::ClientContext* context_; - ::grpc::internal::Call call_; - bool started_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> - meta_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpClientSendClose> - write_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpGenericRecvMessage, - ::grpc::internal::CallOpClientRecvStatus> - finish_ops_; -}; - -/// Async client-side interface for bi-directional streaming, -/// where the client-to-server message stream has messages of type \a W, -/// and the server-to-client message stream has messages of type \a R. template -class ClientAsyncReaderWriterInterface - : public internal::ClientAsyncStreamingInterface, - public internal::AsyncWriterInterface, - public internal::AsyncReaderInterface { - public: - /// Signal the client is done with the writes (half-close the client stream). - /// Thread-safe with respect to \a AsyncReaderInterface::Read - /// - /// \param[in] tag The tag identifying the operation. - virtual void WritesDone(void* tag) = 0; -}; +using ClientAsyncReaderWriterInterface = + ::grpc_impl::ClientAsyncReaderWriterInterface; -namespace internal { template -class ClientAsyncReaderWriterFactory { - public: - /// Create a stream object. - /// Start the RPC request if \a start is set. - /// \a tag will be notified on \a cq when the call has been started (i.e. - /// intitial metadata sent). If \a start is not set, \a tag must be - /// nullptr and the actual call must be initiated by StartCall - /// Note that \a context will be used to fill in custom initial metadata - /// used to send to the server when starting the call. - static ClientAsyncReaderWriter* Create( - ChannelInterface* channel, CompletionQueue* cq, - const ::grpc::internal::RpcMethod& method, - ::grpc_impl::ClientContext* context, bool start, void* tag) { - ::grpc::internal::Call call = channel->CreateCall(method, context, cq); - - return new (g_core_codegen_interface->grpc_call_arena_alloc( - call.call(), sizeof(ClientAsyncReaderWriter))) - ClientAsyncReaderWriter(call, context, start, tag); - } -}; -} // namespace internal - -/// Async client-side interface for bi-directional streaming, -/// where the outgoing message stream going to the server -/// has messages of type \a W, and the incoming message stream coming -/// from the server has messages of type \a R. -template -class ClientAsyncReaderWriter final - : public ClientAsyncReaderWriterInterface { - public: - // always allocated against a call arena, no memory free required - static void operator delete(void* ptr, std::size_t size) { - assert(size == sizeof(ClientAsyncReaderWriter)); - } - - // 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(void* tag) override { - assert(!started_); - started_ = true; - StartCallInternal(tag); - } - - /// See the \a ClientAsyncStreamingInterface.ReadInitialMetadata method - /// for semantics of this method. - /// - /// Side effect: - /// - upon receiving initial metadata from the server, the \a ClientContext - /// is updated with it, and then the receiving initial metadata can - /// be accessed through this \a ClientContext. - void ReadInitialMetadata(void* tag) override { - assert(started_); - GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); - - meta_ops_.set_output_tag(tag); - meta_ops_.RecvInitialMetadata(context_); - call_.PerformOps(&meta_ops_); - } - - void Read(R* msg, void* tag) override { - assert(started_); - read_ops_.set_output_tag(tag); - if (!context_->initial_metadata_received_) { - read_ops_.RecvInitialMetadata(context_); - } - read_ops_.RecvMessage(msg); - call_.PerformOps(&read_ops_); - } - - void Write(const W& msg, void* tag) override { - assert(started_); - write_ops_.set_output_tag(tag); - // TODO(ctiller): don't assert - GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok()); - call_.PerformOps(&write_ops_); - } - - void Write(const W& msg, WriteOptions options, void* tag) override { - assert(started_); - write_ops_.set_output_tag(tag); - if (options.is_last_message()) { - options.set_buffer_hint(); - write_ops_.ClientSendClose(); - } - // TODO(ctiller): don't assert - GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok()); - call_.PerformOps(&write_ops_); - } - - void WritesDone(void* tag) override { - assert(started_); - write_ops_.set_output_tag(tag); - write_ops_.ClientSendClose(); - call_.PerformOps(&write_ops_); - } - - /// See the \a ClientAsyncStreamingInterface.Finish method for semantics. - /// Side effect - /// - the \a ClientContext associated with this call is updated with - /// possible initial and trailing metadata sent from the server. - void Finish(Status* status, void* tag) override { - assert(started_); - finish_ops_.set_output_tag(tag); - if (!context_->initial_metadata_received_) { - finish_ops_.RecvInitialMetadata(context_); - } - finish_ops_.ClientRecvStatus(context_, status); - call_.PerformOps(&finish_ops_); - } - - private: - friend class internal::ClientAsyncReaderWriterFactory; - ClientAsyncReaderWriter(::grpc::internal::Call call, - ::grpc_impl::ClientContext* context, bool start, - void* tag) - : context_(context), call_(call), started_(start) { - if (start) { - StartCallInternal(tag); - } else { - assert(tag == nullptr); - } - } - - void StartCallInternal(void* tag) { - write_ops_.SendInitialMetadata(&context_->send_initial_metadata_, - context_->initial_metadata_flags()); - // if corked bit is set in context, we just keep the initial metadata - // buffered up to coalesce with later message send. No op is performed. - if (!context_->initial_metadata_corked_) { - write_ops_.set_output_tag(tag); - call_.PerformOps(&write_ops_); - } - } - - ::grpc_impl::ClientContext* context_; - ::grpc::internal::Call call_; - bool started_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> - meta_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpRecvMessage> - read_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpClientSendClose> - write_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpClientRecvStatus> - finish_ops_; -}; +using ClientAsyncReaderWriter = ::grpc_impl::ClientAsyncReaderWriter; template -class ServerAsyncReaderInterface - : public internal::ServerAsyncStreamingInterface, - public internal::AsyncReaderInterface { - public: - /// Indicate that the stream is to be finished with a certain status code - /// and also send out \a msg response to the client. - /// Request notification for when the server has sent the response and the - /// appropriate signals to the client to end the call. - /// Should not be used concurrently with other operations. - /// - /// It is appropriate to call this method when: - /// * all messages from the client have been received (either known - /// implictly, or explicitly because a previous - /// \a AsyncReaderInterface::Read operation with a non-ok result, - /// e.g., cq->Next(&read_tag, &ok) filled in 'ok' with 'false'). - /// - /// This operation will end when the server has finished sending out initial - /// metadata (if not sent already), response message, and status, or if - /// 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 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. - /// \param[in] msg To be sent to the client as the response for this call. - virtual void Finish(const W& msg, const Status& status, void* tag) = 0; - - /// Indicate that the stream is to be finished with a certain - /// non-OK status code. - /// Request notification for when the server has sent the appropriate - /// signals to the client to end the call. - /// Should not be used concurrently with other operations. - /// - /// This call is meant to end the call with some error, and can be called at - /// any point that the server would like to "fail" the call (though note - /// this shouldn't be called concurrently with any other "sending" call, like - /// \a AsyncWriterInterface::Write). - /// - /// This operation will end when the server has finished sending out initial - /// metadata (if not sent already), and status, or if some failure occurred - /// when trying to do so. - /// - /// gRPC doesn't take ownership or a reference to \a status, so it is safe to - /// to deallocate once FinishWithError returns. - /// - /// \param[in] tag Tag identifying this request. - /// \param[in] status To be sent to the client as the result of this call. - /// - Note: \a status must have a non-OK code. - virtual void FinishWithError(const Status& status, void* tag) = 0; -}; +using ServerAsyncReaderInterface = + ::grpc_impl::ServerAsyncReaderInterface; -/// Async server-side API for doing client-streaming RPCs, -/// where the incoming message stream from the client has messages of type \a R, -/// and the single response message sent from the server is type \a W. template -class ServerAsyncReader final : public ServerAsyncReaderInterface { - public: - explicit ServerAsyncReader(::grpc_impl::ServerContext* ctx) - : call_(nullptr, nullptr, nullptr), ctx_(ctx) {} - - /// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics. - /// - /// Implicit input parameter: - /// - The initial metadata that will be sent to the client from this op will - /// be taken from the \a ServerContext associated with the call. - void SendInitialMetadata(void* tag) override { - GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); - - meta_ops_.set_output_tag(tag); - meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - meta_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - call_.PerformOps(&meta_ops_); - } - - void Read(R* msg, void* tag) override { - read_ops_.set_output_tag(tag); - read_ops_.RecvMessage(msg); - call_.PerformOps(&read_ops_); - } - - /// See the \a ServerAsyncReaderInterface.Read method for semantics - /// - /// Side effect: - /// - also sends initial metadata if not alreay sent. - /// - uses the \a ServerContext associated with this call to send possible - /// initial and trailing metadata. - /// - /// 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 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_) { - finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - finish_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - } - // The response is dropped if the status is not OK. - if (status.ok()) { - finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, - finish_ops_.SendMessage(msg)); - } else { - finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status); - } - call_.PerformOps(&finish_ops_); - } - - /// See the \a ServerAsyncReaderInterface.Read method for semantics - /// - /// Side effect: - /// - also sends initial metadata if not alreay sent. - /// - uses the \a ServerContext associated with this call to send possible - /// initial and trailing metadata. - /// - /// gRPC doesn't take ownership or a reference to \a status, so it is safe to - /// to deallocate once FinishWithError returns. - void FinishWithError(const Status& status, void* tag) override { - GPR_CODEGEN_ASSERT(!status.ok()); - finish_ops_.set_output_tag(tag); - if (!ctx_->sent_initial_metadata_) { - finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - finish_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - } - finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status); - call_.PerformOps(&finish_ops_); - } - - private: - void BindCall(::grpc::internal::Call* call) override { call_ = *call; } - - ::grpc::internal::Call call_; - ::grpc_impl::ServerContext* ctx_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> - meta_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage> read_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpServerSendStatus> - finish_ops_; -}; +using ServerAsyncReader = ::grpc_impl::ServerAsyncReader; template -class ServerAsyncWriterInterface - : public internal::ServerAsyncStreamingInterface, - public internal::AsyncWriterInterface { - public: - /// Indicate that the stream is to be finished with a certain status code. - /// Request notification for when the server has sent the appropriate - /// signals to the client to end the call. - /// Should not be used concurrently with other operations. - /// - /// It is appropriate to call this method when either: - /// * all messages from the client have been received (either known - /// implictly, or explicitly because a previous \a - /// AsyncReaderInterface::Read operation with a non-ok - /// result (e.g., cq->Next(&read_tag, &ok) filled in 'ok' with 'false'. - /// * it is desired to end the call early with some non-OK status code. - /// - /// This operation will end when the server has finished sending out initial - /// metadata (if not sent already), response message, and status, or if - /// some failure occurred when trying to do so. - /// - /// gRPC doesn't take ownership or a reference to \a status, so it is safe to - /// 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. - virtual void Finish(const Status& status, void* tag) = 0; - - /// Request the writing of \a msg and coalesce it with trailing metadata which - /// contains \a status, using WriteOptions options with - /// identifying tag \a tag. - /// - /// WriteAndFinish is equivalent of performing WriteLast and Finish - /// in a single step. - /// - /// gRPC doesn't take ownership or a reference to \a msg and \a status, so it - /// 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. - /// \param[in] status The Status that server returns to client. - /// \param[in] tag The tag identifying the operation. - virtual void WriteAndFinish(const W& msg, WriteOptions options, - const Status& status, void* tag) = 0; -}; +using ServerAsyncWriterInterface = ::grpc_impl::ServerAsyncWriterInterface; -/// Async server-side API for doing server streaming RPCs, -/// where the outgoing message stream from the server has messages of type \a W. template -class ServerAsyncWriter final : public ServerAsyncWriterInterface { - public: - explicit ServerAsyncWriter(::grpc_impl::ServerContext* ctx) - : call_(nullptr, nullptr, nullptr), ctx_(ctx) {} - - /// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics. - /// - /// Implicit input parameter: - /// - The initial metadata that will be sent to the client from this op will - /// be taken from the \a ServerContext associated with the call. - /// - /// \param[in] tag Tag identifying this request. - void SendInitialMetadata(void* tag) override { - GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); - - meta_ops_.set_output_tag(tag); - meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - meta_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - call_.PerformOps(&meta_ops_); - } - - void Write(const W& msg, void* tag) override { - write_ops_.set_output_tag(tag); - EnsureInitialMetadataSent(&write_ops_); - // TODO(ctiller): don't assert - GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok()); - call_.PerformOps(&write_ops_); - } +using ServerAsyncWriter = ::grpc_impl::ServerAsyncWriter; - void Write(const W& msg, WriteOptions options, void* tag) override { - write_ops_.set_output_tag(tag); - if (options.is_last_message()) { - options.set_buffer_hint(); - } - - EnsureInitialMetadataSent(&write_ops_); - // TODO(ctiller): don't assert - GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok()); - call_.PerformOps(&write_ops_); - } - - /// See the \a ServerAsyncWriterInterface.WriteAndFinish method for semantics. - /// - /// Implicit input parameter: - /// - the \a ServerContext associated with this call is used - /// for sending trailing (and initial) metadata to the client. - /// - /// 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 deallocate once WriteAndFinish returns. - void WriteAndFinish(const W& msg, WriteOptions options, const Status& status, - void* tag) override { - write_ops_.set_output_tag(tag); - EnsureInitialMetadataSent(&write_ops_); - options.set_buffer_hint(); - GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok()); - write_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status); - call_.PerformOps(&write_ops_); - } - - /// See the \a ServerAsyncWriterInterface.Finish method for semantics. - /// - /// Implicit input parameter: - /// - the \a ServerContext associated with this call is used for sending - /// trailing (and initial if not already sent) metadata to the client. - /// - /// Note: there are no restrictions are the code of - /// \a status,it may be non-OK - /// - /// gRPC doesn't take ownership or a reference to \a status, so it is safe to - /// to deallocate once Finish returns. - void Finish(const Status& status, void* tag) override { - finish_ops_.set_output_tag(tag); - EnsureInitialMetadataSent(&finish_ops_); - finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status); - call_.PerformOps(&finish_ops_); - } - - private: - void BindCall(::grpc::internal::Call* call) override { call_ = *call; } - - template - void EnsureInitialMetadataSent(T* ops) { - if (!ctx_->sent_initial_metadata_) { - ops->SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - ops->set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - } - } - - ::grpc::internal::Call call_; - ::grpc_impl::ServerContext* ctx_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> - meta_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpServerSendStatus> - write_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpServerSendStatus> - finish_ops_; -}; - -/// Server-side interface for asynchronous bi-directional streaming. template -class ServerAsyncReaderWriterInterface - : public internal::ServerAsyncStreamingInterface, - public internal::AsyncWriterInterface, - public internal::AsyncReaderInterface { - public: - /// Indicate that the stream is to be finished with a certain status code. - /// Request notification for when the server has sent the appropriate - /// signals to the client to end the call. - /// Should not be used concurrently with other operations. - /// - /// It is appropriate to call this method when either: - /// * all messages from the client have been received (either known - /// implictly, or explicitly because a previous \a - /// AsyncReaderInterface::Read operation - /// with a non-ok result (e.g., cq->Next(&read_tag, &ok) filled in 'ok' - /// with 'false'. - /// * it is desired to end the call early with some non-OK status code. - /// - /// This operation will end when the server has finished sending out initial - /// metadata (if not sent already), response message, and status, or if some - /// failure occurred when trying to do so. - /// - /// gRPC doesn't take ownership or a reference to \a status, so it is safe to - /// 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. - virtual void Finish(const Status& status, void* tag) = 0; - - /// Request the writing of \a msg and coalesce it with trailing metadata which - /// contains \a status, using WriteOptions options with - /// identifying tag \a tag. - /// - /// WriteAndFinish is equivalent of performing WriteLast and Finish in a - /// single step. - /// - /// gRPC doesn't take ownership or a reference to \a msg and \a status, so it - /// 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. - /// \param[in] status The Status that server returns to client. - /// \param[in] tag The tag identifying the operation. - virtual void WriteAndFinish(const W& msg, WriteOptions options, - const Status& status, void* tag) = 0; -}; +using ServerAsyncReaderWriterInterface = + ::grpc_impl::ServerAsyncReaderWriterInterface; -/// Async server-side API for doing bidirectional streaming RPCs, -/// where the incoming message stream coming from the client has messages of -/// type \a R, and the outgoing message stream coming from the server has -/// messages of type \a W. template -class ServerAsyncReaderWriter final - : public ServerAsyncReaderWriterInterface { - public: - explicit ServerAsyncReaderWriter(::grpc_impl::ServerContext* ctx) - : call_(nullptr, nullptr, nullptr), ctx_(ctx) {} - - /// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics. - /// - /// Implicit input parameter: - /// - The initial metadata that will be sent to the client from this op will - /// be taken from the \a ServerContext associated with the call. - /// - /// \param[in] tag Tag identifying this request. - void SendInitialMetadata(void* tag) override { - GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); - - meta_ops_.set_output_tag(tag); - meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - meta_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - call_.PerformOps(&meta_ops_); - } - - void Read(R* msg, void* tag) override { - read_ops_.set_output_tag(tag); - read_ops_.RecvMessage(msg); - call_.PerformOps(&read_ops_); - } - - void Write(const W& msg, void* tag) override { - write_ops_.set_output_tag(tag); - EnsureInitialMetadataSent(&write_ops_); - // TODO(ctiller): don't assert - GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok()); - call_.PerformOps(&write_ops_); - } - - void Write(const W& msg, WriteOptions options, void* tag) override { - write_ops_.set_output_tag(tag); - if (options.is_last_message()) { - options.set_buffer_hint(); - } - EnsureInitialMetadataSent(&write_ops_); - GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok()); - call_.PerformOps(&write_ops_); - } - - /// See the \a ServerAsyncReaderWriterInterface.WriteAndFinish - /// method for semantics. - /// - /// Implicit input parameter: - /// - the \a ServerContext associated with this call is used - /// for sending trailing (and initial) metadata to the client. - /// - /// 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 deallocate once WriteAndFinish returns. - void WriteAndFinish(const W& msg, WriteOptions options, const Status& status, - void* tag) override { - write_ops_.set_output_tag(tag); - EnsureInitialMetadataSent(&write_ops_); - options.set_buffer_hint(); - GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok()); - write_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status); - call_.PerformOps(&write_ops_); - } - - /// See the \a ServerAsyncReaderWriterInterface.Finish method for semantics. - /// - /// Implicit input parameter: - /// - the \a ServerContext associated with this call is used for sending - /// trailing (and initial if not already sent) metadata to the client. - /// - /// Note: there are no restrictions are the code of \a status, - /// it may be non-OK - // - /// gRPC doesn't take ownership or a reference to \a status, so it is safe to - /// to deallocate once Finish returns. - void Finish(const Status& status, void* tag) override { - finish_ops_.set_output_tag(tag); - EnsureInitialMetadataSent(&finish_ops_); - - finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status); - call_.PerformOps(&finish_ops_); - } - - private: - friend class ::grpc_impl::Server; - - void BindCall(::grpc::internal::Call* call) override { call_ = *call; } - - template - void EnsureInitialMetadataSent(T* ops) { - if (!ctx_->sent_initial_metadata_) { - ops->SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - ops->set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - } - } - - ::grpc::internal::Call call_; - ::grpc_impl::ServerContext* ctx_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> - meta_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage> read_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpServerSendStatus> - write_ops_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpServerSendStatus> - finish_ops_; -}; - +using ServerAsyncReaderWriter = ::grpc_impl::ServerAsyncReaderWriter; } // namespace grpc #endif // GRPCPP_IMPL_CODEGEN_ASYNC_STREAM_H diff --git a/include/grpcpp/impl/codegen/async_stream_impl.h b/include/grpcpp/impl/codegen/async_stream_impl.h new file mode 100644 index 00000000000..633a3d5dd00 --- /dev/null +++ b/include/grpcpp/impl/codegen/async_stream_impl.h @@ -0,0 +1,1134 @@ +/* + * + * 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_ASYNC_STREAM_IMPL_H +#define GRPCPP_IMPL_CODEGEN_ASYNC_STREAM_IMPL_H + +#include +#include +#include +#include +#include +#include + +namespace grpc_impl { + +namespace internal { +/// Common interface for all client side asynchronous streaming. +class ClientAsyncStreamingInterface { + public: + virtual ~ClientAsyncStreamingInterface() {} + + /// Start the call that was set up by the constructor, but only if the + /// constructor was invoked through the "Prepare" API which doesn't actually + /// start the call + virtual void StartCall(void* tag) = 0; + + /// Request notification of the reading of the initial metadata. Completion + /// will be notified by \a tag on the associated completion queue. + /// This call is optional, but if it is used, it cannot be used concurrently + /// with or after the \a AsyncReaderInterface::Read method. + /// + /// \param[in] tag Tag identifying this request. + virtual void ReadInitialMetadata(void* tag) = 0; + + /// Indicate that the stream is to be finished and request notification for + /// when the call has been ended. + /// Should not be used concurrently with other operations. + /// + /// It is appropriate to call this method when both: + /// * the client side has no more message to send + /// (this can be declared implicitly by calling this method, or + /// explicitly through an earlier call to the WritesDone method + /// of the class in use, e.g. \a ClientAsyncWriterInterface::WritesDone or + /// \a ClientAsyncReaderWriterInterface::WritesDone). + /// * there are no more messages to be received from the server (this can + /// be known implicitly by the calling code, or explicitly from an + /// earlier call to \a AsyncReaderInterface::Read that yielded a failed + /// result, e.g. cq->Next(&read_tag, &ok) filled in 'ok' with 'false'). + /// + /// The tag will be returned when either: + /// - all incoming messages have been read and the server has returned + /// a status. + /// - the server has returned a non-OK status. + /// - the call failed for some reason and the library generated a + /// status. + /// + /// Note that implementations of this method attempt to receive initial + /// metadata from the server if initial metadata hasn't yet been received. + /// + /// \param[in] tag Tag identifying this request. + /// \param[out] status To be updated with the operation status. + virtual void Finish(::grpc::Status* status, void* tag) = 0; +}; + +/// An interface that yields a sequence of messages of type \a R. +template +class AsyncReaderInterface { + public: + virtual ~AsyncReaderInterface() {} + + /// Read a message of type \a R into \a msg. Completion will be notified by \a + /// tag on the associated completion queue. + /// This is thread-safe with respect to \a Write or \a WritesDone methods. It + /// should not be called concurrently with other streaming APIs + /// on the same stream. It is not meaningful to call it concurrently + /// with another \a AsyncReaderInterface::Read on the same stream since reads + /// on the same stream are delivered in order. + /// + /// \param[out] msg Where to eventually store the read message. + /// \param[in] tag The tag identifying the operation. + /// + /// Side effect: note that this method attempt to receive initial metadata for + /// a stream if it hasn't yet been received. + virtual void Read(R* msg, void* tag) = 0; +}; + +/// An interface that can be fed a sequence of messages of type \a W. +template +class AsyncWriterInterface { + public: + virtual ~AsyncWriterInterface() {} + + /// Request the writing of \a msg with identifying tag \a tag. + /// + /// Only one write may be outstanding at any given time. This means that + /// after calling Write, one must wait to receive \a tag from the completion + /// queue BEFORE calling Write again. + /// This is thread-safe with respect to \a AsyncReaderInterface::Read + /// + /// gRPC doesn't take ownership or a reference to \a msg, so it is safe to + /// to deallocate once Write returns. + /// + /// \param[in] msg The message to be written. + /// \param[in] tag The tag identifying the operation. + virtual void Write(const W& msg, void* tag) = 0; + + /// Request the writing of \a msg using WriteOptions \a options with + /// identifying tag \a tag. + /// + /// Only one write may be outstanding at any given time. This means that + /// after calling Write, one must wait to receive \a tag from the completion + /// queue BEFORE calling Write again. + /// WriteOptions \a options is used to set the write options of this message. + /// This is thread-safe with respect to \a AsyncReaderInterface::Read + /// + /// gRPC doesn't take ownership or a reference to \a msg, so it is safe to + /// to deallocate once Write returns. + /// + /// \param[in] msg The message to be written. + /// \param[in] options The WriteOptions to be used to write this message. + /// \param[in] tag The tag identifying the operation. + virtual void Write(const W& msg, ::grpc::WriteOptions options, void* tag) = 0; + + /// Request the writing of \a msg and coalesce it with the writing + /// of trailing metadata, using WriteOptions \a options with + /// identifying tag \a tag. + /// + /// For client, WriteLast is equivalent of performing Write and + /// WritesDone in a single step. + /// For server, WriteLast buffers the \a msg. The writing of \a msg is held + /// until Finish is called, where \a msg and trailing metadata are coalesced + /// and write is initiated. Note that WriteLast can only buffer \a msg up to + /// the flow control window size. If \a msg size is larger than the window + /// size, it will be sent on wire without buffering. + /// + /// gRPC doesn't take ownership or a reference to \a msg, so it is safe to + /// to deallocate once Write returns. + /// + /// \param[in] msg The message to be written. + /// \param[in] options The WriteOptions to be used to write this message. + /// \param[in] tag The tag identifying the operation. + void WriteLast(const W& msg, ::grpc::WriteOptions options, void* tag) { + Write(msg, options.set_last_message(), tag); + } +}; + +} // namespace internal + +template +class ClientAsyncReaderInterface + : public internal::ClientAsyncStreamingInterface, + public internal::AsyncReaderInterface {}; + +namespace internal { +template +class ClientAsyncReaderFactory { + public: + /// Create a stream object. + /// Write the first request out if \a start is set. + /// \a tag will be notified on \a cq when the call has been started and + /// \a request has been written out. If \a start is not set, \a tag must be + /// nullptr and the actual call must be initiated by StartCall + /// Note that \a context will be used to fill in custom initial metadata + /// used to send to the server when starting the call. + template + static ClientAsyncReader* Create(::grpc::ChannelInterface* channel, + ::grpc_impl::CompletionQueue* cq, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context, + const W& request, bool start, void* tag) { + ::grpc::internal::Call call = channel->CreateCall(method, context, cq); + return new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(ClientAsyncReader))) + ClientAsyncReader(call, context, request, start, tag); + } +}; +} // namespace internal + +/// Async client-side API for doing server-streaming RPCs, +/// where the incoming message stream coming from the server has +/// messages of type \a R. +template +class ClientAsyncReader final : public ClientAsyncReaderInterface { + public: + // always allocated against a call arena, no memory free required + static void operator delete(void* ptr, std::size_t size) { + assert(size == sizeof(ClientAsyncReader)); + } + + // 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(void* tag) override { + assert(!started_); + started_ = true; + StartCallInternal(tag); + } + + /// See the \a ClientAsyncStreamingInterface.ReadInitialMetadata + /// method for semantics. + /// + /// Side effect: + /// - upon receiving initial metadata from the server, + /// the \a ClientContext associated with this call is updated, and the + /// calling code can access the received metadata through the + /// \a ClientContext. + void ReadInitialMetadata(void* tag) override { + assert(started_); + GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); + + meta_ops_.set_output_tag(tag); + meta_ops_.RecvInitialMetadata(context_); + call_.PerformOps(&meta_ops_); + } + + void Read(R* msg, void* tag) override { + assert(started_); + read_ops_.set_output_tag(tag); + if (!context_->initial_metadata_received_) { + read_ops_.RecvInitialMetadata(context_); + } + read_ops_.RecvMessage(msg); + call_.PerformOps(&read_ops_); + } + + /// See the \a ClientAsyncStreamingInterface.Finish method for semantics. + /// + /// Side effect: + /// - the \a ClientContext associated with this call is updated with + /// possible initial and trailing metadata received from the server. + void Finish(::grpc::Status* status, void* tag) override { + assert(started_); + finish_ops_.set_output_tag(tag); + if (!context_->initial_metadata_received_) { + finish_ops_.RecvInitialMetadata(context_); + } + finish_ops_.ClientRecvStatus(context_, status); + call_.PerformOps(&finish_ops_); + } + + private: + friend class internal::ClientAsyncReaderFactory; + template + ClientAsyncReader(::grpc::internal::Call call, + ::grpc_impl::ClientContext* context, const W& request, + bool start, void* tag) + : context_(context), call_(call), started_(start) { + // TODO(ctiller): don't assert + GPR_CODEGEN_ASSERT(init_ops_.SendMessage(request).ok()); + init_ops_.ClientSendClose(); + if (start) { + StartCallInternal(tag); + } else { + assert(tag == nullptr); + } + } + + void StartCallInternal(void* tag) { + init_ops_.SendInitialMetadata(&context_->send_initial_metadata_, + context_->initial_metadata_flags()); + init_ops_.set_output_tag(tag); + call_.PerformOps(&init_ops_); + } + + ::grpc_impl::ClientContext* context_; + ::grpc::internal::Call call_; + bool started_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpClientSendClose> + init_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> + meta_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpRecvMessage> + read_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpClientRecvStatus> + finish_ops_; +}; + +/// Common interface for client side asynchronous writing. +template +class ClientAsyncWriterInterface + : public internal::ClientAsyncStreamingInterface, + public internal::AsyncWriterInterface { + public: + /// Signal the client is done with the writes (half-close the client stream). + /// Thread-safe with respect to \a AsyncReaderInterface::Read + /// + /// \param[in] tag The tag identifying the operation. + virtual void WritesDone(void* tag) = 0; +}; + +namespace internal { +template +class ClientAsyncWriterFactory { + public: + /// Create a stream object. + /// Start the RPC if \a start is set + /// \a tag will be notified on \a cq when the call has been started (i.e. + /// intitial metadata sent) and \a request has been written out. + /// If \a start is not set, \a tag must be nullptr and the actual call + /// must be initiated by StartCall + /// Note that \a context will be used to fill in custom initial metadata + /// used to send to the server when starting the call. + /// \a response will be filled in with the single expected response + /// message from the server upon a successful call to the \a Finish + /// method of this instance. + template + static ClientAsyncWriter* Create(::grpc::ChannelInterface* channel, + ::grpc_impl::CompletionQueue* cq, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context, + R* response, bool start, void* tag) { + ::grpc::internal::Call call = channel->CreateCall(method, context, cq); + return new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(ClientAsyncWriter))) + ClientAsyncWriter(call, context, response, start, tag); + } +}; +} // namespace internal + +/// Async API on the client side for doing client-streaming RPCs, +/// where the outgoing message stream going to the server contains +/// messages of type \a W. +template +class ClientAsyncWriter final : public ClientAsyncWriterInterface { + public: + // always allocated against a call arena, no memory free required + static void operator delete(void* ptr, std::size_t size) { + assert(size == sizeof(ClientAsyncWriter)); + } + + // 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(void* tag) override { + assert(!started_); + started_ = true; + StartCallInternal(tag); + } + + /// See the \a ClientAsyncStreamingInterface.ReadInitialMetadata method for + /// semantics. + /// + /// Side effect: + /// - upon receiving initial metadata from the server, the \a ClientContext + /// associated with this call is updated, and the calling code can access + /// the received metadata through the \a ClientContext. + void ReadInitialMetadata(void* tag) override { + assert(started_); + GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); + + meta_ops_.set_output_tag(tag); + meta_ops_.RecvInitialMetadata(context_); + call_.PerformOps(&meta_ops_); + } + + void Write(const W& msg, void* tag) override { + assert(started_); + write_ops_.set_output_tag(tag); + // TODO(ctiller): don't assert + GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok()); + call_.PerformOps(&write_ops_); + } + + void Write(const W& msg, ::grpc::WriteOptions options, void* tag) override { + assert(started_); + write_ops_.set_output_tag(tag); + if (options.is_last_message()) { + options.set_buffer_hint(); + write_ops_.ClientSendClose(); + } + // TODO(ctiller): don't assert + GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok()); + call_.PerformOps(&write_ops_); + } + + void WritesDone(void* tag) override { + assert(started_); + write_ops_.set_output_tag(tag); + write_ops_.ClientSendClose(); + call_.PerformOps(&write_ops_); + } + + /// See the \a ClientAsyncStreamingInterface.Finish method for semantics. + /// + /// Side effect: + /// - the \a ClientContext associated with this call is updated with + /// possible initial and trailing metadata received from the server. + /// - attempts to fill in the \a response parameter passed to this class's + /// constructor with the server's response message. + void Finish(::grpc::Status* status, void* tag) override { + assert(started_); + finish_ops_.set_output_tag(tag); + if (!context_->initial_metadata_received_) { + finish_ops_.RecvInitialMetadata(context_); + } + finish_ops_.ClientRecvStatus(context_, status); + call_.PerformOps(&finish_ops_); + } + + private: + friend class internal::ClientAsyncWriterFactory; + template + ClientAsyncWriter(::grpc::internal::Call call, + ::grpc_impl::ClientContext* context, R* response, + bool start, void* tag) + : context_(context), call_(call), started_(start) { + finish_ops_.RecvMessage(response); + finish_ops_.AllowNoMessage(); + if (start) { + StartCallInternal(tag); + } else { + assert(tag == nullptr); + } + } + + void StartCallInternal(void* tag) { + write_ops_.SendInitialMetadata(&context_->send_initial_metadata_, + context_->initial_metadata_flags()); + // if corked bit is set in context, we just keep the initial metadata + // buffered up to coalesce with later message send. No op is performed. + if (!context_->initial_metadata_corked_) { + write_ops_.set_output_tag(tag); + call_.PerformOps(&write_ops_); + } + } + + ::grpc_impl::ClientContext* context_; + ::grpc::internal::Call call_; + bool started_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> + meta_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpClientSendClose> + write_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpGenericRecvMessage, + ::grpc::internal::CallOpClientRecvStatus> + finish_ops_; +}; + +/// Async client-side interface for bi-directional streaming, +/// where the client-to-server message stream has messages of type \a W, +/// and the server-to-client message stream has messages of type \a R. +template +class ClientAsyncReaderWriterInterface + : public internal::ClientAsyncStreamingInterface, + public internal::AsyncWriterInterface, + public internal::AsyncReaderInterface { + public: + /// Signal the client is done with the writes (half-close the client stream). + /// Thread-safe with respect to \a AsyncReaderInterface::Read + /// + /// \param[in] tag The tag identifying the operation. + virtual void WritesDone(void* tag) = 0; +}; + +namespace internal { +template +class ClientAsyncReaderWriterFactory { + public: + /// Create a stream object. + /// Start the RPC request if \a start is set. + /// \a tag will be notified on \a cq when the call has been started (i.e. + /// intitial metadata sent). If \a start is not set, \a tag must be + /// nullptr and the actual call must be initiated by StartCall + /// Note that \a context will be used to fill in custom initial metadata + /// used to send to the server when starting the call. + static ClientAsyncReaderWriter* Create( + ::grpc::ChannelInterface* channel, ::grpc_impl::CompletionQueue* cq, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context, bool start, void* tag) { + ::grpc::internal::Call call = channel->CreateCall(method, context, cq); + + return new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(ClientAsyncReaderWriter))) + ClientAsyncReaderWriter(call, context, start, tag); + } +}; +} // namespace internal + +/// Async client-side interface for bi-directional streaming, +/// where the outgoing message stream going to the server +/// has messages of type \a W, and the incoming message stream coming +/// from the server has messages of type \a R. +template +class ClientAsyncReaderWriter final + : public ClientAsyncReaderWriterInterface { + public: + // always allocated against a call arena, no memory free required + static void operator delete(void* ptr, std::size_t size) { + assert(size == sizeof(ClientAsyncReaderWriter)); + } + + // 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(void* tag) override { + assert(!started_); + started_ = true; + StartCallInternal(tag); + } + + /// See the \a ClientAsyncStreamingInterface.ReadInitialMetadata method + /// for semantics of this method. + /// + /// Side effect: + /// - upon receiving initial metadata from the server, the \a ClientContext + /// is updated with it, and then the receiving initial metadata can + /// be accessed through this \a ClientContext. + void ReadInitialMetadata(void* tag) override { + assert(started_); + GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); + + meta_ops_.set_output_tag(tag); + meta_ops_.RecvInitialMetadata(context_); + call_.PerformOps(&meta_ops_); + } + + void Read(R* msg, void* tag) override { + assert(started_); + read_ops_.set_output_tag(tag); + if (!context_->initial_metadata_received_) { + read_ops_.RecvInitialMetadata(context_); + } + read_ops_.RecvMessage(msg); + call_.PerformOps(&read_ops_); + } + + void Write(const W& msg, void* tag) override { + assert(started_); + write_ops_.set_output_tag(tag); + // TODO(ctiller): don't assert + GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok()); + call_.PerformOps(&write_ops_); + } + + void Write(const W& msg, ::grpc::WriteOptions options, void* tag) override { + assert(started_); + write_ops_.set_output_tag(tag); + if (options.is_last_message()) { + options.set_buffer_hint(); + write_ops_.ClientSendClose(); + } + // TODO(ctiller): don't assert + GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok()); + call_.PerformOps(&write_ops_); + } + + void WritesDone(void* tag) override { + assert(started_); + write_ops_.set_output_tag(tag); + write_ops_.ClientSendClose(); + call_.PerformOps(&write_ops_); + } + + /// See the \a ClientAsyncStreamingInterface.Finish method for semantics. + /// Side effect + /// - the \a ClientContext associated with this call is updated with + /// possible initial and trailing metadata sent from the server. + void Finish(::grpc::Status* status, void* tag) override { + assert(started_); + finish_ops_.set_output_tag(tag); + if (!context_->initial_metadata_received_) { + finish_ops_.RecvInitialMetadata(context_); + } + finish_ops_.ClientRecvStatus(context_, status); + call_.PerformOps(&finish_ops_); + } + + private: + friend class internal::ClientAsyncReaderWriterFactory; + ClientAsyncReaderWriter(::grpc::internal::Call call, + ::grpc_impl::ClientContext* context, bool start, + void* tag) + : context_(context), call_(call), started_(start) { + if (start) { + StartCallInternal(tag); + } else { + assert(tag == nullptr); + } + } + + void StartCallInternal(void* tag) { + write_ops_.SendInitialMetadata(&context_->send_initial_metadata_, + context_->initial_metadata_flags()); + // if corked bit is set in context, we just keep the initial metadata + // buffered up to coalesce with later message send. No op is performed. + if (!context_->initial_metadata_corked_) { + write_ops_.set_output_tag(tag); + call_.PerformOps(&write_ops_); + } + } + + ::grpc_impl::ClientContext* context_; + ::grpc::internal::Call call_; + bool started_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> + meta_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpRecvMessage> + read_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpClientSendClose> + write_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpClientRecvStatus> + finish_ops_; +}; + +template +class ServerAsyncReaderInterface + : public ::grpc::internal::ServerAsyncStreamingInterface, + public internal::AsyncReaderInterface { + public: + /// Indicate that the stream is to be finished with a certain status code + /// and also send out \a msg response to the client. + /// Request notification for when the server has sent the response and the + /// appropriate signals to the client to end the call. + /// Should not be used concurrently with other operations. + /// + /// It is appropriate to call this method when: + /// * all messages from the client have been received (either known + /// implictly, or explicitly because a previous + /// \a AsyncReaderInterface::Read operation with a non-ok result, + /// e.g., cq->Next(&read_tag, &ok) filled in 'ok' with 'false'). + /// + /// This operation will end when the server has finished sending out initial + /// metadata (if not sent already), response message, and status, or if + /// 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 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. + /// \param[in] msg To be sent to the client as the response for this call. + virtual void Finish(const W& msg, const ::grpc::Status& status, + void* tag) = 0; + + /// Indicate that the stream is to be finished with a certain + /// non-OK status code. + /// Request notification for when the server has sent the appropriate + /// signals to the client to end the call. + /// Should not be used concurrently with other operations. + /// + /// This call is meant to end the call with some error, and can be called at + /// any point that the server would like to "fail" the call (though note + /// this shouldn't be called concurrently with any other "sending" call, like + /// \a AsyncWriterInterface::Write). + /// + /// This operation will end when the server has finished sending out initial + /// metadata (if not sent already), and status, or if some failure occurred + /// when trying to do so. + /// + /// gRPC doesn't take ownership or a reference to \a status, so it is safe to + /// to deallocate once FinishWithError returns. + /// + /// \param[in] tag Tag identifying this request. + /// \param[in] status To be sent to the client as the result of this call. + /// - Note: \a status must have a non-OK code. + virtual void FinishWithError(const ::grpc::Status& status, void* tag) = 0; +}; + +/// Async server-side API for doing client-streaming RPCs, +/// where the incoming message stream from the client has messages of type \a R, +/// and the single response message sent from the server is type \a W. +template +class ServerAsyncReader final : public ServerAsyncReaderInterface { + public: + explicit ServerAsyncReader(::grpc_impl::ServerContext* ctx) + : call_(nullptr, nullptr, nullptr), ctx_(ctx) {} + + /// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics. + /// + /// Implicit input parameter: + /// - The initial metadata that will be sent to the client from this op will + /// be taken from the \a ServerContext associated with the call. + void SendInitialMetadata(void* tag) override { + GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); + + meta_ops_.set_output_tag(tag); + meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + meta_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + call_.PerformOps(&meta_ops_); + } + + void Read(R* msg, void* tag) override { + read_ops_.set_output_tag(tag); + read_ops_.RecvMessage(msg); + call_.PerformOps(&read_ops_); + } + + /// See the \a ServerAsyncReaderInterface.Read method for semantics + /// + /// Side effect: + /// - also sends initial metadata if not alreay sent. + /// - uses the \a ServerContext associated with this call to send possible + /// initial and trailing metadata. + /// + /// 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 deallocate once Finish returns. + void Finish(const W& msg, const ::grpc::Status& status, void* tag) override { + finish_ops_.set_output_tag(tag); + if (!ctx_->sent_initial_metadata_) { + finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + finish_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + } + // The response is dropped if the status is not OK. + if (status.ok()) { + finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, + finish_ops_.SendMessage(msg)); + } else { + finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status); + } + call_.PerformOps(&finish_ops_); + } + + /// See the \a ServerAsyncReaderInterface.Read method for semantics + /// + /// Side effect: + /// - also sends initial metadata if not alreay sent. + /// - uses the \a ServerContext associated with this call to send possible + /// initial and trailing metadata. + /// + /// gRPC doesn't take ownership or a reference to \a status, so it is safe to + /// to deallocate once FinishWithError returns. + void FinishWithError(const ::grpc::Status& status, void* tag) override { + GPR_CODEGEN_ASSERT(!status.ok()); + finish_ops_.set_output_tag(tag); + if (!ctx_->sent_initial_metadata_) { + finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + finish_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + } + finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status); + call_.PerformOps(&finish_ops_); + } + + private: + void BindCall(::grpc::internal::Call* call) override { call_ = *call; } + + ::grpc::internal::Call call_; + ::grpc_impl::ServerContext* ctx_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> + meta_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage> read_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpServerSendStatus> + finish_ops_; +}; + +template +class ServerAsyncWriterInterface + : public ::grpc::internal::ServerAsyncStreamingInterface, + public internal::AsyncWriterInterface { + public: + /// Indicate that the stream is to be finished with a certain status code. + /// Request notification for when the server has sent the appropriate + /// signals to the client to end the call. + /// Should not be used concurrently with other operations. + /// + /// It is appropriate to call this method when either: + /// * all messages from the client have been received (either known + /// implictly, or explicitly because a previous \a + /// AsyncReaderInterface::Read operation with a non-ok + /// result (e.g., cq->Next(&read_tag, &ok) filled in 'ok' with 'false'. + /// * it is desired to end the call early with some non-OK status code. + /// + /// This operation will end when the server has finished sending out initial + /// metadata (if not sent already), response message, and status, or if + /// some failure occurred when trying to do so. + /// + /// gRPC doesn't take ownership or a reference to \a status, so it is safe to + /// 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. + virtual void Finish(const ::grpc::Status& status, void* tag) = 0; + + /// Request the writing of \a msg and coalesce it with trailing metadata which + /// contains \a status, using WriteOptions options with + /// identifying tag \a tag. + /// + /// WriteAndFinish is equivalent of performing WriteLast and Finish + /// in a single step. + /// + /// gRPC doesn't take ownership or a reference to \a msg and \a status, so it + /// 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. + /// \param[in] status The Status that server returns to client. + /// \param[in] tag The tag identifying the operation. + virtual void WriteAndFinish(const W& msg, ::grpc::WriteOptions options, + const ::grpc::Status& status, void* tag) = 0; +}; + +/// Async server-side API for doing server streaming RPCs, +/// where the outgoing message stream from the server has messages of type \a W. +template +class ServerAsyncWriter final : public ServerAsyncWriterInterface { + public: + explicit ServerAsyncWriter(::grpc_impl::ServerContext* ctx) + : call_(nullptr, nullptr, nullptr), ctx_(ctx) {} + + /// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics. + /// + /// Implicit input parameter: + /// - The initial metadata that will be sent to the client from this op will + /// be taken from the \a ServerContext associated with the call. + /// + /// \param[in] tag Tag identifying this request. + void SendInitialMetadata(void* tag) override { + GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); + + meta_ops_.set_output_tag(tag); + meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + meta_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + call_.PerformOps(&meta_ops_); + } + + void Write(const W& msg, void* tag) override { + write_ops_.set_output_tag(tag); + EnsureInitialMetadataSent(&write_ops_); + // TODO(ctiller): don't assert + GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok()); + call_.PerformOps(&write_ops_); + } + + void Write(const W& msg, ::grpc::WriteOptions options, void* tag) override { + write_ops_.set_output_tag(tag); + if (options.is_last_message()) { + options.set_buffer_hint(); + } + + EnsureInitialMetadataSent(&write_ops_); + // TODO(ctiller): don't assert + GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok()); + call_.PerformOps(&write_ops_); + } + + /// See the \a ServerAsyncWriterInterface.WriteAndFinish method for semantics. + /// + /// Implicit input parameter: + /// - the \a ServerContext associated with this call is used + /// for sending trailing (and initial) metadata to the client. + /// + /// 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 deallocate once WriteAndFinish returns. + void WriteAndFinish(const W& msg, ::grpc::WriteOptions options, + const ::grpc::Status& status, void* tag) override { + write_ops_.set_output_tag(tag); + EnsureInitialMetadataSent(&write_ops_); + options.set_buffer_hint(); + GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok()); + write_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status); + call_.PerformOps(&write_ops_); + } + + /// See the \a ServerAsyncWriterInterface.Finish method for semantics. + /// + /// Implicit input parameter: + /// - the \a ServerContext associated with this call is used for sending + /// trailing (and initial if not already sent) metadata to the client. + /// + /// Note: there are no restrictions are the code of + /// \a status,it may be non-OK + /// + /// gRPC doesn't take ownership or a reference to \a status, so it is safe to + /// to deallocate once Finish returns. + void Finish(const ::grpc::Status& status, void* tag) override { + finish_ops_.set_output_tag(tag); + EnsureInitialMetadataSent(&finish_ops_); + finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status); + call_.PerformOps(&finish_ops_); + } + + private: + void BindCall(::grpc::internal::Call* call) override { call_ = *call; } + + template + void EnsureInitialMetadataSent(T* ops) { + if (!ctx_->sent_initial_metadata_) { + ops->SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + ops->set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + } + } + + ::grpc::internal::Call call_; + ::grpc_impl::ServerContext* ctx_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> + meta_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpServerSendStatus> + write_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpServerSendStatus> + finish_ops_; +}; + +/// Server-side interface for asynchronous bi-directional streaming. +template +class ServerAsyncReaderWriterInterface + : public ::grpc::internal::ServerAsyncStreamingInterface, + public internal::AsyncWriterInterface, + public internal::AsyncReaderInterface { + public: + /// Indicate that the stream is to be finished with a certain status code. + /// Request notification for when the server has sent the appropriate + /// signals to the client to end the call. + /// Should not be used concurrently with other operations. + /// + /// It is appropriate to call this method when either: + /// * all messages from the client have been received (either known + /// implictly, or explicitly because a previous \a + /// AsyncReaderInterface::Read operation + /// with a non-ok result (e.g., cq->Next(&read_tag, &ok) filled in 'ok' + /// with 'false'. + /// * it is desired to end the call early with some non-OK status code. + /// + /// This operation will end when the server has finished sending out initial + /// metadata (if not sent already), response message, and status, or if some + /// failure occurred when trying to do so. + /// + /// gRPC doesn't take ownership or a reference to \a status, so it is safe to + /// 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. + virtual void Finish(const ::grpc::Status& status, void* tag) = 0; + + /// Request the writing of \a msg and coalesce it with trailing metadata which + /// contains \a status, using WriteOptions options with + /// identifying tag \a tag. + /// + /// WriteAndFinish is equivalent of performing WriteLast and Finish in a + /// single step. + /// + /// gRPC doesn't take ownership or a reference to \a msg and \a status, so it + /// 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. + /// \param[in] status The Status that server returns to client. + /// \param[in] tag The tag identifying the operation. + virtual void WriteAndFinish(const W& msg, ::grpc::WriteOptions options, + const ::grpc::Status& status, void* tag) = 0; +}; + +/// Async server-side API for doing bidirectional streaming RPCs, +/// where the incoming message stream coming from the client has messages of +/// type \a R, and the outgoing message stream coming from the server has +/// messages of type \a W. +template +class ServerAsyncReaderWriter final + : public ServerAsyncReaderWriterInterface { + public: + explicit ServerAsyncReaderWriter(::grpc_impl::ServerContext* ctx) + : call_(nullptr, nullptr, nullptr), ctx_(ctx) {} + + /// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics. + /// + /// Implicit input parameter: + /// - The initial metadata that will be sent to the client from this op will + /// be taken from the \a ServerContext associated with the call. + /// + /// \param[in] tag Tag identifying this request. + void SendInitialMetadata(void* tag) override { + GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); + + meta_ops_.set_output_tag(tag); + meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + meta_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + call_.PerformOps(&meta_ops_); + } + + void Read(R* msg, void* tag) override { + read_ops_.set_output_tag(tag); + read_ops_.RecvMessage(msg); + call_.PerformOps(&read_ops_); + } + + void Write(const W& msg, void* tag) override { + write_ops_.set_output_tag(tag); + EnsureInitialMetadataSent(&write_ops_); + // TODO(ctiller): don't assert + GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok()); + call_.PerformOps(&write_ops_); + } + + void Write(const W& msg, ::grpc::WriteOptions options, void* tag) override { + write_ops_.set_output_tag(tag); + if (options.is_last_message()) { + options.set_buffer_hint(); + } + EnsureInitialMetadataSent(&write_ops_); + GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok()); + call_.PerformOps(&write_ops_); + } + + /// See the \a ServerAsyncReaderWriterInterface.WriteAndFinish + /// method for semantics. + /// + /// Implicit input parameter: + /// - the \a ServerContext associated with this call is used + /// for sending trailing (and initial) metadata to the client. + /// + /// 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 deallocate once WriteAndFinish returns. + void WriteAndFinish(const W& msg, ::grpc::WriteOptions options, + const ::grpc::Status& status, void* tag) override { + write_ops_.set_output_tag(tag); + EnsureInitialMetadataSent(&write_ops_); + options.set_buffer_hint(); + GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg, options).ok()); + write_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status); + call_.PerformOps(&write_ops_); + } + + /// See the \a ServerAsyncReaderWriterInterface.Finish method for semantics. + /// + /// Implicit input parameter: + /// - the \a ServerContext associated with this call is used for sending + /// trailing (and initial if not already sent) metadata to the client. + /// + /// Note: there are no restrictions are the code of \a status, + /// it may be non-OK + // + /// gRPC doesn't take ownership or a reference to \a status, so it is safe to + /// to deallocate once Finish returns. + void Finish(const ::grpc::Status& status, void* tag) override { + finish_ops_.set_output_tag(tag); + EnsureInitialMetadataSent(&finish_ops_); + + finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, status); + call_.PerformOps(&finish_ops_); + } + + private: + friend class ::grpc_impl::Server; + + void BindCall(::grpc::internal::Call* call) override { call_ = *call; } + + template + void EnsureInitialMetadataSent(T* ops) { + if (!ctx_->sent_initial_metadata_) { + ops->SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + ops->set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + } + } + + ::grpc::internal::Call call_; + ::grpc_impl::ServerContext* ctx_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> + meta_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage> read_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpServerSendStatus> + write_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpServerSendStatus> + finish_ops_; +}; + +} // namespace grpc_impl +#endif // GRPCPP_IMPL_CODEGEN_ASYNC_STREAM_IMPL_H diff --git a/include/grpcpp/impl/codegen/async_unary_call.h b/include/grpcpp/impl/codegen/async_unary_call.h index 5da6a649f14..64ee17dec0d 100644 --- a/include/grpcpp/impl/codegen/async_unary_call.h +++ b/include/grpcpp/impl/codegen/async_unary_call.h @@ -19,299 +19,18 @@ #ifndef GRPCPP_IMPL_CODEGEN_ASYNC_UNARY_CALL_H #define GRPCPP_IMPL_CODEGEN_ASYNC_UNARY_CALL_H -#include -#include -#include -#include -#include -#include -#include +#include namespace grpc { - -extern CoreCodegenInterface* g_core_codegen_interface; - -/// An interface relevant for async client side unary RPCs (which send -/// one request message to a server and receive one response message). -template -class ClientAsyncResponseReaderInterface { - public: - virtual ~ClientAsyncResponseReaderInterface() {} - - /// Start the call that was set up by the constructor, but only if the - /// constructor was invoked through the "Prepare" API which doesn't actually - /// start the call - virtual void StartCall() = 0; - - /// Request notification of the reading of initial metadata. Completion - /// will be notified by \a tag on the associated completion queue. - /// This call is optional, but if it is used, it cannot be used concurrently - /// with or after the \a Finish method. - /// - /// \param[in] tag Tag identifying this request. - virtual void ReadInitialMetadata(void* tag) = 0; - - /// Request to receive the server's response \a msg and final \a status for - /// the call, and to notify \a tag on this call's completion queue when - /// finished. - /// - /// This function will return when either: - /// - when the server's response message and status have been received. - /// - when the server has returned a non-OK status (no message expected in - /// this case). - /// - when the call failed for some reason and the library generated a - /// non-OK status. - /// - /// \param[in] tag Tag identifying this request. - /// \param[out] status To be updated with the operation status. - /// \param[out] msg To be filled in with the server's response message. - virtual void Finish(R* msg, Status* status, void* tag) = 0; -}; - -namespace internal { template -class ClientAsyncResponseReaderFactory { - public: - /// Start a call and write the request out if \a start is set. - /// \a tag will be notified on \a cq when the call has been started (i.e. - /// intitial metadata sent) and \a request has been written out. - /// If \a start is not set, the actual call must be initiated by StartCall - /// Note that \a context will be used to fill in custom initial metadata - /// used to send to the server when starting the call. - template - static ClientAsyncResponseReader* Create( - ChannelInterface* channel, ::grpc_impl::CompletionQueue* cq, - const ::grpc::internal::RpcMethod& method, - ::grpc_impl::ClientContext* context, const W& request, bool start) { - ::grpc::internal::Call call = channel->CreateCall(method, context, cq); - return new (g_core_codegen_interface->grpc_call_arena_alloc( - call.call(), sizeof(ClientAsyncResponseReader))) - ClientAsyncResponseReader(call, context, request, start); - } -}; -} // namespace internal - -/// Async API for client-side unary RPCs, where the message response -/// received from the server is of type \a R. +using ClientAsyncResponseReaderInterface = + grpc_impl::ClientAsyncResponseReaderInterface; template -class ClientAsyncResponseReader final - : public ClientAsyncResponseReaderInterface { - public: - // always allocated against a call arena, no memory free required - static void operator delete(void* ptr, std::size_t size) { - assert(size == sizeof(ClientAsyncResponseReader)); - } - - // 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 { - assert(!started_); - started_ = true; - StartCallInternal(); - } - - /// See \a ClientAsyncResponseReaderInterface::ReadInitialMetadata for - /// semantics. - /// - /// Side effect: - /// - the \a ClientContext associated with this call is updated with - /// possible initial and trailing metadata sent from the server. - void ReadInitialMetadata(void* tag) override { - assert(started_); - GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); - - single_buf.set_output_tag(tag); - single_buf.RecvInitialMetadata(context_); - call_.PerformOps(&single_buf); - initial_metadata_read_ = true; - } - - /// See \a ClientAysncResponseReaderInterface::Finish for semantics. - /// - /// Side effect: - /// - the \a ClientContext associated with this call is updated with - /// possible initial and trailing metadata sent from the server. - void Finish(R* msg, Status* status, void* tag) override { - assert(started_); - if (initial_metadata_read_) { - finish_buf.set_output_tag(tag); - finish_buf.RecvMessage(msg); - finish_buf.AllowNoMessage(); - finish_buf.ClientRecvStatus(context_, status); - call_.PerformOps(&finish_buf); - } else { - single_buf.set_output_tag(tag); - single_buf.RecvInitialMetadata(context_); - single_buf.RecvMessage(msg); - single_buf.AllowNoMessage(); - single_buf.ClientRecvStatus(context_, status); - call_.PerformOps(&single_buf); - } - } - - private: - friend class internal::ClientAsyncResponseReaderFactory; - ::grpc_impl::ClientContext* const context_; - ::grpc::internal::Call call_; - bool started_; - bool initial_metadata_read_ = false; +using ClientAsyncResponseReader = grpc_impl::ClientAsyncResponseReader; - template - ClientAsyncResponseReader(::grpc::internal::Call call, - ::grpc_impl::ClientContext* context, - const W& request, bool start) - : context_(context), call_(call), started_(start) { - // Bind the metadata at time of StartCallInternal but set up the rest here - // TODO(ctiller): don't assert - GPR_CODEGEN_ASSERT(single_buf.SendMessage(request).ok()); - single_buf.ClientSendClose(); - if (start) StartCallInternal(); - } - - void StartCallInternal() { - single_buf.SendInitialMetadata(&context_->send_initial_metadata_, - context_->initial_metadata_flags()); - } - - // disable operator new - static void* operator new(std::size_t size); - static void* operator new(std::size_t size, void* p) { return p; } - - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpClientSendClose, - ::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpRecvMessage, - ::grpc::internal::CallOpClientRecvStatus> - single_buf; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage, - ::grpc::internal::CallOpClientRecvStatus> - finish_buf; -}; - -/// Async server-side API for handling unary calls, where the single -/// response message sent to the client is of type \a W. template -class ServerAsyncResponseWriter final - : public internal::ServerAsyncStreamingInterface { - public: - explicit ServerAsyncResponseWriter(::grpc_impl::ServerContext* ctx) - : call_(nullptr, nullptr, nullptr), ctx_(ctx) {} - - /// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics. - /// - /// Side effect: - /// The initial metadata that will be sent to the client from this op will - /// be taken from the \a ServerContext associated with the call. - /// - /// \param[in] tag Tag identifying this request. - void SendInitialMetadata(void* tag) override { - GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); - - meta_buf_.set_output_tag(tag); - meta_buf_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - meta_buf_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - call_.PerformOps(&meta_buf_); - } - - /// Indicate that the stream is to be finished and request notification - /// when the server has sent the appropriate signals to the client to - /// end the call. Should not be used concurrently with other operations. - /// - /// \param[in] tag Tag identifying this request. - /// \param[in] status To be sent to the client as the result of the call. - /// \param[in] msg Message to be sent to the client. - /// - /// Side effect: - /// - also sends initial metadata if not already sent (using the - /// \a ServerContext associated with this call). - /// - /// Note: if \a status has a non-OK code, then \a msg will not be sent, - /// and the client will receive only the status with possible trailing - /// metadata. - void Finish(const W& msg, const Status& status, void* tag) { - finish_buf_.set_output_tag(tag); - finish_buf_.set_core_cq_tag(&finish_buf_); - if (!ctx_->sent_initial_metadata_) { - finish_buf_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - finish_buf_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - } - // The response is dropped if the status is not OK. - if (status.ok()) { - finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_, - finish_buf_.SendMessage(msg)); - } else { - finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_, status); - } - call_.PerformOps(&finish_buf_); - } - - /// Indicate that the stream is to be finished with a non-OK status, - /// and request notification for when the server has finished sending the - /// appropriate signals to the client to end the call. - /// Should not be used concurrently with other operations. - /// - /// \param[in] tag Tag identifying this request. - /// \param[in] status To be sent to the client as the result of the call. - /// - Note: \a status must have a non-OK code. - /// - /// Side effect: - /// - also sends initial metadata if not already sent (using the - /// \a ServerContext associated with this call). - void FinishWithError(const Status& status, void* tag) { - GPR_CODEGEN_ASSERT(!status.ok()); - finish_buf_.set_output_tag(tag); - if (!ctx_->sent_initial_metadata_) { - finish_buf_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - finish_buf_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - } - finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_, status); - call_.PerformOps(&finish_buf_); - } - - private: - void BindCall(::grpc::internal::Call* call) override { call_ = *call; } - - ::grpc::internal::Call call_; - ::grpc_impl::ServerContext* ctx_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> - meta_buf_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpServerSendStatus> - finish_buf_; -}; +using ServerAsyncResponseWriter = ::grpc_impl::ServerAsyncResponseWriter; } // namespace grpc -namespace std { -template -class default_delete> { - public: - void operator()(void* p) {} -}; -template -class default_delete> { - public: - void operator()(void* p) {} -}; -} // namespace std - #endif // GRPCPP_IMPL_CODEGEN_ASYNC_UNARY_CALL_H diff --git a/include/grpcpp/impl/codegen/async_unary_call_impl.h b/include/grpcpp/impl/codegen/async_unary_call_impl.h new file mode 100644 index 00000000000..ff8bf15602b --- /dev/null +++ b/include/grpcpp/impl/codegen/async_unary_call_impl.h @@ -0,0 +1,315 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPCPP_IMPL_CODEGEN_ASYNC_UNARY_CALL_IMPL_H +#define GRPCPP_IMPL_CODEGEN_ASYNC_UNARY_CALL_IMPL_H + +#include +#include +#include +#include +#include +#include +#include + +namespace grpc_impl { + +/// An interface relevant for async client side unary RPCs (which send +/// one request message to a server and receive one response message). +template +class ClientAsyncResponseReaderInterface { + public: + virtual ~ClientAsyncResponseReaderInterface() {} + + /// Start the call that was set up by the constructor, but only if the + /// constructor was invoked through the "Prepare" API which doesn't actually + /// start the call + virtual void StartCall() = 0; + + /// Request notification of the reading of initial metadata. Completion + /// will be notified by \a tag on the associated completion queue. + /// This call is optional, but if it is used, it cannot be used concurrently + /// with or after the \a Finish method. + /// + /// \param[in] tag Tag identifying this request. + virtual void ReadInitialMetadata(void* tag) = 0; + + /// Request to receive the server's response \a msg and final \a status for + /// the call, and to notify \a tag on this call's completion queue when + /// finished. + /// + /// This function will return when either: + /// - when the server's response message and status have been received. + /// - when the server has returned a non-OK status (no message expected in + /// this case). + /// - when the call failed for some reason and the library generated a + /// non-OK status. + /// + /// \param[in] tag Tag identifying this request. + /// \param[out] status To be updated with the operation status. + /// \param[out] msg To be filled in with the server's response message. + virtual void Finish(R* msg, ::grpc::Status* status, void* tag) = 0; +}; + +namespace internal { +template +class ClientAsyncResponseReaderFactory { + public: + /// Start a call and write the request out if \a start is set. + /// \a tag will be notified on \a cq when the call has been started (i.e. + /// intitial metadata sent) and \a request has been written out. + /// If \a start is not set, the actual call must be initiated by StartCall + /// Note that \a context will be used to fill in custom initial metadata + /// used to send to the server when starting the call. + template + static ClientAsyncResponseReader* Create( + ::grpc::ChannelInterface* channel, ::grpc_impl::CompletionQueue* cq, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context, const W& request, bool start) { + ::grpc::internal::Call call = channel->CreateCall(method, context, cq); + return new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(ClientAsyncResponseReader))) + ClientAsyncResponseReader(call, context, request, start); + } +}; +} // namespace internal + +/// Async API for client-side unary RPCs, where the message response +/// received from the server is of type \a R. +template +class ClientAsyncResponseReader final + : public ClientAsyncResponseReaderInterface { + public: + // always allocated against a call arena, no memory free required + static void operator delete(void* ptr, std::size_t size) { + assert(size == sizeof(ClientAsyncResponseReader)); + } + + // 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 { + assert(!started_); + started_ = true; + StartCallInternal(); + } + + /// See \a ClientAsyncResponseReaderInterface::ReadInitialMetadata for + /// semantics. + /// + /// Side effect: + /// - the \a ClientContext associated with this call is updated with + /// possible initial and trailing metadata sent from the server. + void ReadInitialMetadata(void* tag) override { + assert(started_); + GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); + + single_buf.set_output_tag(tag); + single_buf.RecvInitialMetadata(context_); + call_.PerformOps(&single_buf); + initial_metadata_read_ = true; + } + + /// See \a ClientAysncResponseReaderInterface::Finish for semantics. + /// + /// Side effect: + /// - the \a ClientContext associated with this call is updated with + /// possible initial and trailing metadata sent from the server. + void Finish(R* msg, ::grpc::Status* status, void* tag) override { + assert(started_); + if (initial_metadata_read_) { + finish_buf.set_output_tag(tag); + finish_buf.RecvMessage(msg); + finish_buf.AllowNoMessage(); + finish_buf.ClientRecvStatus(context_, status); + call_.PerformOps(&finish_buf); + } else { + single_buf.set_output_tag(tag); + single_buf.RecvInitialMetadata(context_); + single_buf.RecvMessage(msg); + single_buf.AllowNoMessage(); + single_buf.ClientRecvStatus(context_, status); + call_.PerformOps(&single_buf); + } + } + + private: + friend class internal::ClientAsyncResponseReaderFactory; + ::grpc_impl::ClientContext* const context_; + ::grpc::internal::Call call_; + bool started_; + bool initial_metadata_read_ = false; + + template + ClientAsyncResponseReader(::grpc::internal::Call call, + ::grpc_impl::ClientContext* context, + const W& request, bool start) + : context_(context), call_(call), started_(start) { + // Bind the metadata at time of StartCallInternal but set up the rest here + // TODO(ctiller): don't assert + GPR_CODEGEN_ASSERT(single_buf.SendMessage(request).ok()); + single_buf.ClientSendClose(); + if (start) StartCallInternal(); + } + + void StartCallInternal() { + single_buf.SendInitialMetadata(&context_->send_initial_metadata_, + context_->initial_metadata_flags()); + } + + // disable operator new + static void* operator new(std::size_t size); + static void* operator new(std::size_t size, void* p) { return p; } + + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpClientSendClose, + ::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpRecvMessage, + ::grpc::internal::CallOpClientRecvStatus> + single_buf; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage, + ::grpc::internal::CallOpClientRecvStatus> + finish_buf; +}; + +/// Async server-side API for handling unary calls, where the single +/// response message sent to the client is of type \a W. +template +class ServerAsyncResponseWriter final + : public ::grpc::internal::ServerAsyncStreamingInterface { + public: + explicit ServerAsyncResponseWriter(::grpc_impl::ServerContext* ctx) + : call_(nullptr, nullptr, nullptr), ctx_(ctx) {} + + /// See \a ServerAsyncStreamingInterface::SendInitialMetadata for semantics. + /// + /// Side effect: + /// The initial metadata that will be sent to the client from this op will + /// be taken from the \a ServerContext associated with the call. + /// + /// \param[in] tag Tag identifying this request. + void SendInitialMetadata(void* tag) override { + GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); + + meta_buf_.set_output_tag(tag); + meta_buf_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + meta_buf_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + call_.PerformOps(&meta_buf_); + } + + /// Indicate that the stream is to be finished and request notification + /// when the server has sent the appropriate signals to the client to + /// end the call. Should not be used concurrently with other operations. + /// + /// \param[in] tag Tag identifying this request. + /// \param[in] status To be sent to the client as the result of the call. + /// \param[in] msg Message to be sent to the client. + /// + /// Side effect: + /// - also sends initial metadata if not already sent (using the + /// \a ServerContext associated with this call). + /// + /// Note: if \a status has a non-OK code, then \a msg will not be sent, + /// and the client will receive only the status with possible trailing + /// metadata. + void Finish(const W& msg, const ::grpc::Status& status, void* tag) { + finish_buf_.set_output_tag(tag); + finish_buf_.set_core_cq_tag(&finish_buf_); + if (!ctx_->sent_initial_metadata_) { + finish_buf_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + finish_buf_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + } + // The response is dropped if the status is not OK. + if (status.ok()) { + finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_, + finish_buf_.SendMessage(msg)); + } else { + finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_, status); + } + call_.PerformOps(&finish_buf_); + } + + /// Indicate that the stream is to be finished with a non-OK status, + /// and request notification for when the server has finished sending the + /// appropriate signals to the client to end the call. + /// Should not be used concurrently with other operations. + /// + /// \param[in] tag Tag identifying this request. + /// \param[in] status To be sent to the client as the result of the call. + /// - Note: \a status must have a non-OK code. + /// + /// Side effect: + /// - also sends initial metadata if not already sent (using the + /// \a ServerContext associated with this call). + void FinishWithError(const ::grpc::Status& status, void* tag) { + GPR_CODEGEN_ASSERT(!status.ok()); + finish_buf_.set_output_tag(tag); + if (!ctx_->sent_initial_metadata_) { + finish_buf_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + finish_buf_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + } + finish_buf_.ServerSendStatus(&ctx_->trailing_metadata_, status); + call_.PerformOps(&finish_buf_); + } + + private: + void BindCall(::grpc::internal::Call* call) override { call_ = *call; } + + ::grpc::internal::Call call_; + ::grpc_impl::ServerContext* ctx_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> + meta_buf_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpServerSendStatus> + finish_buf_; +}; + +} // namespace grpc_impl + +namespace std { +template +class default_delete<::grpc_impl::ClientAsyncResponseReader> { + public: + void operator()(void* p) {} +}; +template +class default_delete<::grpc_impl::ClientAsyncResponseReaderInterface> { + public: + void operator()(void* p) {} +}; +} // namespace std + +#endif // GRPCPP_IMPL_CODEGEN_ASYNC_UNARY_CALL_IMPL_H diff --git a/include/grpcpp/impl/codegen/byte_buffer.h b/include/grpcpp/impl/codegen/byte_buffer.h index e2ba9344bcb..0b7be6fc753 100644 --- a/include/grpcpp/impl/codegen/byte_buffer.h +++ b/include/grpcpp/impl/codegen/byte_buffer.h @@ -29,6 +29,17 @@ #include +namespace grpc_impl { +namespace internal { + +template +class CallbackUnaryHandler; +template +class CallbackServerStreamingHandler; + +} // namespace internal +} // namespace grpc_impl + namespace grpc { class ServerInterface; @@ -45,10 +56,6 @@ template class RpcMethodHandler; template class ServerStreamingHandler; -template -class CallbackUnaryHandler; -template -class CallbackServerStreamingHandler; template class ErrorMethodHandler; class ExternalConnectionAcceptorImpl; @@ -176,9 +183,9 @@ class ByteBuffer final { template friend class internal::ServerStreamingHandler; template - friend class internal::CallbackUnaryHandler; + friend class ::grpc_impl::internal::CallbackUnaryHandler; template - friend class ::grpc::internal::CallbackServerStreamingHandler; + friend class ::grpc_impl::internal::CallbackServerStreamingHandler; template friend class internal::ErrorMethodHandler; template diff --git a/include/grpcpp/impl/codegen/call_op_set.h b/include/grpcpp/impl/codegen/call_op_set.h index d0958bbb251..84d1407cbe2 100644 --- a/include/grpcpp/impl/codegen/call_op_set.h +++ b/include/grpcpp/impl/codegen/call_op_set.h @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/grpcpp/impl/codegen/channel_interface.h b/include/grpcpp/impl/codegen/channel_interface.h index 836c287e509..dd2fe8d687a 100644 --- a/include/grpcpp/impl/codegen/channel_interface.h +++ b/include/grpcpp/impl/codegen/channel_interface.h @@ -27,24 +27,13 @@ namespace grpc_impl { class ClientContext; class CompletionQueue; -} // namespace grpc_impl - -namespace grpc { -class ChannelInterface; - template class ClientReader; template class ClientWriter; template class ClientReaderWriter; - namespace internal { -class Call; -class CallOpSetInterface; -class RpcMethod; -template -class BlockingUnaryCallImpl; template class CallbackUnaryCallImpl; template @@ -62,7 +51,19 @@ class ClientCallbackReaderFactory; template class ClientCallbackWriterFactory; class ClientCallbackUnaryFactory; +} // namespace internal +} // namespace grpc_impl + +namespace grpc { +class ChannelInterface; + +namespace internal { +class Call; +class CallOpSetInterface; +class RpcMethod; class InterceptedChannel; +template +class BlockingUnaryCallImpl; } // namespace internal /// Codegen interface for \a grpc::Channel. @@ -102,30 +103,30 @@ class ChannelInterface { private: template - friend class ::grpc::ClientReader; + friend class ::grpc_impl::ClientReader; template - friend class ::grpc::ClientWriter; + friend class ::grpc_impl::ClientWriter; template - friend class ::grpc::ClientReaderWriter; + friend class ::grpc_impl::ClientReaderWriter; template - friend class ::grpc::internal::ClientAsyncReaderFactory; + friend class ::grpc_impl::internal::ClientAsyncReaderFactory; template - friend class ::grpc::internal::ClientAsyncWriterFactory; + friend class ::grpc_impl::internal::ClientAsyncWriterFactory; template - friend class ::grpc::internal::ClientAsyncReaderWriterFactory; + friend class ::grpc_impl::internal::ClientAsyncReaderWriterFactory; template - friend class ::grpc::internal::ClientAsyncResponseReaderFactory; + friend class ::grpc_impl::internal::ClientAsyncResponseReaderFactory; template - friend class ::grpc::internal::ClientCallbackReaderWriterFactory; + friend class ::grpc_impl::internal::ClientCallbackReaderWriterFactory; template - friend class ::grpc::internal::ClientCallbackReaderFactory; + friend class ::grpc_impl::internal::ClientCallbackReaderFactory; template - friend class ::grpc::internal::ClientCallbackWriterFactory; - friend class ::grpc::internal::ClientCallbackUnaryFactory; + friend class ::grpc_impl::internal::ClientCallbackWriterFactory; + friend class ::grpc_impl::internal::ClientCallbackUnaryFactory; template friend class ::grpc::internal::BlockingUnaryCallImpl; template - friend class ::grpc::internal::CallbackUnaryCallImpl; + friend class ::grpc_impl::internal::CallbackUnaryCallImpl; friend class ::grpc::internal::RpcMethod; friend class ::grpc::internal::InterceptedChannel; virtual internal::Call CreateCall(const internal::RpcMethod& method, diff --git a/include/grpcpp/impl/codegen/client_callback.h b/include/grpcpp/impl/codegen/client_callback.h index 9441a48b051..4f60741624a 100644 --- a/include/grpcpp/impl/codegen/client_callback.h +++ b/include/grpcpp/impl/codegen/client_callback.h @@ -19,1012 +19,25 @@ #ifndef GRPCPP_IMPL_CODEGEN_CLIENT_CALLBACK_H #define GRPCPP_IMPL_CODEGEN_CLIENT_CALLBACK_H -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace grpc_impl { -class Channel; -class ClientContext; -} // namespace grpc_impl +#include namespace grpc { - -namespace internal { -class RpcMethod; - -/// Perform a callback-based unary call -/// TODO(vjpai): Combine as much as possible with the blocking unary call code -template -void CallbackUnaryCall(ChannelInterface* channel, const RpcMethod& method, - ::grpc_impl::ClientContext* context, - const InputMessage* request, OutputMessage* result, - std::function on_completion) { - CallbackUnaryCallImpl x( - channel, method, context, request, result, on_completion); -} - -template -class CallbackUnaryCallImpl { - public: - CallbackUnaryCallImpl(ChannelInterface* channel, const RpcMethod& method, - ::grpc_impl::ClientContext* context, - const InputMessage* request, OutputMessage* result, - std::function on_completion) { - CompletionQueue* cq = channel->CallbackCQ(); - GPR_CODEGEN_ASSERT(cq != nullptr); - Call call(channel->CreateCall(method, context, cq)); - - using FullCallOpSet = - CallOpSet, - CallOpClientSendClose, CallOpClientRecvStatus>; - - auto* ops = new (g_core_codegen_interface->grpc_call_arena_alloc( - call.call(), sizeof(FullCallOpSet))) FullCallOpSet; - - auto* tag = new (g_core_codegen_interface->grpc_call_arena_alloc( - call.call(), sizeof(CallbackWithStatusTag))) - CallbackWithStatusTag(call.call(), on_completion, ops); - - // TODO(vjpai): Unify code with sync API as much as possible - Status s = ops->SendMessagePtr(request); - if (!s.ok()) { - tag->force_run(s); - return; - } - ops->SendInitialMetadata(&context->send_initial_metadata_, - context->initial_metadata_flags()); - ops->RecvInitialMetadata(context); - ops->RecvMessage(result); - ops->AllowNoMessage(); - ops->ClientSendClose(); - ops->ClientRecvStatus(context, tag->status_ptr()); - ops->set_core_cq_tag(tag); - call.PerformOps(ops); - } -}; -} // namespace internal - namespace experimental { -// Forward declarations -template -class ClientBidiReactor; template -class ClientReadReactor; -template -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 -// will interact exclusively with the reactors that they define. -template -class ClientCallbackReaderWriter { - public: - virtual ~ClientCallbackReaderWriter() {} - virtual void StartCall() = 0; - virtual void Write(const Request* req, WriteOptions options) = 0; - virtual void WritesDone() = 0; - virtual void Read(Response* resp) = 0; - virtual void AddHold(int holds) = 0; - virtual void RemoveHold() = 0; - - protected: - void BindReactor(ClientBidiReactor* reactor) { - reactor->BindStream(this); - } -}; - -template -class ClientCallbackReader { - public: - virtual ~ClientCallbackReader() {} - virtual void StartCall() = 0; - virtual void Read(Response* resp) = 0; - virtual void AddHold(int holds) = 0; - virtual void RemoveHold() = 0; - - protected: - void BindReactor(ClientReadReactor* reactor) { - reactor->BindReader(this); - } -}; +using ClientReadReactor = + ::grpc_impl::experimental::ClientReadReactor; template -class ClientCallbackWriter { - public: - virtual ~ClientCallbackWriter() {} - virtual void StartCall() = 0; - void Write(const Request* req) { Write(req, WriteOptions()); } - virtual void Write(const Request* req, WriteOptions options) = 0; - void WriteLast(const Request* req, WriteOptions options) { - Write(req, options.set_last_message()); - } - virtual void WritesDone() = 0; +using ClientWriteReactor = + ::grpc_impl::experimental::ClientWriteReactor; - virtual void AddHold(int holds) = 0; - virtual void RemoveHold() = 0; - - protected: - void BindReactor(ClientWriteReactor* reactor) { - reactor->BindWriter(this); - } -}; - -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 -// activated by calling StartCall, possibly after initiating StartRead, -// StartWrite, or AddHold operations on the streaming object. Note that none of -// the classes are pure; all reactions have a default empty reaction so that the -// user class only needs to override those classes that it cares about. -// The reactor must be passed to the stub invocation before any of the below -// operations can be called. - -/// \a ClientBidiReactor is the interface for a bidirectional streaming RPC. template -class ClientBidiReactor { - public: - virtual ~ClientBidiReactor() {} - - /// Activate the RPC and initiate any reads or writes that have been Start'ed - /// before this call. All streaming RPCs issued by the client MUST have - /// StartCall invoked on them (even if they are canceled) as this call is the - /// activation of their lifecycle. - void StartCall() { stream_->StartCall(); } - - /// Initiate a read operation (or post it for later initiation if StartCall - /// has not yet been invoked). - /// - /// \param[out] resp Where to eventually store the read message. Valid when - /// the library calls OnReadDone - void StartRead(Response* resp) { stream_->Read(resp); } - - /// Initiate a write operation (or post it for later initiation if StartCall - /// has not yet been invoked). - /// - /// \param[in] req The message to be written. The library takes temporary - /// ownership until OnWriteDone, at which point the application - /// regains ownership of msg. - void StartWrite(const Request* req) { StartWrite(req, WriteOptions()); } - - /// Initiate/post a write operation with specified options. - /// - /// \param[in] req The message to be written. The library takes temporary - /// ownership until OnWriteDone, at which point the application - /// regains ownership of msg. - /// \param[in] options The WriteOptions to use for writing this message - void StartWrite(const Request* req, WriteOptions options) { - stream_->Write(req, std::move(options)); - } - - /// Initiate/post a write operation with specified options and an indication - /// that this is the last write (like StartWrite and StartWritesDone, merged). - /// Note that calling this means that no more calls to StartWrite, - /// StartWriteLast, or StartWritesDone are allowed. - /// - /// \param[in] req The message to be written. The library takes temporary - /// ownership until OnWriteDone, at which point the application - /// regains ownership of msg. - /// \param[in] options The WriteOptions to use for writing this message - void StartWriteLast(const Request* req, WriteOptions options) { - StartWrite(req, std::move(options.set_last_message())); - } - - /// Indicate that the RPC will have no more write operations. This can only be - /// issued once for a given RPC. This is not required or allowed if - /// StartWriteLast is used since that already has the same implication. - /// Note that calling this means that no more calls to StartWrite, - /// StartWriteLast, or StartWritesDone are allowed. - void StartWritesDone() { stream_->WritesDone(); } - - /// Holds are needed if (and only if) this stream has operations that take - /// place on it after StartCall but from outside one of the reactions - /// (OnReadDone, etc). This is _not_ a common use of the streaming API. - /// - /// Holds must be added before calling StartCall. If a stream still has a hold - /// in place, its resources will not be destroyed even if the status has - /// already come in from the wire and there are currently no active callbacks - /// outstanding. Similarly, the stream will not call OnDone if there are still - /// holds on it. - /// - /// For example, if a StartRead or StartWrite operation is going to be - /// initiated from elsewhere in the application, the application should call - /// AddHold or AddMultipleHolds before StartCall. If there is going to be, - /// for example, a read-flow and a write-flow taking place outside the - /// reactions, then call AddMultipleHolds(2) before StartCall. When the - /// application knows that it won't issue any more read operations (such as - /// when a read comes back as not ok), it should issue a RemoveHold(). It - /// should also call RemoveHold() again after it does StartWriteLast or - /// StartWritesDone that indicates that there will be no more write ops. - /// The number of RemoveHold calls must match the total number of AddHold - /// calls plus the number of holds added by AddMultipleHolds. - void AddHold() { AddMultipleHolds(1); } - void AddMultipleHolds(int holds) { stream_->AddHold(holds); } - void RemoveHold() { stream_->RemoveHold(); } - - /// Notifies the application that all operations associated with this RPC - /// have completed and provides the RPC status outcome. - /// - /// \param[in] s The status outcome of this RPC - virtual void OnDone(const Status& s) {} - - /// Notifies the application that a read of initial metadata from the - /// server is done. If the application chooses not to implement this method, - /// it can assume that the initial metadata has been read before the first - /// call of OnReadDone or OnDone. - /// - /// \param[in] ok Was the initial metadata read successfully? If false, no - /// further read-side operation will succeed. - virtual void OnReadInitialMetadataDone(bool ok) {} - - /// Notifies the application that a StartRead operation completed. - /// - /// \param[in] ok Was it successful? If false, no further read-side operation - /// will succeed. - virtual void OnReadDone(bool ok) {} - - /// Notifies the application that a StartWrite operation completed. - /// - /// \param[in] ok Was it successful? If false, no further write-side operation - /// will succeed. - virtual void OnWriteDone(bool ok) {} - - /// Notifies the application that a StartWritesDone operation completed. Note - /// that this is only used on explicit StartWritesDone operations and not for - /// those that are implicitly invoked as part of a StartWriteLast. - /// - /// \param[in] ok Was it successful? If false, the application will later see - /// the failure reflected as a bad status in OnDone. - virtual void OnWritesDoneDone(bool ok) {} - - private: - friend class ClientCallbackReaderWriter; - void BindStream(ClientCallbackReaderWriter* stream) { - stream_ = stream; - } - ClientCallbackReaderWriter* stream_; -}; - -/// \a ClientReadReactor is the interface for a server-streaming RPC. -/// All public methods behave as in ClientBidiReactor. -template -class ClientReadReactor { - public: - virtual ~ClientReadReactor() {} - - void StartCall() { reader_->StartCall(); } - void StartRead(Response* resp) { reader_->Read(resp); } - - void AddHold() { AddMultipleHolds(1); } - void AddMultipleHolds(int holds) { reader_->AddHold(holds); } - void RemoveHold() { reader_->RemoveHold(); } - - virtual void OnDone(const Status& s) {} - virtual void OnReadInitialMetadataDone(bool ok) {} - virtual void OnReadDone(bool ok) {} - - private: - friend class ClientCallbackReader; - void BindReader(ClientCallbackReader* reader) { reader_ = reader; } - ClientCallbackReader* reader_; -}; - -/// \a ClientWriteReactor is the interface for a client-streaming RPC. -/// All public methods behave as in ClientBidiReactor. -template -class ClientWriteReactor { - public: - virtual ~ClientWriteReactor() {} - - void StartCall() { writer_->StartCall(); } - void StartWrite(const Request* req) { StartWrite(req, WriteOptions()); } - void StartWrite(const Request* req, WriteOptions options) { - writer_->Write(req, std::move(options)); - } - void StartWriteLast(const Request* req, WriteOptions options) { - StartWrite(req, std::move(options.set_last_message())); - } - void StartWritesDone() { writer_->WritesDone(); } - - void AddHold() { AddMultipleHolds(1); } - void AddMultipleHolds(int holds) { writer_->AddHold(holds); } - void RemoveHold() { writer_->RemoveHold(); } - - virtual void OnDone(const Status& s) {} - virtual void OnReadInitialMetadataDone(bool ok) {} - virtual void OnWriteDone(bool ok) {} - virtual void OnWritesDoneDone(bool ok) {} - - private: - friend class ClientCallbackWriter; - void BindWriter(ClientCallbackWriter* writer) { writer_ = writer; } - ClientCallbackWriter* 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); -} +using ClientBidiReactor = + ::grpc_impl::experimental::ClientBidiReactor; +typedef ::grpc_impl::experimental::ClientUnaryReactor ClientUnaryReactor; } // namespace experimental - -namespace internal { - -// Forward declare factory classes for friendship -template -class ClientCallbackReaderWriterFactory; -template -class ClientCallbackReaderFactory; -template -class ClientCallbackWriterFactory; - -template -class ClientCallbackReaderWriterImpl - : public ::grpc::experimental::ClientCallbackReaderWriter { - public: - // always allocated against a call arena, no memory free required - static void operator delete(void* ptr, std::size_t size) { - assert(size == sizeof(ClientCallbackReaderWriterImpl)); - } - - // 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 MaybeFinish() { - if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( - 1, std::memory_order_acq_rel) == 1)) { - Status s = std::move(finish_status_); - auto* reactor = reactor_; - auto* call = call_.call(); - this->~ClientCallbackReaderWriterImpl(); - g_core_codegen_interface->grpc_call_unref(call); - reactor->OnDone(s); - } - } - - void StartCall() override { - // This call initiates two batches, plus any backlog, each with a callback - // 1. Send initial metadata (unless corked) + recv initial metadata - // 2. Any read backlog - // 3. Any write backlog - // 4. Recv trailing metadata, on_completion callback - started_ = true; - - start_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnReadInitialMetadataDone(ok); - MaybeFinish(); - }, - &start_ops_); - if (!start_corked_) { - 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_); - - // Also set up the read and write tags so that they don't have to be set up - // each time - write_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnWriteDone(ok); - MaybeFinish(); - }, - &write_ops_); - write_ops_.set_core_cq_tag(&write_tag_); - - read_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnReadDone(ok); - MaybeFinish(); - }, - &read_ops_); - read_ops_.set_core_cq_tag(&read_tag_); - if (read_ops_at_start_) { - call_.PerformOps(&read_ops_); - } - - if (write_ops_at_start_) { - call_.PerformOps(&write_ops_); - } - - if (writes_done_ops_at_start_) { - call_.PerformOps(&writes_done_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 Read(Response* msg) override { - read_ops_.RecvMessage(msg); - callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); - if (started_) { - call_.PerformOps(&read_ops_); - } else { - read_ops_at_start_ = true; - } - } - - void Write(const Request* msg, WriteOptions options) override { - if (start_corked_) { - write_ops_.SendInitialMetadata(&context_->send_initial_metadata_, - context_->initial_metadata_flags()); - start_corked_ = false; - } - - if (options.is_last_message()) { - options.set_buffer_hint(); - write_ops_.ClientSendClose(); - } - // TODO(vjpai): don't assert - GPR_CODEGEN_ASSERT(write_ops_.SendMessagePtr(msg, options).ok()); - callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); - if (started_) { - call_.PerformOps(&write_ops_); - } else { - write_ops_at_start_ = true; - } - } - void WritesDone() override { - if (start_corked_) { - writes_done_ops_.SendInitialMetadata(&context_->send_initial_metadata_, - context_->initial_metadata_flags()); - start_corked_ = false; - } - writes_done_ops_.ClientSendClose(); - writes_done_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnWritesDoneDone(ok); - MaybeFinish(); - }, - &writes_done_ops_); - writes_done_ops_.set_core_cq_tag(&writes_done_tag_); - callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); - if (started_) { - call_.PerformOps(&writes_done_ops_); - } else { - writes_done_ops_at_start_ = true; - } - } - - void AddHold(int holds) override { - callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed); - } - void RemoveHold() override { MaybeFinish(); } - - private: - friend class ClientCallbackReaderWriterFactory; - - ClientCallbackReaderWriterImpl( - Call call, ::grpc_impl::ClientContext* context, - ::grpc::experimental::ClientBidiReactor* reactor) - : context_(context), - call_(call), - reactor_(reactor), - start_corked_(context_->initial_metadata_corked_) { - this->BindReactor(reactor); - } - - ::grpc_impl::ClientContext* const context_; - Call call_; - ::grpc::experimental::ClientBidiReactor* const reactor_; - - CallOpSet start_ops_; - CallbackWithSuccessTag start_tag_; - bool start_corked_; - - CallOpSet finish_ops_; - CallbackWithSuccessTag finish_tag_; - Status finish_status_; - - CallOpSet - write_ops_; - CallbackWithSuccessTag write_tag_; - bool write_ops_at_start_{false}; - - CallOpSet writes_done_ops_; - CallbackWithSuccessTag writes_done_tag_; - bool writes_done_ops_at_start_{false}; - - CallOpSet> read_ops_; - CallbackWithSuccessTag read_tag_; - bool read_ops_at_start_{false}; - - // Minimum of 2 callbacks to pre-register for start and finish - std::atomic callbacks_outstanding_{2}; - bool started_{false}; -}; - -template -class ClientCallbackReaderWriterFactory { - public: - static void Create( - ChannelInterface* channel, const ::grpc::internal::RpcMethod& method, - ::grpc_impl::ClientContext* context, - ::grpc::experimental::ClientBidiReactor* 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(ClientCallbackReaderWriterImpl))) - ClientCallbackReaderWriterImpl(call, context, - reactor); - } -}; - -template -class ClientCallbackReaderImpl - : public ::grpc::experimental::ClientCallbackReader { - public: - // always allocated against a call arena, no memory free required - static void operator delete(void* ptr, std::size_t size) { - assert(size == sizeof(ClientCallbackReaderImpl)); - } - - // 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 MaybeFinish() { - if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( - 1, std::memory_order_acq_rel) == 1)) { - Status s = std::move(finish_status_); - auto* reactor = reactor_; - auto* call = call_.call(); - this->~ClientCallbackReaderImpl(); - g_core_codegen_interface->grpc_call_unref(call); - reactor->OnDone(s); - } - } - - void StartCall() override { - // This call initiates two batches, plus any backlog, each with a callback - // 1. Send initial metadata (unless corked) + recv initial metadata - // 2. Any backlog - // 3. Recv trailing metadata, on_completion callback - 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_); - - // Also set up the read tag so it doesn't have to be set up each time - read_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnReadDone(ok); - MaybeFinish(); - }, - &read_ops_); - read_ops_.set_core_cq_tag(&read_tag_); - if (read_ops_at_start_) { - call_.PerformOps(&read_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 Read(Response* msg) override { - read_ops_.RecvMessage(msg); - callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); - if (started_) { - call_.PerformOps(&read_ops_); - } else { - read_ops_at_start_ = true; - } - } - - void AddHold(int holds) override { - callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed); - } - void RemoveHold() override { MaybeFinish(); } - - private: - friend class ClientCallbackReaderFactory; - - template - ClientCallbackReaderImpl( - Call call, ::grpc_impl::ClientContext* context, Request* request, - ::grpc::experimental::ClientReadReactor* 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(); - } - - ::grpc_impl::ClientContext* const context_; - Call call_; - ::grpc::experimental::ClientReadReactor* const reactor_; - - CallOpSet - start_ops_; - CallbackWithSuccessTag start_tag_; - - CallOpSet finish_ops_; - CallbackWithSuccessTag finish_tag_; - Status finish_status_; - - CallOpSet> read_ops_; - CallbackWithSuccessTag read_tag_; - bool read_ops_at_start_{false}; - - // Minimum of 2 callbacks to pre-register for start and finish - std::atomic callbacks_outstanding_{2}; - bool started_{false}; -}; - -template -class ClientCallbackReaderFactory { - public: - template - static void Create( - ChannelInterface* channel, const ::grpc::internal::RpcMethod& method, - ::grpc_impl::ClientContext* context, const Request* request, - ::grpc::experimental::ClientReadReactor* 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(ClientCallbackReaderImpl))) - ClientCallbackReaderImpl(call, context, request, reactor); - } -}; - -template -class ClientCallbackWriterImpl - : public ::grpc::experimental::ClientCallbackWriter { - public: - // always allocated against a call arena, no memory free required - static void operator delete(void* ptr, std::size_t size) { - assert(size == sizeof(ClientCallbackWriterImpl)); - } - - // 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 MaybeFinish() { - if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( - 1, std::memory_order_acq_rel) == 1)) { - Status s = std::move(finish_status_); - auto* reactor = reactor_; - auto* call = call_.call(); - this->~ClientCallbackWriterImpl(); - g_core_codegen_interface->grpc_call_unref(call); - reactor->OnDone(s); - } - } - - void StartCall() override { - // This call initiates two batches, plus any backlog, each with a callback - // 1. Send initial metadata (unless corked) + recv initial metadata - // 2. Any backlog - // 3. Recv trailing metadata, on_completion callback - started_ = true; - - start_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnReadInitialMetadataDone(ok); - MaybeFinish(); - }, - &start_ops_); - if (!start_corked_) { - 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_); - - // Also set up the read and write tags so that they don't have to be set up - // each time - write_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnWriteDone(ok); - MaybeFinish(); - }, - &write_ops_); - write_ops_.set_core_cq_tag(&write_tag_); - - if (write_ops_at_start_) { - call_.PerformOps(&write_ops_); - } - - if (writes_done_ops_at_start_) { - call_.PerformOps(&writes_done_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 Write(const Request* msg, WriteOptions options) override { - if (start_corked_) { - write_ops_.SendInitialMetadata(&context_->send_initial_metadata_, - context_->initial_metadata_flags()); - start_corked_ = false; - } - - if (options.is_last_message()) { - options.set_buffer_hint(); - write_ops_.ClientSendClose(); - } - // TODO(vjpai): don't assert - GPR_CODEGEN_ASSERT(write_ops_.SendMessagePtr(msg, options).ok()); - callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); - if (started_) { - call_.PerformOps(&write_ops_); - } else { - write_ops_at_start_ = true; - } - } - void WritesDone() override { - if (start_corked_) { - writes_done_ops_.SendInitialMetadata(&context_->send_initial_metadata_, - context_->initial_metadata_flags()); - start_corked_ = false; - } - writes_done_ops_.ClientSendClose(); - writes_done_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnWritesDoneDone(ok); - MaybeFinish(); - }, - &writes_done_ops_); - writes_done_ops_.set_core_cq_tag(&writes_done_tag_); - callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); - if (started_) { - call_.PerformOps(&writes_done_ops_); - } else { - writes_done_ops_at_start_ = true; - } - } - - void AddHold(int holds) override { - callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed); - } - void RemoveHold() override { MaybeFinish(); } - - private: - friend class ClientCallbackWriterFactory; - - template - ClientCallbackWriterImpl( - Call call, ::grpc_impl::ClientContext* context, Response* response, - ::grpc::experimental::ClientWriteReactor* reactor) - : context_(context), - call_(call), - reactor_(reactor), - start_corked_(context_->initial_metadata_corked_) { - this->BindReactor(reactor); - finish_ops_.RecvMessage(response); - finish_ops_.AllowNoMessage(); - } - - ::grpc_impl::ClientContext* const context_; - Call call_; - ::grpc::experimental::ClientWriteReactor* const reactor_; - - CallOpSet start_ops_; - CallbackWithSuccessTag start_tag_; - bool start_corked_; - - CallOpSet finish_ops_; - CallbackWithSuccessTag finish_tag_; - Status finish_status_; - - CallOpSet - write_ops_; - CallbackWithSuccessTag write_tag_; - bool write_ops_at_start_{false}; - - CallOpSet writes_done_ops_; - CallbackWithSuccessTag writes_done_tag_; - bool writes_done_ops_at_start_{false}; - - // Minimum of 2 callbacks to pre-register for start and finish - std::atomic callbacks_outstanding_{2}; - bool started_{false}; -}; - -template -class ClientCallbackWriterFactory { - public: - template - static void Create( - ChannelInterface* channel, const ::grpc::internal::RpcMethod& method, - ::grpc_impl::ClientContext* context, Response* response, - ::grpc::experimental::ClientWriteReactor* 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(ClientCallbackWriterImpl))) - ClientCallbackWriterImpl(call, context, response, reactor); - } -}; - -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 (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( - 1, std::memory_order_acq_rel) == 1)) { - 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 - ClientCallbackUnaryImpl(Call call, ::grpc_impl::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(); - } - - ::grpc_impl::ClientContext* const context_; - Call call_; - ::grpc::experimental::ClientUnaryReactor* const reactor_; - - CallOpSet - start_ops_; - CallbackWithSuccessTag start_tag_; - - CallOpSet finish_ops_; - CallbackWithSuccessTag finish_tag_; - Status finish_status_; - - // This call will have 2 callbacks: start and finish - std::atomic callbacks_outstanding_{2}; - bool started_{false}; -}; - -class ClientCallbackUnaryFactory { - public: - template - static void Create(ChannelInterface* channel, - const ::grpc::internal::RpcMethod& method, - ::grpc_impl::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 #endif // GRPCPP_IMPL_CODEGEN_CLIENT_CALLBACK_H diff --git a/include/grpcpp/impl/codegen/client_callback_impl.h b/include/grpcpp/impl/codegen/client_callback_impl.h new file mode 100644 index 00000000000..81847bc9e04 --- /dev/null +++ b/include/grpcpp/impl/codegen/client_callback_impl.h @@ -0,0 +1,1067 @@ +/* + * + * 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_CLIENT_CALLBACK_IMPL_H +#define GRPCPP_IMPL_CODEGEN_CLIENT_CALLBACK_IMPL_H +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace grpc { +namespace internal { +class RpcMethod; +} // namespace internal +} // namespace grpc + +namespace grpc_impl { +class Channel; +class ClientContext; + +namespace internal { + +/// Perform a callback-based unary call +/// TODO(vjpai): Combine as much as possible with the blocking unary call code +template +void CallbackUnaryCall(::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context, + const InputMessage* request, OutputMessage* result, + std::function on_completion) { + CallbackUnaryCallImpl x( + channel, method, context, request, result, on_completion); +} + +template +class CallbackUnaryCallImpl { + public: + CallbackUnaryCallImpl(::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context, + const InputMessage* request, OutputMessage* result, + std::function on_completion) { + ::grpc_impl::CompletionQueue* cq = channel->CallbackCQ(); + GPR_CODEGEN_ASSERT(cq != nullptr); + grpc::internal::Call call(channel->CreateCall(method, context, cq)); + + using FullCallOpSet = grpc::internal::CallOpSet< + ::grpc::internal::CallOpSendInitialMetadata, + grpc::internal::CallOpSendMessage, + grpc::internal::CallOpRecvInitialMetadata, + grpc::internal::CallOpRecvMessage, + grpc::internal::CallOpClientSendClose, + grpc::internal::CallOpClientRecvStatus>; + + auto* ops = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(FullCallOpSet))) FullCallOpSet; + + auto* tag = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(grpc::internal::CallbackWithStatusTag))) + grpc::internal::CallbackWithStatusTag(call.call(), on_completion, ops); + + // TODO(vjpai): Unify code with sync API as much as possible + ::grpc::Status s = ops->SendMessagePtr(request); + if (!s.ok()) { + tag->force_run(s); + return; + } + ops->SendInitialMetadata(&context->send_initial_metadata_, + context->initial_metadata_flags()); + ops->RecvInitialMetadata(context); + ops->RecvMessage(result); + ops->AllowNoMessage(); + ops->ClientSendClose(); + ops->ClientRecvStatus(context, tag->status_ptr()); + ops->set_core_cq_tag(tag); + call.PerformOps(ops); + } +}; +} // namespace internal + +namespace experimental { + +// Forward declarations +template +class ClientBidiReactor; +template +class ClientReadReactor; +template +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 +// will interact exclusively with the reactors that they define. +template +class ClientCallbackReaderWriter { + public: + virtual ~ClientCallbackReaderWriter() {} + virtual void StartCall() = 0; + virtual void Write(const Request* req, ::grpc::WriteOptions options) = 0; + virtual void WritesDone() = 0; + virtual void Read(Response* resp) = 0; + virtual void AddHold(int holds) = 0; + virtual void RemoveHold() = 0; + + protected: + void BindReactor(ClientBidiReactor* reactor) { + reactor->BindStream(this); + } +}; + +template +class ClientCallbackReader { + public: + virtual ~ClientCallbackReader() {} + virtual void StartCall() = 0; + virtual void Read(Response* resp) = 0; + virtual void AddHold(int holds) = 0; + virtual void RemoveHold() = 0; + + protected: + void BindReactor(ClientReadReactor* reactor) { + reactor->BindReader(this); + } +}; + +template +class ClientCallbackWriter { + public: + virtual ~ClientCallbackWriter() {} + virtual void StartCall() = 0; + void Write(const Request* req) { Write(req, ::grpc::WriteOptions()); } + virtual void Write(const Request* req, ::grpc::WriteOptions options) = 0; + void WriteLast(const Request* req, ::grpc::WriteOptions options) { + Write(req, options.set_last_message()); + } + virtual void WritesDone() = 0; + + virtual void AddHold(int holds) = 0; + virtual void RemoveHold() = 0; + + protected: + void BindReactor(ClientWriteReactor* reactor) { + reactor->BindWriter(this); + } +}; + +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 +// activated by calling StartCall, possibly after initiating StartRead, +// StartWrite, or AddHold operations on the streaming object. Note that none of +// the classes are pure; all reactions have a default empty reaction so that the +// user class only needs to override those classes that it cares about. +// The reactor must be passed to the stub invocation before any of the below +// operations can be called. + +/// \a ClientBidiReactor is the interface for a bidirectional streaming RPC. +template +class ClientBidiReactor { + public: + virtual ~ClientBidiReactor() {} + + /// Activate the RPC and initiate any reads or writes that have been Start'ed + /// before this call. All streaming RPCs issued by the client MUST have + /// StartCall invoked on them (even if they are canceled) as this call is the + /// activation of their lifecycle. + void StartCall() { stream_->StartCall(); } + + /// Initiate a read operation (or post it for later initiation if StartCall + /// has not yet been invoked). + /// + /// \param[out] resp Where to eventually store the read message. Valid when + /// the library calls OnReadDone + void StartRead(Response* resp) { stream_->Read(resp); } + + /// Initiate a write operation (or post it for later initiation if StartCall + /// has not yet been invoked). + /// + /// \param[in] req The message to be written. The library takes temporary + /// ownership until OnWriteDone, at which point the application + /// regains ownership of msg. + void StartWrite(const Request* req) { + StartWrite(req, ::grpc::WriteOptions()); + } + + /// Initiate/post a write operation with specified options. + /// + /// \param[in] req The message to be written. The library takes temporary + /// ownership until OnWriteDone, at which point the application + /// regains ownership of msg. + /// \param[in] options The WriteOptions to use for writing this message + void StartWrite(const Request* req, ::grpc::WriteOptions options) { + stream_->Write(req, std::move(options)); + } + + /// Initiate/post a write operation with specified options and an indication + /// that this is the last write (like StartWrite and StartWritesDone, merged). + /// Note that calling this means that no more calls to StartWrite, + /// StartWriteLast, or StartWritesDone are allowed. + /// + /// \param[in] req The message to be written. The library takes temporary + /// ownership until OnWriteDone, at which point the application + /// regains ownership of msg. + /// \param[in] options The WriteOptions to use for writing this message + void StartWriteLast(const Request* req, ::grpc::WriteOptions options) { + StartWrite(req, std::move(options.set_last_message())); + } + + /// Indicate that the RPC will have no more write operations. This can only be + /// issued once for a given RPC. This is not required or allowed if + /// StartWriteLast is used since that already has the same implication. + /// Note that calling this means that no more calls to StartWrite, + /// StartWriteLast, or StartWritesDone are allowed. + void StartWritesDone() { stream_->WritesDone(); } + + /// Holds are needed if (and only if) this stream has operations that take + /// place on it after StartCall but from outside one of the reactions + /// (OnReadDone, etc). This is _not_ a common use of the streaming API. + /// + /// Holds must be added before calling StartCall. If a stream still has a hold + /// in place, its resources will not be destroyed even if the status has + /// already come in from the wire and there are currently no active callbacks + /// outstanding. Similarly, the stream will not call OnDone if there are still + /// holds on it. + /// + /// For example, if a StartRead or StartWrite operation is going to be + /// initiated from elsewhere in the application, the application should call + /// AddHold or AddMultipleHolds before StartCall. If there is going to be, + /// for example, a read-flow and a write-flow taking place outside the + /// reactions, then call AddMultipleHolds(2) before StartCall. When the + /// application knows that it won't issue any more read operations (such as + /// when a read comes back as not ok), it should issue a RemoveHold(). It + /// should also call RemoveHold() again after it does StartWriteLast or + /// StartWritesDone that indicates that there will be no more write ops. + /// The number of RemoveHold calls must match the total number of AddHold + /// calls plus the number of holds added by AddMultipleHolds. + void AddHold() { AddMultipleHolds(1); } + void AddMultipleHolds(int holds) { stream_->AddHold(holds); } + void RemoveHold() { stream_->RemoveHold(); } + + /// Notifies the application that all operations associated with this RPC + /// have completed and provides the RPC status outcome. + /// + /// \param[in] s The status outcome of this RPC + virtual void OnDone(const ::grpc::Status& s) {} + + /// Notifies the application that a read of initial metadata from the + /// server is done. If the application chooses not to implement this method, + /// it can assume that the initial metadata has been read before the first + /// call of OnReadDone or OnDone. + /// + /// \param[in] ok Was the initial metadata read successfully? If false, no + /// further read-side operation will succeed. + virtual void OnReadInitialMetadataDone(bool ok) {} + + /// Notifies the application that a StartRead operation completed. + /// + /// \param[in] ok Was it successful? If false, no further read-side operation + /// will succeed. + virtual void OnReadDone(bool ok) {} + + /// Notifies the application that a StartWrite operation completed. + /// + /// \param[in] ok Was it successful? If false, no further write-side operation + /// will succeed. + virtual void OnWriteDone(bool ok) {} + + /// Notifies the application that a StartWritesDone operation completed. Note + /// that this is only used on explicit StartWritesDone operations and not for + /// those that are implicitly invoked as part of a StartWriteLast. + /// + /// \param[in] ok Was it successful? If false, the application will later see + /// the failure reflected as a bad status in OnDone. + virtual void OnWritesDoneDone(bool ok) {} + + private: + friend class ClientCallbackReaderWriter; + void BindStream(ClientCallbackReaderWriter* stream) { + stream_ = stream; + } + ClientCallbackReaderWriter* stream_; +}; + +/// \a ClientReadReactor is the interface for a server-streaming RPC. +/// All public methods behave as in ClientBidiReactor. +template +class ClientReadReactor { + public: + virtual ~ClientReadReactor() {} + + void StartCall() { reader_->StartCall(); } + void StartRead(Response* resp) { reader_->Read(resp); } + + void AddHold() { AddMultipleHolds(1); } + void AddMultipleHolds(int holds) { reader_->AddHold(holds); } + void RemoveHold() { reader_->RemoveHold(); } + + virtual void OnDone(const ::grpc::Status& s) {} + virtual void OnReadInitialMetadataDone(bool ok) {} + virtual void OnReadDone(bool ok) {} + + private: + friend class ClientCallbackReader; + void BindReader(ClientCallbackReader* reader) { reader_ = reader; } + ClientCallbackReader* reader_; +}; + +/// \a ClientWriteReactor is the interface for a client-streaming RPC. +/// All public methods behave as in ClientBidiReactor. +template +class ClientWriteReactor { + public: + virtual ~ClientWriteReactor() {} + + void StartCall() { writer_->StartCall(); } + void StartWrite(const Request* req) { + StartWrite(req, ::grpc::WriteOptions()); + } + void StartWrite(const Request* req, ::grpc::WriteOptions options) { + writer_->Write(req, std::move(options)); + } + void StartWriteLast(const Request* req, ::grpc::WriteOptions options) { + StartWrite(req, std::move(options.set_last_message())); + } + void StartWritesDone() { writer_->WritesDone(); } + + void AddHold() { AddMultipleHolds(1); } + void AddMultipleHolds(int holds) { writer_->AddHold(holds); } + void RemoveHold() { writer_->RemoveHold(); } + + virtual void OnDone(const ::grpc::Status& s) {} + virtual void OnReadInitialMetadataDone(bool ok) {} + virtual void OnWriteDone(bool ok) {} + virtual void OnWritesDoneDone(bool ok) {} + + private: + friend class ClientCallbackWriter; + void BindWriter(ClientCallbackWriter* writer) { writer_ = writer; } + ClientCallbackWriter* 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 ::grpc::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 { + +// Forward declare factory classes for friendship +template +class ClientCallbackReaderWriterFactory; +template +class ClientCallbackReaderFactory; +template +class ClientCallbackWriterFactory; + +template +class ClientCallbackReaderWriterImpl + : public experimental::ClientCallbackReaderWriter { + public: + // always allocated against a call arena, no memory free required + static void operator delete(void* ptr, std::size_t size) { + assert(size == sizeof(ClientCallbackReaderWriterImpl)); + } + + // 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 MaybeFinish() { + if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( + 1, std::memory_order_acq_rel) == 1)) { + ::grpc::Status s = std::move(finish_status_); + auto* reactor = reactor_; + auto* call = call_.call(); + this->~ClientCallbackReaderWriterImpl(); + ::grpc::g_core_codegen_interface->grpc_call_unref(call); + reactor->OnDone(s); + } + } + + void StartCall() override { + // This call initiates two batches, plus any backlog, each with a callback + // 1. Send initial metadata (unless corked) + recv initial metadata + // 2. Any read backlog + // 3. Any write backlog + // 4. Recv trailing metadata, on_completion callback + started_ = true; + + start_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnReadInitialMetadataDone(ok); + MaybeFinish(); + }, + &start_ops_); + if (!start_corked_) { + 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_); + + // Also set up the read and write tags so that they don't have to be set up + // each time + write_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnWriteDone(ok); + MaybeFinish(); + }, + &write_ops_); + write_ops_.set_core_cq_tag(&write_tag_); + + read_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnReadDone(ok); + MaybeFinish(); + }, + &read_ops_); + read_ops_.set_core_cq_tag(&read_tag_); + if (read_ops_at_start_) { + call_.PerformOps(&read_ops_); + } + + if (write_ops_at_start_) { + call_.PerformOps(&write_ops_); + } + + if (writes_done_ops_at_start_) { + call_.PerformOps(&writes_done_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 Read(Response* msg) override { + read_ops_.RecvMessage(msg); + callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); + if (started_) { + call_.PerformOps(&read_ops_); + } else { + read_ops_at_start_ = true; + } + } + + void Write(const Request* msg, ::grpc::WriteOptions options) override { + if (start_corked_) { + write_ops_.SendInitialMetadata(&context_->send_initial_metadata_, + context_->initial_metadata_flags()); + start_corked_ = false; + } + + if (options.is_last_message()) { + options.set_buffer_hint(); + write_ops_.ClientSendClose(); + } + // TODO(vjpai): don't assert + GPR_CODEGEN_ASSERT(write_ops_.SendMessagePtr(msg, options).ok()); + callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); + if (started_) { + call_.PerformOps(&write_ops_); + } else { + write_ops_at_start_ = true; + } + } + void WritesDone() override { + if (start_corked_) { + writes_done_ops_.SendInitialMetadata(&context_->send_initial_metadata_, + context_->initial_metadata_flags()); + start_corked_ = false; + } + writes_done_ops_.ClientSendClose(); + writes_done_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnWritesDoneDone(ok); + MaybeFinish(); + }, + &writes_done_ops_); + writes_done_ops_.set_core_cq_tag(&writes_done_tag_); + callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); + if (started_) { + call_.PerformOps(&writes_done_ops_); + } else { + writes_done_ops_at_start_ = true; + } + } + + void AddHold(int holds) override { + callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed); + } + void RemoveHold() override { MaybeFinish(); } + + private: + friend class ClientCallbackReaderWriterFactory; + + ClientCallbackReaderWriterImpl( + grpc::internal::Call call, ::grpc_impl::ClientContext* context, + experimental::ClientBidiReactor* reactor) + : context_(context), + call_(call), + reactor_(reactor), + start_corked_(context_->initial_metadata_corked_) { + this->BindReactor(reactor); + } + + ::grpc_impl::ClientContext* const context_; + grpc::internal::Call call_; + experimental::ClientBidiReactor* const reactor_; + + grpc::internal::CallOpSet + start_ops_; + grpc::internal::CallbackWithSuccessTag start_tag_; + bool start_corked_; + + grpc::internal::CallOpSet finish_ops_; + grpc::internal::CallbackWithSuccessTag finish_tag_; + ::grpc::Status finish_status_; + + grpc::internal::CallOpSet + write_ops_; + grpc::internal::CallbackWithSuccessTag write_tag_; + bool write_ops_at_start_{false}; + + grpc::internal::CallOpSet + writes_done_ops_; + grpc::internal::CallbackWithSuccessTag writes_done_tag_; + bool writes_done_ops_at_start_{false}; + + grpc::internal::CallOpSet> + read_ops_; + grpc::internal::CallbackWithSuccessTag read_tag_; + bool read_ops_at_start_{false}; + + // Minimum of 2 callbacks to pre-register for start and finish + std::atomic callbacks_outstanding_{2}; + bool started_{false}; +}; + +template +class ClientCallbackReaderWriterFactory { + public: + static void Create( + ::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context, + experimental::ClientBidiReactor* reactor) { + grpc::internal::Call call = + channel->CreateCall(method, context, channel->CallbackCQ()); + + ::grpc::g_core_codegen_interface->grpc_call_ref(call.call()); + new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(ClientCallbackReaderWriterImpl))) + ClientCallbackReaderWriterImpl(call, context, + reactor); + } +}; + +template +class ClientCallbackReaderImpl + : public experimental::ClientCallbackReader { + public: + // always allocated against a call arena, no memory free required + static void operator delete(void* ptr, std::size_t size) { + assert(size == sizeof(ClientCallbackReaderImpl)); + } + + // 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 MaybeFinish() { + if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( + 1, std::memory_order_acq_rel) == 1)) { + ::grpc::Status s = std::move(finish_status_); + auto* reactor = reactor_; + auto* call = call_.call(); + this->~ClientCallbackReaderImpl(); + ::grpc::g_core_codegen_interface->grpc_call_unref(call); + reactor->OnDone(s); + } + } + + void StartCall() override { + // This call initiates two batches, plus any backlog, each with a callback + // 1. Send initial metadata (unless corked) + recv initial metadata + // 2. Any backlog + // 3. Recv trailing metadata, on_completion callback + 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_); + + // Also set up the read tag so it doesn't have to be set up each time + read_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnReadDone(ok); + MaybeFinish(); + }, + &read_ops_); + read_ops_.set_core_cq_tag(&read_tag_); + if (read_ops_at_start_) { + call_.PerformOps(&read_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 Read(Response* msg) override { + read_ops_.RecvMessage(msg); + callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); + if (started_) { + call_.PerformOps(&read_ops_); + } else { + read_ops_at_start_ = true; + } + } + + void AddHold(int holds) override { + callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed); + } + void RemoveHold() override { MaybeFinish(); } + + private: + friend class ClientCallbackReaderFactory; + + template + ClientCallbackReaderImpl(::grpc::internal::Call call, + ::grpc_impl::ClientContext* context, + Request* request, + experimental::ClientReadReactor* 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(); + } + + ::grpc_impl::ClientContext* const context_; + grpc::internal::Call call_; + experimental::ClientReadReactor* const reactor_; + + grpc::internal::CallOpSet + start_ops_; + grpc::internal::CallbackWithSuccessTag start_tag_; + + grpc::internal::CallOpSet finish_ops_; + grpc::internal::CallbackWithSuccessTag finish_tag_; + ::grpc::Status finish_status_; + + grpc::internal::CallOpSet> + read_ops_; + grpc::internal::CallbackWithSuccessTag read_tag_; + bool read_ops_at_start_{false}; + + // Minimum of 2 callbacks to pre-register for start and finish + std::atomic callbacks_outstanding_{2}; + bool started_{false}; +}; + +template +class ClientCallbackReaderFactory { + public: + template + static void Create(::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context, + const Request* request, + experimental::ClientReadReactor* reactor) { + grpc::internal::Call call = + channel->CreateCall(method, context, channel->CallbackCQ()); + + ::grpc::g_core_codegen_interface->grpc_call_ref(call.call()); + new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(ClientCallbackReaderImpl))) + ClientCallbackReaderImpl(call, context, request, reactor); + } +}; + +template +class ClientCallbackWriterImpl + : public experimental::ClientCallbackWriter { + public: + // always allocated against a call arena, no memory free required + static void operator delete(void* ptr, std::size_t size) { + assert(size == sizeof(ClientCallbackWriterImpl)); + } + + // 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 MaybeFinish() { + if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( + 1, std::memory_order_acq_rel) == 1)) { + ::grpc::Status s = std::move(finish_status_); + auto* reactor = reactor_; + auto* call = call_.call(); + this->~ClientCallbackWriterImpl(); + ::grpc::g_core_codegen_interface->grpc_call_unref(call); + reactor->OnDone(s); + } + } + + void StartCall() override { + // This call initiates two batches, plus any backlog, each with a callback + // 1. Send initial metadata (unless corked) + recv initial metadata + // 2. Any backlog + // 3. Recv trailing metadata, on_completion callback + started_ = true; + + start_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnReadInitialMetadataDone(ok); + MaybeFinish(); + }, + &start_ops_); + if (!start_corked_) { + 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_); + + // Also set up the read and write tags so that they don't have to be set up + // each time + write_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnWriteDone(ok); + MaybeFinish(); + }, + &write_ops_); + write_ops_.set_core_cq_tag(&write_tag_); + + if (write_ops_at_start_) { + call_.PerformOps(&write_ops_); + } + + if (writes_done_ops_at_start_) { + call_.PerformOps(&writes_done_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 Write(const Request* msg, ::grpc::WriteOptions options) override { + if (start_corked_) { + write_ops_.SendInitialMetadata(&context_->send_initial_metadata_, + context_->initial_metadata_flags()); + start_corked_ = false; + } + + if (options.is_last_message()) { + options.set_buffer_hint(); + write_ops_.ClientSendClose(); + } + // TODO(vjpai): don't assert + GPR_CODEGEN_ASSERT(write_ops_.SendMessagePtr(msg, options).ok()); + callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); + if (started_) { + call_.PerformOps(&write_ops_); + } else { + write_ops_at_start_ = true; + } + } + void WritesDone() override { + if (start_corked_) { + writes_done_ops_.SendInitialMetadata(&context_->send_initial_metadata_, + context_->initial_metadata_flags()); + start_corked_ = false; + } + writes_done_ops_.ClientSendClose(); + writes_done_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnWritesDoneDone(ok); + MaybeFinish(); + }, + &writes_done_ops_); + writes_done_ops_.set_core_cq_tag(&writes_done_tag_); + callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); + if (started_) { + call_.PerformOps(&writes_done_ops_); + } else { + writes_done_ops_at_start_ = true; + } + } + + void AddHold(int holds) override { + callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed); + } + void RemoveHold() override { MaybeFinish(); } + + private: + friend class ClientCallbackWriterFactory; + + template + ClientCallbackWriterImpl(::grpc::internal::Call call, + ::grpc_impl::ClientContext* context, + Response* response, + experimental::ClientWriteReactor* reactor) + : context_(context), + call_(call), + reactor_(reactor), + start_corked_(context_->initial_metadata_corked_) { + this->BindReactor(reactor); + finish_ops_.RecvMessage(response); + finish_ops_.AllowNoMessage(); + } + + ::grpc_impl::ClientContext* const context_; + grpc::internal::Call call_; + experimental::ClientWriteReactor* const reactor_; + + grpc::internal::CallOpSet + start_ops_; + grpc::internal::CallbackWithSuccessTag start_tag_; + bool start_corked_; + + grpc::internal::CallOpSet + finish_ops_; + grpc::internal::CallbackWithSuccessTag finish_tag_; + ::grpc::Status finish_status_; + + grpc::internal::CallOpSet + write_ops_; + grpc::internal::CallbackWithSuccessTag write_tag_; + bool write_ops_at_start_{false}; + + grpc::internal::CallOpSet + writes_done_ops_; + grpc::internal::CallbackWithSuccessTag writes_done_tag_; + bool writes_done_ops_at_start_{false}; + + // Minimum of 2 callbacks to pre-register for start and finish + std::atomic callbacks_outstanding_{2}; + bool started_{false}; +}; + +template +class ClientCallbackWriterFactory { + public: + template + static void Create(::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context, Response* response, + experimental::ClientWriteReactor* reactor) { + grpc::internal::Call call = + channel->CreateCall(method, context, channel->CallbackCQ()); + + ::grpc::g_core_codegen_interface->grpc_call_ref(call.call()); + new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(ClientCallbackWriterImpl))) + ClientCallbackWriterImpl(call, context, response, reactor); + } +}; + +class ClientCallbackUnaryImpl final : public 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 (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( + 1, std::memory_order_acq_rel) == 1)) { + ::grpc::Status s = std::move(finish_status_); + auto* reactor = reactor_; + auto* call = call_.call(); + this->~ClientCallbackUnaryImpl(); + ::grpc::g_core_codegen_interface->grpc_call_unref(call); + reactor->OnDone(s); + } + } + + private: + friend class ClientCallbackUnaryFactory; + + template + ClientCallbackUnaryImpl(::grpc::internal::Call call, + ::grpc_impl::ClientContext* context, Request* request, + Response* response, + 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(); + } + + ::grpc_impl::ClientContext* const context_; + grpc::internal::Call call_; + experimental::ClientUnaryReactor* const reactor_; + + grpc::internal::CallOpSet + start_ops_; + grpc::internal::CallbackWithSuccessTag start_tag_; + + grpc::internal::CallOpSet + finish_ops_; + grpc::internal::CallbackWithSuccessTag finish_tag_; + ::grpc::Status finish_status_; + + // This call will have 2 callbacks: start and finish + std::atomic callbacks_outstanding_{2}; + bool started_{false}; +}; + +class ClientCallbackUnaryFactory { + public: + template + static void Create(::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context, + const Request* request, Response* response, + experimental::ClientUnaryReactor* reactor) { + grpc::internal::Call call = + channel->CreateCall(method, context, channel->CallbackCQ()); + + ::grpc::g_core_codegen_interface->grpc_call_ref(call.call()); + + new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(ClientCallbackUnaryImpl))) + ClientCallbackUnaryImpl(call, context, request, response, reactor); + } +}; + +} // namespace internal +} // namespace grpc_impl +#endif // GRPCPP_IMPL_CODEGEN_CLIENT_CALLBACK_IMPL_H diff --git a/include/grpcpp/impl/codegen/client_context_impl.h b/include/grpcpp/impl/codegen/client_context_impl.h index 8491215cf0e..638ea641bed 100644 --- a/include/grpcpp/impl/codegen/client_context_impl.h +++ b/include/grpcpp/impl/codegen/client_context_impl.h @@ -63,10 +63,19 @@ class ChannelInterface; namespace internal { class RpcMethod; -class CallOpClientRecvStatus; -class CallOpRecvInitialMetadata; template class BlockingUnaryCallImpl; +class CallOpClientRecvStatus; +class CallOpRecvInitialMetadata; +} // namespace internal + +namespace testing { +class InteropClientContextInspector; +} // namespace testing +} // namespace grpc +namespace grpc_impl { + +namespace internal { template class CallbackUnaryCallImpl; template @@ -78,6 +87,10 @@ class ClientCallbackWriterImpl; class ClientCallbackUnaryImpl; } // namespace internal +class CallCredentials; +class Channel; +class CompletionQueue; +class ServerContext; template class ClientReader; template @@ -93,17 +106,6 @@ class ClientAsyncReaderWriter; template class ClientAsyncResponseReader; -namespace testing { -class InteropClientContextInspector; -} // namespace testing -} // namespace grpc -namespace grpc_impl { - -class CallCredentials; -class Channel; -class CompletionQueue; -class ServerContext; - /// Options for \a ClientContext::FromServerContext specifying which traits from /// the \a ServerContext to propagate (copy) from it into a new \a /// ClientContext. @@ -398,30 +400,30 @@ class ClientContext { friend class ::grpc::internal::CallOpRecvInitialMetadata; friend class ::grpc_impl::Channel; template - friend class ::grpc::ClientReader; + friend class ::grpc_impl::ClientReader; template - friend class ::grpc::ClientWriter; + friend class ::grpc_impl::ClientWriter; template - friend class ::grpc::ClientReaderWriter; + friend class ::grpc_impl::ClientReaderWriter; template - friend class ::grpc::ClientAsyncReader; + friend class ::grpc_impl::ClientAsyncReader; template - friend class ::grpc::ClientAsyncWriter; + friend class ::grpc_impl::ClientAsyncWriter; template - friend class ::grpc::ClientAsyncReaderWriter; + friend class ::grpc_impl::ClientAsyncReaderWriter; template - friend class ::grpc::ClientAsyncResponseReader; + friend class ::grpc_impl::ClientAsyncResponseReader; template friend class ::grpc::internal::BlockingUnaryCallImpl; template - friend class ::grpc::internal::CallbackUnaryCallImpl; + friend class ::grpc_impl::internal::CallbackUnaryCallImpl; template - friend class ::grpc::internal::ClientCallbackReaderWriterImpl; + friend class ::grpc_impl::internal::ClientCallbackReaderWriterImpl; template - friend class ::grpc::internal::ClientCallbackReaderImpl; + friend class ::grpc_impl::internal::ClientCallbackReaderImpl; template - friend class ::grpc::internal::ClientCallbackWriterImpl; - friend class ::grpc::internal::ClientCallbackUnaryImpl; + friend class ::grpc_impl::internal::ClientCallbackWriterImpl; + friend class ::grpc_impl::internal::ClientCallbackUnaryImpl; // Used by friend class CallOpClientRecvStatus void set_debug_error_string(const grpc::string& debug_error_string) { diff --git a/include/grpcpp/impl/codegen/client_unary_call.h b/include/grpcpp/impl/codegen/client_unary_call.h index 599dd1ecac9..7f80e571c07 100644 --- a/include/grpcpp/impl/codegen/client_unary_call.h +++ b/include/grpcpp/impl/codegen/client_unary_call.h @@ -49,10 +49,10 @@ class BlockingUnaryCallImpl { BlockingUnaryCallImpl(ChannelInterface* channel, const RpcMethod& method, grpc_impl::ClientContext* context, const InputMessage& request, OutputMessage* result) { - CompletionQueue cq(grpc_completion_queue_attributes{ + ::grpc_impl::CompletionQueue cq(grpc_completion_queue_attributes{ GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING, nullptr}); // Pluckable completion queue - Call call(channel->CreateCall(method, context, &cq)); + ::grpc::internal::Call call(channel->CreateCall(method, context, &cq)); CallOpSet, CallOpClientSendClose, CallOpClientRecvStatus> diff --git a/include/grpcpp/impl/codegen/completion_queue_impl.h b/include/grpcpp/impl/codegen/completion_queue_impl.h index 0a6b0b0977b..7716a57e84a 100644 --- a/include/grpcpp/impl/codegen/completion_queue_impl.h +++ b/include/grpcpp/impl/codegen/completion_queue_impl.h @@ -47,9 +47,6 @@ class Channel; class Server; class ServerBuilder; class ServerContext; -} // namespace grpc_impl -namespace grpc { - template class ClientReader; template @@ -64,6 +61,8 @@ namespace internal { template class ServerReaderWriterBody; } // namespace internal +} // namespace grpc_impl +namespace grpc { class ChannelInterface; class ServerInterface; @@ -255,17 +254,17 @@ class CompletionQueue : private ::grpc::GrpcLibraryCodegen { // Friend synchronous wrappers so that they can access Pluck(), which is // a semi-private API geared towards the synchronous implementation. template - friend class ::grpc::ClientReader; + friend class ::grpc_impl::ClientReader; template - friend class ::grpc::ClientWriter; + friend class ::grpc_impl::ClientWriter; template - friend class ::grpc::ClientReaderWriter; + friend class ::grpc_impl::ClientReaderWriter; template - friend class ::grpc::ServerReader; + friend class ::grpc_impl::ServerReader; template - friend class ::grpc::ServerWriter; + friend class ::grpc_impl::ServerWriter; template - friend class ::grpc::internal::ServerReaderWriterBody; + friend class ::grpc_impl::internal::ServerReaderWriterBody; template friend class ::grpc::internal::RpcMethodHandler; template diff --git a/include/grpcpp/impl/codegen/server_callback.h b/include/grpcpp/impl/codegen/server_callback.h index 36ae19c5bec..cb771a662b9 100644 --- a/include/grpcpp/impl/codegen/server_callback.h +++ b/include/grpcpp/impl/codegen/server_callback.h @@ -19,1141 +19,26 @@ #ifndef GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_H #define GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_H -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include namespace grpc { - -// Declare base class of all reactors as internal -namespace internal { - -// Forward declarations -template -class CallbackClientStreamingHandler; -template -class CallbackServerStreamingHandler; -template -class CallbackBidiHandler; - -class ServerReactor { - public: - virtual ~ServerReactor() = default; - virtual void OnDone() = 0; - virtual void OnCancel() = 0; - - private: - friend class ::grpc_impl::ServerContext; - template - friend class CallbackClientStreamingHandler; - template - friend class CallbackServerStreamingHandler; - template - 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 (GPR_UNLIKELY(on_cancel_conditions_remaining_.fetch_sub( - 1, std::memory_order_acq_rel) == 1)) { - OnCancel(); - } - } - - std::atomic on_cancel_conditions_remaining_{2}; -}; - -template -class DefaultMessageHolder - : public experimental::MessageHolder { - public: - DefaultMessageHolder() { - this->set_request(&request_obj_); - this->set_response(&response_obj_); - } - void Release() override { - // the object is allocated in the call arena. - this->~DefaultMessageHolder(); - } - - private: - Request request_obj_; - Response response_obj_; -}; - -} // namespace internal - namespace experimental { - -// Forward declarations -template -class ServerReadReactor; -template -class ServerWriteReactor; -template -class ServerBidiReactor; - -// For unary RPCs, the exposed controller class is only an interface -// and the actual implementation is an internal class. -class ServerCallbackRpcController { - public: - virtual ~ServerCallbackRpcController() = default; - - // The method handler must call this function when it is done so that - // the library knows to free its resources - virtual void Finish(Status s) = 0; - - // Allow the method handler to push out the initial metadata before - // the response and status are ready - virtual void SendInitialMetadata(std::function) = 0; - - /// SetCancelCallback passes in a callback to be called when the RPC is - /// canceled for whatever reason (streaming calls have OnCancel instead). This - /// is an advanced and uncommon use with several important restrictions. This - /// function may not be called more than once on the same RPC. - /// - /// If code calls SetCancelCallback on an RPC, it must also call - /// ClearCancelCallback before calling Finish on the RPC controller. That - /// method makes sure that no cancellation callback is executed for this RPC - /// beyond the point of its return. ClearCancelCallback may be called even if - /// SetCancelCallback was not called for this RPC, and it may be called - /// multiple times. It _must_ be called if SetCancelCallback was called for - /// this RPC. - /// - /// The callback should generally be lightweight and nonblocking and primarily - /// concerned with clearing application state related to the RPC or causing - /// operations (such as cancellations) to happen on dependent RPCs. - /// - /// If the RPC is already canceled at the time that SetCancelCallback is - /// called, the callback is invoked immediately. - /// - /// The cancellation callback may be executed concurrently with the method - /// handler that invokes it but will certainly not issue or execute after the - /// return of ClearCancelCallback. If ClearCancelCallback is invoked while the - /// callback is already executing, the callback will complete its execution - /// before ClearCancelCallback takes effect. - /// - /// To preserve the orderings described above, the callback may be called - /// under a lock that is also used for ClearCancelCallback and - /// ServerContext::IsCancelled, so the callback CANNOT call either of those - /// operations on this RPC or any other function that causes those operations - /// to be called before the callback completes. - virtual void SetCancelCallback(std::function callback) = 0; - virtual void ClearCancelCallback() = 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 RpcAllocatorState* GetRpcAllocatorState() = 0; -}; - -// NOTE: The actual streaming object classes are provided -// as API only to support mocking. There are no implementations of -// these class interfaces in the API. -template -class ServerCallbackReader { - public: - virtual ~ServerCallbackReader() {} - virtual void Finish(Status s) = 0; - virtual void SendInitialMetadata() = 0; - virtual void Read(Request* msg) = 0; - - protected: - template - void BindReactor(ServerReadReactor* reactor) { - reactor->InternalBindReader(this); - } -}; - -template -class ServerCallbackWriter { - public: - virtual ~ServerCallbackWriter() {} - - virtual void Finish(Status s) = 0; - virtual void SendInitialMetadata() = 0; - virtual void Write(const Response* msg, WriteOptions options) = 0; - virtual void WriteAndFinish(const Response* msg, WriteOptions options, - Status s) { - // Default implementation that can/should be overridden - Write(msg, std::move(options)); - Finish(std::move(s)); - } - - protected: - template - void BindReactor(ServerWriteReactor* reactor) { - reactor->InternalBindWriter(this); - } -}; - -template -class ServerCallbackReaderWriter { - public: - virtual ~ServerCallbackReaderWriter() {} - - virtual void Finish(Status s) = 0; - virtual void SendInitialMetadata() = 0; - virtual void Read(Request* msg) = 0; - virtual void Write(const Response* msg, WriteOptions options) = 0; - virtual void WriteAndFinish(const Response* msg, WriteOptions options, - Status s) { - // Default implementation that can/should be overridden - Write(msg, std::move(options)); - Finish(std::move(s)); - } - - protected: - void BindReactor(ServerBidiReactor* reactor) { - reactor->InternalBindStream(this); - } -}; - -// The following classes are the reactor interfaces that are to be implemented -// by the user, returned as the result of the method handler for a callback -// method, and activated by the call to OnStarted. The library guarantees that -// OnStarted will be called for any reactor that has been created using a -// method handler registered on a service. No operation initiation method may be -// called until after the call to OnStarted. -// Note that none of the classes are pure; all reactions have a default empty -// reaction so that the user class only needs to override those classes that it -// cares about. - -/// \a ServerBidiReactor is the interface for a bidirectional streaming RPC. template -class ServerBidiReactor : public internal::ServerReactor { - public: - ~ServerBidiReactor() = default; - - /// Do NOT call any operation initiation method (names that start with Start) - /// until after the library has called OnStarted on this object. - - /// Send any initial metadata stored in the RPC context. If not invoked, - /// any initial metadata will be passed along with the first Write or the - /// Finish (if there are no writes). - void StartSendInitialMetadata() { stream_->SendInitialMetadata(); } - - /// Initiate a read operation. - /// - /// \param[out] req Where to eventually store the read message. Valid when - /// the library calls OnReadDone - void StartRead(Request* req) { stream_->Read(req); } - - /// Initiate a write operation. - /// - /// \param[in] resp The message to be written. The library takes temporary - /// ownership until OnWriteDone, at which point the - /// application regains ownership of resp. - void StartWrite(const Response* resp) { StartWrite(resp, WriteOptions()); } - - /// Initiate a write operation with specified options. - /// - /// \param[in] resp The message to be written. The library takes temporary - /// ownership until OnWriteDone, at which point the - /// application regains ownership of resp. - /// \param[in] options The WriteOptions to use for writing this message - void StartWrite(const Response* resp, WriteOptions options) { - stream_->Write(resp, std::move(options)); - } - - /// Initiate a write operation with specified options and final RPC Status, - /// which also causes any trailing metadata for this RPC to be sent out. - /// StartWriteAndFinish is like merging StartWriteLast and Finish into a - /// single step. A key difference, though, is that this operation doesn't have - /// an OnWriteDone reaction - it is considered complete only when OnDone is - /// available. An RPC can either have StartWriteAndFinish or Finish, but not - /// both. - /// - /// \param[in] resp The message to be written. The library takes temporary - /// ownership until Onone, at which point the application - /// regains ownership of resp. - /// \param[in] options The WriteOptions to use for writing this message - /// \param[in] s The status outcome of this RPC - void StartWriteAndFinish(const Response* resp, WriteOptions options, - Status s) { - stream_->WriteAndFinish(resp, std::move(options), std::move(s)); - } - - /// Inform system of a planned write operation with specified options, but - /// allow the library to schedule the actual write coalesced with the writing - /// of trailing metadata (which takes place on a Finish call). - /// - /// \param[in] resp The message to be written. The library takes temporary - /// ownership until OnWriteDone, at which point the - /// application regains ownership of resp. - /// \param[in] options The WriteOptions to use for writing this message - void StartWriteLast(const Response* resp, WriteOptions options) { - StartWrite(resp, std::move(options.set_last_message())); - } - - /// Indicate that the stream is to be finished and the trailing metadata and - /// RPC status are to be sent. Every RPC MUST be finished using either Finish - /// or StartWriteAndFinish (but not both), even if the RPC is already - /// cancelled. - /// - /// \param[in] s The status outcome of this RPC - void Finish(Status s) { stream_->Finish(std::move(s)); } - - /// Notify the application that a streaming RPC has started and that it is now - /// ok to call any operation initiation method. An RPC is considered started - /// after the server has received all initial metadata from the client, which - /// is a result of the client calling StartCall(). - /// - /// \param[in] context The context object now associated with this RPC - virtual void OnStarted(::grpc_impl::ServerContext* context) {} - - /// Notifies the application that an explicit StartSendInitialMetadata - /// operation completed. Not used when the sending of initial metadata - /// piggybacks onto the first write. - /// - /// \param[in] ok Was it successful? If false, no further write-side operation - /// will succeed. - virtual void OnSendInitialMetadataDone(bool ok) {} - - /// Notifies the application that a StartRead operation completed. - /// - /// \param[in] ok Was it successful? If false, no further read-side operation - /// will succeed. - virtual void OnReadDone(bool ok) {} - - /// Notifies the application that a StartWrite (or StartWriteLast) operation - /// completed. - /// - /// \param[in] ok Was it successful? If false, no further write-side operation - /// will succeed. - virtual void OnWriteDone(bool ok) {} - - /// Notifies the application that all operations associated with this RPC - /// have completed. This is an override (from the internal base class) but not - /// final, so derived classes should override it if they want to take action. - void OnDone() override {} - - /// Notifies the application that this RPC has been cancelled. This is an - /// override (from the internal base class) but not final, so derived classes - /// should override it if they want to take action. - void OnCancel() override {} - - private: - friend class ServerCallbackReaderWriter; - // May be overridden by internal implementation details. This is not a public - // customization point. - virtual void InternalBindStream( - ServerCallbackReaderWriter* stream) { - stream_ = stream; - } +using ServerReadReactor = + ::grpc_impl::experimental::ServerReadReactor; - ServerCallbackReaderWriter* stream_; -}; - -/// \a ServerReadReactor is the interface for a client-streaming RPC. template -class ServerReadReactor : public internal::ServerReactor { - public: - ~ServerReadReactor() = default; - - /// The following operation initiations are exactly like ServerBidiReactor. - void StartSendInitialMetadata() { reader_->SendInitialMetadata(); } - void StartRead(Request* req) { reader_->Read(req); } - void Finish(Status s) { reader_->Finish(std::move(s)); } - - /// Similar to ServerBidiReactor::OnStarted, except that this also provides - /// the response object that the stream fills in before calling Finish. - /// (It must be filled in if status is OK, but it may be filled in otherwise.) - /// - /// \param[in] context The context object now associated with this RPC - /// \param[in] resp The response object to be used by this RPC - virtual void OnStarted(::grpc_impl::ServerContext* context, Response* resp) {} - - /// The following notifications are exactly like ServerBidiReactor. - virtual void OnSendInitialMetadataDone(bool ok) {} - virtual void OnReadDone(bool ok) {} - void OnDone() override {} - void OnCancel() override {} - - private: - friend class ServerCallbackReader; - // May be overridden by internal implementation details. This is not a public - // customization point. - virtual void InternalBindReader(ServerCallbackReader* reader) { - reader_ = reader; - } +using ServerWriteReactor = + ::grpc_impl::experimental::ServerWriteReactor; - ServerCallbackReader* reader_; -}; - -/// \a ServerWriteReactor is the interface for a server-streaming RPC. template -class ServerWriteReactor : public internal::ServerReactor { - public: - ~ServerWriteReactor() = default; - - /// The following operation initiations are exactly like ServerBidiReactor. - void StartSendInitialMetadata() { writer_->SendInitialMetadata(); } - void StartWrite(const Response* resp) { StartWrite(resp, WriteOptions()); } - void StartWrite(const Response* resp, WriteOptions options) { - writer_->Write(resp, std::move(options)); - } - void StartWriteAndFinish(const Response* resp, WriteOptions options, - Status s) { - writer_->WriteAndFinish(resp, std::move(options), std::move(s)); - } - void StartWriteLast(const Response* resp, WriteOptions options) { - StartWrite(resp, std::move(options.set_last_message())); - } - void Finish(Status s) { writer_->Finish(std::move(s)); } - - /// Similar to ServerBidiReactor::OnStarted, except that this also provides - /// the request object sent by the client. - /// - /// \param[in] context The context object now associated with this RPC - /// \param[in] req The request object sent by the client - virtual void OnStarted(::grpc_impl::ServerContext* context, - const Request* req) {} - - /// The following notifications are exactly like ServerBidiReactor. - virtual void OnSendInitialMetadataDone(bool ok) {} - virtual void OnWriteDone(bool ok) {} - void OnDone() override {} - void OnCancel() override {} +using ServerBidiReactor = + ::grpc_impl::experimental::ServerBidiReactor; - private: - friend class ServerCallbackWriter; - // May be overridden by internal implementation details. This is not a public - // customization point. - virtual void InternalBindWriter(ServerCallbackWriter* writer) { - writer_ = writer; - } - - ServerCallbackWriter* writer_; -}; +typedef ::grpc_impl::experimental::ServerCallbackRpcController + ServerCallbackRpcController; } // namespace experimental - -namespace internal { - -template -class UnimplementedReadReactor - : public experimental::ServerReadReactor { - public: - void OnDone() override { delete this; } - void OnStarted(::grpc_impl::ServerContext*, Response*) override { - this->Finish(Status(StatusCode::UNIMPLEMENTED, "")); - } -}; - -template -class UnimplementedWriteReactor - : public experimental::ServerWriteReactor { - public: - void OnDone() override { delete this; } - void OnStarted(::grpc_impl::ServerContext*, const Request*) override { - this->Finish(Status(StatusCode::UNIMPLEMENTED, "")); - } -}; - -template -class UnimplementedBidiReactor - : public experimental::ServerBidiReactor { - public: - void OnDone() override { delete this; } - void OnStarted(::grpc_impl::ServerContext*) override { - this->Finish(Status(StatusCode::UNIMPLEMENTED, "")); - } -}; - -template -class CallbackUnaryHandler : public MethodHandler { - public: - CallbackUnaryHandler( - std::function - func) - : func_(func) {} - - void SetMessageAllocator( - experimental::MessageAllocator* 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_state = - static_cast*>( - param.internal_data); - auto* controller = new (g_core_codegen_interface->grpc_call_arena_alloc( - param.call->call(), sizeof(ServerCallbackRpcControllerImpl))) - ServerCallbackRpcControllerImpl(param.server_context, param.call, - allocator_state, - 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(), - controller->response(), controller); - } else { - // if deserialization failed, we need to fail the call - controller->Finish(status); - } - } - - void* Deserialize(grpc_call* call, grpc_byte_buffer* req, Status* status, - void** handler_data) final { - ByteBuffer buf; - buf.set_buffer(req); - RequestType* request = nullptr; - experimental::MessageHolder* allocator_state = - nullptr; - if (allocator_ != nullptr) { - allocator_state = allocator_->AllocateMessages(); - } else { - allocator_state = new (g_core_codegen_interface->grpc_call_arena_alloc( - call, sizeof(DefaultMessageHolder))) - DefaultMessageHolder(); - } - *handler_data = allocator_state; - request = allocator_state->request(); - *status = SerializationTraits::Deserialize(&buf, request); - buf.Release(); - if (status->ok()) { - return request; - } - // Clean up on deserialization failure. - allocator_state->Release(); - return nullptr; - } - - private: - std::function - func_; - experimental::MessageAllocator* allocator_ = - nullptr; - - // The implementation class of ServerCallbackRpcController is a private member - // of CallbackUnaryHandler since it is never exposed anywhere, and this allows - // it to take advantage of CallbackUnaryHandler's friendships. - class ServerCallbackRpcControllerImpl - : public experimental::ServerCallbackRpcController { - public: - void Finish(Status s) override { - finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); }, - &finish_ops_); - if (!ctx_->sent_initial_metadata_) { - finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - finish_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - } - // The response is dropped if the status is not OK. - if (s.ok()) { - finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, - finish_ops_.SendMessagePtr(response())); - } else { - finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s); - } - finish_ops_.set_core_cq_tag(&finish_tag_); - call_.PerformOps(&finish_ops_); - } - - void SendInitialMetadata(std::function f) override { - GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); - callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); - // TODO(vjpai): Consider taking f as a move-capture if we adopt C++14 - // and if performance of this operation matters - meta_tag_.Set(call_.call(), - [this, f](bool ok) { - f(ok); - MaybeDone(); - }, - &meta_ops_); - meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - meta_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - meta_ops_.set_core_cq_tag(&meta_tag_); - call_.PerformOps(&meta_ops_); - } - - // Neither SetCancelCallback nor ClearCancelCallback should affect the - // callbacks_outstanding_ count since they are paired and both must precede - // the invocation of Finish (if they are used at all) - void SetCancelCallback(std::function callback) override { - ctx_->SetCancelCallback(std::move(callback)); - } - - void ClearCancelCallback() override { ctx_->ClearCancelCallback(); } - - experimental::RpcAllocatorState* GetRpcAllocatorState() override { - return allocator_state_; - } - - private: - friend class CallbackUnaryHandler; - - ServerCallbackRpcControllerImpl( - ::grpc_impl::ServerContext* ctx, Call* call, - experimental::MessageHolder* allocator_state, - std::function call_requester) - : ctx_(ctx), - call_(*call), - allocator_state_(allocator_state), - call_requester_(std::move(call_requester)) { - ctx_->BeginCompletionOp(call, [this](bool) { MaybeDone(); }, nullptr); - } - - const RequestType* request() { return allocator_state_->request(); } - ResponseType* response() { return allocator_state_->response(); } - - void MaybeDone() { - if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( - 1, std::memory_order_acq_rel) == 1)) { - grpc_call* call = call_.call(); - auto call_requester = std::move(call_requester_); - allocator_state_->Release(); - this->~ServerCallbackRpcControllerImpl(); // explicitly call destructor - g_core_codegen_interface->grpc_call_unref(call); - call_requester(); - } - } - - CallOpSet meta_ops_; - CallbackWithSuccessTag meta_tag_; - CallOpSet - finish_ops_; - CallbackWithSuccessTag finish_tag_; - - ::grpc_impl::ServerContext* ctx_; - Call call_; - experimental::MessageHolder* const - allocator_state_; - std::function call_requester_; - std::atomic callbacks_outstanding_{ - 2}; // reserve for Finish and CompletionOp - }; -}; - -template -class CallbackClientStreamingHandler : public MethodHandler { - public: - CallbackClientStreamingHandler( - std::function< - experimental::ServerReadReactor*()> - func) - : func_(std::move(func)) {} - void RunHandler(const HandlerParameter& param) final { - // Arena allocate a reader structure (that includes response) - g_core_codegen_interface->grpc_call_ref(param.call->call()); - - experimental::ServerReadReactor* reactor = - param.status.ok() - ? CatchingReactorCreator< - experimental::ServerReadReactor>( - func_) - : nullptr; - - if (reactor == nullptr) { - // if deserialization or reactor creator failed, we need to fail the call - reactor = new UnimplementedReadReactor; - } - - auto* reader = new (g_core_codegen_interface->grpc_call_arena_alloc( - param.call->call(), sizeof(ServerCallbackReaderImpl))) - ServerCallbackReaderImpl(param.server_context, param.call, - std::move(param.call_requester), reactor); - - 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(); - } - - private: - std::function*()> - func_; - - class ServerCallbackReaderImpl - : public experimental::ServerCallbackReader { - public: - void Finish(Status s) override { - finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); }, - &finish_ops_); - if (!ctx_->sent_initial_metadata_) { - finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - finish_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - } - // The response is dropped if the status is not OK. - if (s.ok()) { - finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, - finish_ops_.SendMessagePtr(&resp_)); - } else { - finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s); - } - finish_ops_.set_core_cq_tag(&finish_tag_); - call_.PerformOps(&finish_ops_); - } - - void SendInitialMetadata() override { - GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); - callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); - meta_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnSendInitialMetadataDone(ok); - MaybeDone(); - }, - &meta_ops_); - meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - meta_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - meta_ops_.set_core_cq_tag(&meta_tag_); - call_.PerformOps(&meta_ops_); - } - - void Read(RequestType* req) override { - callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); - read_ops_.RecvMessage(req); - call_.PerformOps(&read_ops_); - } - - private: - friend class CallbackClientStreamingHandler; - - ServerCallbackReaderImpl( - ::grpc_impl::ServerContext* ctx, Call* call, - std::function call_requester, - experimental::ServerReadReactor* reactor) - : ctx_(ctx), - call_(*call), - call_requester_(std::move(call_requester)), - reactor_(reactor) { - ctx_->BeginCompletionOp(call, [this](bool) { MaybeDone(); }, reactor); - read_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnReadDone(ok); - MaybeDone(); - }, - &read_ops_); - read_ops_.set_core_cq_tag(&read_tag_); - } - - ~ServerCallbackReaderImpl() {} - - ResponseType* response() { return &resp_; } - - void MaybeDone() { - if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( - 1, std::memory_order_acq_rel) == 1)) { - reactor_->OnDone(); - grpc_call* call = call_.call(); - auto call_requester = std::move(call_requester_); - this->~ServerCallbackReaderImpl(); // explicitly call destructor - g_core_codegen_interface->grpc_call_unref(call); - call_requester(); - } - } - - CallOpSet meta_ops_; - CallbackWithSuccessTag meta_tag_; - CallOpSet - finish_ops_; - CallbackWithSuccessTag finish_tag_; - CallOpSet> read_ops_; - CallbackWithSuccessTag read_tag_; - - ::grpc_impl::ServerContext* ctx_; - Call call_; - ResponseType resp_; - std::function call_requester_; - experimental::ServerReadReactor* reactor_; - std::atomic callbacks_outstanding_{ - 3}; // reserve for OnStarted, Finish, and CompletionOp - }; -}; - -template -class CallbackServerStreamingHandler : public MethodHandler { - public: - CallbackServerStreamingHandler( - std::function< - experimental::ServerWriteReactor*()> - func) - : func_(std::move(func)) {} - void RunHandler(const HandlerParameter& param) final { - // Arena allocate a writer structure - g_core_codegen_interface->grpc_call_ref(param.call->call()); - - experimental::ServerWriteReactor* reactor = - param.status.ok() - ? CatchingReactorCreator< - experimental::ServerWriteReactor>( - func_) - : nullptr; - - if (reactor == nullptr) { - // if deserialization or reactor creator failed, we need to fail the call - reactor = new UnimplementedWriteReactor; - } - - auto* writer = new (g_core_codegen_interface->grpc_call_arena_alloc( - param.call->call(), sizeof(ServerCallbackWriterImpl))) - ServerCallbackWriterImpl(param.server_context, param.call, - static_cast(param.request), - 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, - 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(); - *status = SerializationTraits::Deserialize(&buf, request); - buf.Release(); - if (status->ok()) { - return request; - } - request->~RequestType(); - return nullptr; - } - - private: - std::function*()> - func_; - - class ServerCallbackWriterImpl - : public experimental::ServerCallbackWriter { - public: - void Finish(Status s) override { - finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); }, - &finish_ops_); - finish_ops_.set_core_cq_tag(&finish_tag_); - - if (!ctx_->sent_initial_metadata_) { - finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - finish_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - } - finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s); - call_.PerformOps(&finish_ops_); - } - - void SendInitialMetadata() override { - GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); - callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); - meta_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnSendInitialMetadataDone(ok); - MaybeDone(); - }, - &meta_ops_); - meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - meta_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - meta_ops_.set_core_cq_tag(&meta_tag_); - call_.PerformOps(&meta_ops_); - } - - void Write(const ResponseType* resp, WriteOptions options) override { - callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); - if (options.is_last_message()) { - options.set_buffer_hint(); - } - if (!ctx_->sent_initial_metadata_) { - write_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - write_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - } - // TODO(vjpai): don't assert - GPR_CODEGEN_ASSERT(write_ops_.SendMessagePtr(resp, options).ok()); - call_.PerformOps(&write_ops_); - } - - void WriteAndFinish(const ResponseType* resp, WriteOptions options, - Status s) override { - // This combines the write into the finish callback - // Don't send any message if the status is bad - if (s.ok()) { - // TODO(vjpai): don't assert - GPR_CODEGEN_ASSERT(finish_ops_.SendMessagePtr(resp, options).ok()); - } - Finish(std::move(s)); - } - - private: - friend class CallbackServerStreamingHandler; - - ServerCallbackWriterImpl( - ::grpc_impl::ServerContext* ctx, Call* call, const RequestType* req, - std::function call_requester, - experimental::ServerWriteReactor* reactor) - : ctx_(ctx), - call_(*call), - req_(req), - call_requester_(std::move(call_requester)), - reactor_(reactor) { - ctx_->BeginCompletionOp(call, [this](bool) { MaybeDone(); }, reactor); - write_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnWriteDone(ok); - MaybeDone(); - }, - &write_ops_); - write_ops_.set_core_cq_tag(&write_tag_); - } - ~ServerCallbackWriterImpl() { req_->~RequestType(); } - - const RequestType* request() { return req_; } - - void MaybeDone() { - if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( - 1, std::memory_order_acq_rel) == 1)) { - reactor_->OnDone(); - grpc_call* call = call_.call(); - auto call_requester = std::move(call_requester_); - this->~ServerCallbackWriterImpl(); // explicitly call destructor - g_core_codegen_interface->grpc_call_unref(call); - call_requester(); - } - } - - CallOpSet meta_ops_; - CallbackWithSuccessTag meta_tag_; - CallOpSet - finish_ops_; - CallbackWithSuccessTag finish_tag_; - CallOpSet write_ops_; - CallbackWithSuccessTag write_tag_; - - ::grpc_impl::ServerContext* ctx_; - Call call_; - const RequestType* req_; - std::function call_requester_; - experimental::ServerWriteReactor* reactor_; - std::atomic callbacks_outstanding_{ - 3}; // reserve for OnStarted, Finish, and CompletionOp - }; -}; - -template -class CallbackBidiHandler : public MethodHandler { - public: - CallbackBidiHandler( - std::function< - experimental::ServerBidiReactor*()> - func) - : func_(std::move(func)) {} - void RunHandler(const HandlerParameter& param) final { - g_core_codegen_interface->grpc_call_ref(param.call->call()); - - experimental::ServerBidiReactor* reactor = - param.status.ok() - ? CatchingReactorCreator< - experimental::ServerBidiReactor>( - func_) - : nullptr; - - if (reactor == nullptr) { - // if deserialization or reactor creator failed, we need to fail the call - reactor = new UnimplementedBidiReactor; - } - - auto* stream = new (g_core_codegen_interface->grpc_call_arena_alloc( - param.call->call(), sizeof(ServerCallbackReaderWriterImpl))) - ServerCallbackReaderWriterImpl(param.server_context, param.call, - std::move(param.call_requester), - reactor); - - stream->BindReactor(reactor); - reactor->OnStarted(param.server_context); - // The earliest that OnCancel can be called is after OnStarted is done. - reactor->MaybeCallOnCancel(); - stream->MaybeDone(); - } - - private: - std::function*()> - func_; - - class ServerCallbackReaderWriterImpl - : public experimental::ServerCallbackReaderWriter { - public: - void Finish(Status s) override { - finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); }, - &finish_ops_); - finish_ops_.set_core_cq_tag(&finish_tag_); - - if (!ctx_->sent_initial_metadata_) { - finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - finish_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - } - finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s); - call_.PerformOps(&finish_ops_); - } - - void SendInitialMetadata() override { - GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); - callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); - meta_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnSendInitialMetadataDone(ok); - MaybeDone(); - }, - &meta_ops_); - meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - meta_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - meta_ops_.set_core_cq_tag(&meta_tag_); - call_.PerformOps(&meta_ops_); - } - - void Write(const ResponseType* resp, WriteOptions options) override { - callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); - if (options.is_last_message()) { - options.set_buffer_hint(); - } - if (!ctx_->sent_initial_metadata_) { - write_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - write_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - } - // TODO(vjpai): don't assert - GPR_CODEGEN_ASSERT(write_ops_.SendMessagePtr(resp, options).ok()); - call_.PerformOps(&write_ops_); - } - - void WriteAndFinish(const ResponseType* resp, WriteOptions options, - Status s) override { - // Don't send any message if the status is bad - if (s.ok()) { - // TODO(vjpai): don't assert - GPR_CODEGEN_ASSERT(finish_ops_.SendMessagePtr(resp, options).ok()); - } - Finish(std::move(s)); - } - - void Read(RequestType* req) override { - callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); - read_ops_.RecvMessage(req); - call_.PerformOps(&read_ops_); - } - - private: - friend class CallbackBidiHandler; - - ServerCallbackReaderWriterImpl( - ::grpc_impl::ServerContext* ctx, Call* call, - std::function call_requester, - experimental::ServerBidiReactor* reactor) - : ctx_(ctx), - call_(*call), - call_requester_(std::move(call_requester)), - reactor_(reactor) { - ctx_->BeginCompletionOp(call, [this](bool) { MaybeDone(); }, reactor); - write_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnWriteDone(ok); - MaybeDone(); - }, - &write_ops_); - write_ops_.set_core_cq_tag(&write_tag_); - read_tag_.Set(call_.call(), - [this](bool ok) { - reactor_->OnReadDone(ok); - MaybeDone(); - }, - &read_ops_); - read_ops_.set_core_cq_tag(&read_tag_); - } - ~ServerCallbackReaderWriterImpl() {} - - void MaybeDone() { - if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( - 1, std::memory_order_acq_rel) == 1)) { - reactor_->OnDone(); - grpc_call* call = call_.call(); - auto call_requester = std::move(call_requester_); - this->~ServerCallbackReaderWriterImpl(); // explicitly call destructor - g_core_codegen_interface->grpc_call_unref(call); - call_requester(); - } - } - - CallOpSet meta_ops_; - CallbackWithSuccessTag meta_tag_; - CallOpSet - finish_ops_; - CallbackWithSuccessTag finish_tag_; - CallOpSet write_ops_; - CallbackWithSuccessTag write_tag_; - CallOpSet> read_ops_; - CallbackWithSuccessTag read_tag_; - - ::grpc_impl::ServerContext* ctx_; - Call call_; - std::function call_requester_; - experimental::ServerBidiReactor* reactor_; - std::atomic callbacks_outstanding_{ - 3}; // reserve for OnStarted, Finish, and CompletionOp - }; -}; - -} // namespace internal - } // namespace grpc #endif // GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_H diff --git a/include/grpcpp/impl/codegen/server_callback_impl.h b/include/grpcpp/impl/codegen/server_callback_impl.h new file mode 100644 index 00000000000..08ecdfd6497 --- /dev/null +++ b/include/grpcpp/impl/codegen/server_callback_impl.h @@ -0,0 +1,1186 @@ +/* + * + * 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_SERVER_CALLBACK_IMPL_H +#define GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_IMPL_H + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace grpc_impl { + +// Declare base class of all reactors as internal +namespace internal { + +// Forward declarations +template +class CallbackClientStreamingHandler; +template +class CallbackServerStreamingHandler; +template +class CallbackBidiHandler; + +class ServerReactor { + public: + virtual ~ServerReactor() = default; + virtual void OnDone() = 0; + virtual void OnCancel() = 0; + + private: + friend class ::grpc_impl::ServerContext; + template + friend class CallbackClientStreamingHandler; + template + friend class CallbackServerStreamingHandler; + template + 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 (GPR_UNLIKELY(on_cancel_conditions_remaining_.fetch_sub( + 1, std::memory_order_acq_rel) == 1)) { + OnCancel(); + } + } + + std::atomic on_cancel_conditions_remaining_{2}; +}; + +template +class DefaultMessageHolder + : public ::grpc::experimental::MessageHolder { + public: + DefaultMessageHolder() { + this->set_request(&request_obj_); + this->set_response(&response_obj_); + } + void Release() override { + // the object is allocated in the call arena. + this->~DefaultMessageHolder(); + } + + private: + Request request_obj_; + Response response_obj_; +}; + +} // namespace internal + +namespace experimental { + +// Forward declarations +template +class ServerReadReactor; +template +class ServerWriteReactor; +template +class ServerBidiReactor; + +// For unary RPCs, the exposed controller class is only an interface +// and the actual implementation is an internal class. +class ServerCallbackRpcController { + public: + virtual ~ServerCallbackRpcController() = default; + + // The method handler must call this function when it is done so that + // the library knows to free its resources + virtual void Finish(::grpc::Status s) = 0; + + // Allow the method handler to push out the initial metadata before + // the response and status are ready + virtual void SendInitialMetadata(std::function) = 0; + + /// SetCancelCallback passes in a callback to be called when the RPC is + /// canceled for whatever reason (streaming calls have OnCancel instead). This + /// is an advanced and uncommon use with several important restrictions. This + /// function may not be called more than once on the same RPC. + /// + /// If code calls SetCancelCallback on an RPC, it must also call + /// ClearCancelCallback before calling Finish on the RPC controller. That + /// method makes sure that no cancellation callback is executed for this RPC + /// beyond the point of its return. ClearCancelCallback may be called even if + /// SetCancelCallback was not called for this RPC, and it may be called + /// multiple times. It _must_ be called if SetCancelCallback was called for + /// this RPC. + /// + /// The callback should generally be lightweight and nonblocking and primarily + /// concerned with clearing application state related to the RPC or causing + /// operations (such as cancellations) to happen on dependent RPCs. + /// + /// If the RPC is already canceled at the time that SetCancelCallback is + /// called, the callback is invoked immediately. + /// + /// The cancellation callback may be executed concurrently with the method + /// handler that invokes it but will certainly not issue or execute after the + /// return of ClearCancelCallback. If ClearCancelCallback is invoked while the + /// callback is already executing, the callback will complete its execution + /// before ClearCancelCallback takes effect. + /// + /// To preserve the orderings described above, the callback may be called + /// under a lock that is also used for ClearCancelCallback and + /// ServerContext::IsCancelled, so the callback CANNOT call either of those + /// operations on this RPC or any other function that causes those operations + /// to be called before the callback completes. + virtual void SetCancelCallback(std::function callback) = 0; + virtual void ClearCancelCallback() = 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 grpc::experimental::RpcAllocatorState* GetRpcAllocatorState() = 0; +}; + +// NOTE: The actual streaming object classes are provided +// as API only to support mocking. There are no implementations of +// these class interfaces in the API. +template +class ServerCallbackReader { + public: + virtual ~ServerCallbackReader() {} + virtual void Finish(::grpc::Status s) = 0; + virtual void SendInitialMetadata() = 0; + virtual void Read(Request* msg) = 0; + + protected: + template + void BindReactor(ServerReadReactor* reactor) { + reactor->InternalBindReader(this); + } +}; + +template +class ServerCallbackWriter { + public: + virtual ~ServerCallbackWriter() {} + + virtual void Finish(::grpc::Status s) = 0; + virtual void SendInitialMetadata() = 0; + virtual void Write(const Response* msg, ::grpc::WriteOptions options) = 0; + virtual void WriteAndFinish(const Response* msg, ::grpc::WriteOptions options, + ::grpc::Status s) { + // Default implementation that can/should be overridden + Write(msg, std::move(options)); + Finish(std::move(s)); + } + + protected: + template + void BindReactor(ServerWriteReactor* reactor) { + reactor->InternalBindWriter(this); + } +}; + +template +class ServerCallbackReaderWriter { + public: + virtual ~ServerCallbackReaderWriter() {} + + virtual void Finish(::grpc::Status s) = 0; + virtual void SendInitialMetadata() = 0; + virtual void Read(Request* msg) = 0; + virtual void Write(const Response* msg, ::grpc::WriteOptions options) = 0; + virtual void WriteAndFinish(const Response* msg, ::grpc::WriteOptions options, + ::grpc::Status s) { + // Default implementation that can/should be overridden + Write(msg, std::move(options)); + Finish(std::move(s)); + } + + protected: + void BindReactor(ServerBidiReactor* reactor) { + reactor->InternalBindStream(this); + } +}; + +// The following classes are the reactor interfaces that are to be implemented +// by the user, returned as the result of the method handler for a callback +// method, and activated by the call to OnStarted. The library guarantees that +// OnStarted will be called for any reactor that has been created using a +// method handler registered on a service. No operation initiation method may be +// called until after the call to OnStarted. +// Note that none of the classes are pure; all reactions have a default empty +// reaction so that the user class only needs to override those classes that it +// cares about. + +/// \a ServerBidiReactor is the interface for a bidirectional streaming RPC. +template +class ServerBidiReactor : public internal::ServerReactor { + public: + ~ServerBidiReactor() = default; + + /// Do NOT call any operation initiation method (names that start with Start) + /// until after the library has called OnStarted on this object. + + /// Send any initial metadata stored in the RPC context. If not invoked, + /// any initial metadata will be passed along with the first Write or the + /// Finish (if there are no writes). + void StartSendInitialMetadata() { stream_->SendInitialMetadata(); } + + /// Initiate a read operation. + /// + /// \param[out] req Where to eventually store the read message. Valid when + /// the library calls OnReadDone + void StartRead(Request* req) { stream_->Read(req); } + + /// Initiate a write operation. + /// + /// \param[in] resp The message to be written. The library takes temporary + /// ownership until OnWriteDone, at which point the + /// application regains ownership of resp. + void StartWrite(const Response* resp) { + StartWrite(resp, ::grpc::WriteOptions()); + } + + /// Initiate a write operation with specified options. + /// + /// \param[in] resp The message to be written. The library takes temporary + /// ownership until OnWriteDone, at which point the + /// application regains ownership of resp. + /// \param[in] options The WriteOptions to use for writing this message + void StartWrite(const Response* resp, ::grpc::WriteOptions options) { + stream_->Write(resp, std::move(options)); + } + + /// Initiate a write operation with specified options and final RPC Status, + /// which also causes any trailing metadata for this RPC to be sent out. + /// StartWriteAndFinish is like merging StartWriteLast and Finish into a + /// single step. A key difference, though, is that this operation doesn't have + /// an OnWriteDone reaction - it is considered complete only when OnDone is + /// available. An RPC can either have StartWriteAndFinish or Finish, but not + /// both. + /// + /// \param[in] resp The message to be written. The library takes temporary + /// ownership until Onone, at which point the application + /// regains ownership of resp. + /// \param[in] options The WriteOptions to use for writing this message + /// \param[in] s The status outcome of this RPC + void StartWriteAndFinish(const Response* resp, ::grpc::WriteOptions options, + ::grpc::Status s) { + stream_->WriteAndFinish(resp, std::move(options), std::move(s)); + } + + /// Inform system of a planned write operation with specified options, but + /// allow the library to schedule the actual write coalesced with the writing + /// of trailing metadata (which takes place on a Finish call). + /// + /// \param[in] resp The message to be written. The library takes temporary + /// ownership until OnWriteDone, at which point the + /// application regains ownership of resp. + /// \param[in] options The WriteOptions to use for writing this message + void StartWriteLast(const Response* resp, ::grpc::WriteOptions options) { + StartWrite(resp, std::move(options.set_last_message())); + } + + /// Indicate that the stream is to be finished and the trailing metadata and + /// RPC status are to be sent. Every RPC MUST be finished using either Finish + /// or StartWriteAndFinish (but not both), even if the RPC is already + /// cancelled. + /// + /// \param[in] s The status outcome of this RPC + void Finish(::grpc::Status s) { stream_->Finish(std::move(s)); } + + /// Notify the application that a streaming RPC has started and that it is now + /// ok to call any operation initiation method. An RPC is considered started + /// after the server has received all initial metadata from the client, which + /// is a result of the client calling StartCall(). + /// + /// \param[in] context The context object now associated with this RPC + virtual void OnStarted(::grpc_impl::ServerContext* context) {} + + /// Notifies the application that an explicit StartSendInitialMetadata + /// operation completed. Not used when the sending of initial metadata + /// piggybacks onto the first write. + /// + /// \param[in] ok Was it successful? If false, no further write-side operation + /// will succeed. + virtual void OnSendInitialMetadataDone(bool ok) {} + + /// Notifies the application that a StartRead operation completed. + /// + /// \param[in] ok Was it successful? If false, no further read-side operation + /// will succeed. + virtual void OnReadDone(bool ok) {} + + /// Notifies the application that a StartWrite (or StartWriteLast) operation + /// completed. + /// + /// \param[in] ok Was it successful? If false, no further write-side operation + /// will succeed. + virtual void OnWriteDone(bool ok) {} + + /// Notifies the application that all operations associated with this RPC + /// have completed. This is an override (from the internal base class) but not + /// final, so derived classes should override it if they want to take action. + void OnDone() override {} + + /// Notifies the application that this RPC has been cancelled. This is an + /// override (from the internal base class) but not final, so derived classes + /// should override it if they want to take action. + void OnCancel() override {} + + private: + friend class ServerCallbackReaderWriter; + // May be overridden by internal implementation details. This is not a public + // customization point. + virtual void InternalBindStream( + ServerCallbackReaderWriter* stream) { + stream_ = stream; + } + + ServerCallbackReaderWriter* stream_; +}; + +/// \a ServerReadReactor is the interface for a client-streaming RPC. +template +class ServerReadReactor : public internal::ServerReactor { + public: + ~ServerReadReactor() = default; + + /// The following operation initiations are exactly like ServerBidiReactor. + void StartSendInitialMetadata() { reader_->SendInitialMetadata(); } + void StartRead(Request* req) { reader_->Read(req); } + void Finish(::grpc::Status s) { reader_->Finish(std::move(s)); } + + /// Similar to ServerBidiReactor::OnStarted, except that this also provides + /// the response object that the stream fills in before calling Finish. + /// (It must be filled in if status is OK, but it may be filled in otherwise.) + /// + /// \param[in] context The context object now associated with this RPC + /// \param[in] resp The response object to be used by this RPC + virtual void OnStarted(::grpc_impl::ServerContext* context, Response* resp) {} + + /// The following notifications are exactly like ServerBidiReactor. + virtual void OnSendInitialMetadataDone(bool ok) {} + virtual void OnReadDone(bool ok) {} + void OnDone() override {} + void OnCancel() override {} + + private: + friend class ServerCallbackReader; + // May be overridden by internal implementation details. This is not a public + // customization point. + virtual void InternalBindReader(ServerCallbackReader* reader) { + reader_ = reader; + } + + ServerCallbackReader* reader_; +}; + +/// \a ServerWriteReactor is the interface for a server-streaming RPC. +template +class ServerWriteReactor : public internal::ServerReactor { + public: + ~ServerWriteReactor() = default; + + /// The following operation initiations are exactly like ServerBidiReactor. + void StartSendInitialMetadata() { writer_->SendInitialMetadata(); } + void StartWrite(const Response* resp) { + StartWrite(resp, ::grpc::WriteOptions()); + } + void StartWrite(const Response* resp, ::grpc::WriteOptions options) { + writer_->Write(resp, std::move(options)); + } + void StartWriteAndFinish(const Response* resp, ::grpc::WriteOptions options, + ::grpc::Status s) { + writer_->WriteAndFinish(resp, std::move(options), std::move(s)); + } + void StartWriteLast(const Response* resp, ::grpc::WriteOptions options) { + StartWrite(resp, std::move(options.set_last_message())); + } + void Finish(::grpc::Status s) { writer_->Finish(std::move(s)); } + + /// Similar to ServerBidiReactor::OnStarted, except that this also provides + /// the request object sent by the client. + /// + /// \param[in] context The context object now associated with this RPC + /// \param[in] req The request object sent by the client + virtual void OnStarted(::grpc_impl::ServerContext* context, + const Request* req) {} + + /// The following notifications are exactly like ServerBidiReactor. + virtual void OnSendInitialMetadataDone(bool ok) {} + virtual void OnWriteDone(bool ok) {} + void OnDone() override {} + void OnCancel() override {} + + private: + friend class ServerCallbackWriter; + // May be overridden by internal implementation details. This is not a public + // customization point. + virtual void InternalBindWriter(ServerCallbackWriter* writer) { + writer_ = writer; + } + + ServerCallbackWriter* writer_; +}; + +} // namespace experimental + +namespace internal { + +template +class UnimplementedReadReactor + : public experimental::ServerReadReactor { + public: + void OnDone() override { delete this; } + void OnStarted(::grpc_impl::ServerContext*, Response*) override { + this->Finish(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")); + } +}; + +template +class UnimplementedWriteReactor + : public experimental::ServerWriteReactor { + public: + void OnDone() override { delete this; } + void OnStarted(::grpc_impl::ServerContext*, const Request*) override { + this->Finish(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")); + } +}; + +template +class UnimplementedBidiReactor + : public experimental::ServerBidiReactor { + public: + void OnDone() override { delete this; } + void OnStarted(::grpc_impl::ServerContext*) override { + this->Finish(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")); + } +}; + +template +class CallbackUnaryHandler : public grpc::internal::MethodHandler { + public: + CallbackUnaryHandler( + std::function + func) + : func_(func) {} + + void SetMessageAllocator( + ::grpc::experimental::MessageAllocator* + allocator) { + allocator_ = allocator; + } + + void RunHandler(const HandlerParameter& param) final { + // Arena allocate a controller structure (that includes request/response) + ::grpc::g_core_codegen_interface->grpc_call_ref(param.call->call()); + auto* allocator_state = static_cast< + grpc::experimental::MessageHolder*>( + param.internal_data); + auto* controller = + new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + param.call->call(), sizeof(ServerCallbackRpcControllerImpl))) + ServerCallbackRpcControllerImpl(param.server_context, param.call, + allocator_state, + std::move(param.call_requester)); + ::grpc::Status status = param.status; + if (status.ok()) { + // Call the actual function handler and expect the user to call finish + grpc::internal::CatchingCallback(func_, param.server_context, + controller->request(), + controller->response(), controller); + } else { + // if deserialization failed, we need to fail the call + controller->Finish(status); + } + } + + void* Deserialize(grpc_call* call, grpc_byte_buffer* req, + ::grpc::Status* status, void** handler_data) final { + grpc::ByteBuffer buf; + buf.set_buffer(req); + RequestType* request = nullptr; + ::grpc::experimental::MessageHolder* + allocator_state = nullptr; + if (allocator_ != nullptr) { + allocator_state = allocator_->AllocateMessages(); + } else { + allocator_state = + new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + call, sizeof(DefaultMessageHolder))) + DefaultMessageHolder(); + } + *handler_data = allocator_state; + request = allocator_state->request(); + *status = + ::grpc::SerializationTraits::Deserialize(&buf, request); + buf.Release(); + if (status->ok()) { + return request; + } + // Clean up on deserialization failure. + allocator_state->Release(); + return nullptr; + } + + private: + std::function + func_; + grpc::experimental::MessageAllocator* allocator_ = + nullptr; + + // The implementation class of ServerCallbackRpcController is a private member + // of CallbackUnaryHandler since it is never exposed anywhere, and this allows + // it to take advantage of CallbackUnaryHandler's friendships. + class ServerCallbackRpcControllerImpl + : public experimental::ServerCallbackRpcController { + public: + void Finish(::grpc::Status s) override { + finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); }, + &finish_ops_); + if (!ctx_->sent_initial_metadata_) { + finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + finish_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + } + // The response is dropped if the status is not OK. + if (s.ok()) { + finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, + finish_ops_.SendMessagePtr(response())); + } else { + finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s); + } + finish_ops_.set_core_cq_tag(&finish_tag_); + call_.PerformOps(&finish_ops_); + } + + void SendInitialMetadata(std::function f) override { + GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); + callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); + // TODO(vjpai): Consider taking f as a move-capture if we adopt C++14 + // and if performance of this operation matters + meta_tag_.Set(call_.call(), + [this, f](bool ok) { + f(ok); + MaybeDone(); + }, + &meta_ops_); + meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + meta_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + meta_ops_.set_core_cq_tag(&meta_tag_); + call_.PerformOps(&meta_ops_); + } + + // Neither SetCancelCallback nor ClearCancelCallback should affect the + // callbacks_outstanding_ count since they are paired and both must precede + // the invocation of Finish (if they are used at all) + void SetCancelCallback(std::function callback) override { + ctx_->SetCancelCallback(std::move(callback)); + } + + void ClearCancelCallback() override { ctx_->ClearCancelCallback(); } + + grpc::experimental::RpcAllocatorState* GetRpcAllocatorState() override { + return allocator_state_; + } + + private: + friend class CallbackUnaryHandler; + + ServerCallbackRpcControllerImpl( + ServerContext* ctx, ::grpc::internal::Call* call, + ::grpc::experimental::MessageHolder* + allocator_state, + std::function call_requester) + : ctx_(ctx), + call_(*call), + allocator_state_(allocator_state), + call_requester_(std::move(call_requester)) { + ctx_->BeginCompletionOp(call, [this](bool) { MaybeDone(); }, nullptr); + } + + const RequestType* request() { return allocator_state_->request(); } + ResponseType* response() { return allocator_state_->response(); } + + void MaybeDone() { + if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( + 1, std::memory_order_acq_rel) == 1)) { + grpc_call* call = call_.call(); + auto call_requester = std::move(call_requester_); + allocator_state_->Release(); + this->~ServerCallbackRpcControllerImpl(); // explicitly call destructor + ::grpc::g_core_codegen_interface->grpc_call_unref(call); + call_requester(); + } + } + + grpc::internal::CallOpSet + meta_ops_; + grpc::internal::CallbackWithSuccessTag meta_tag_; + grpc::internal::CallOpSet + finish_ops_; + grpc::internal::CallbackWithSuccessTag finish_tag_; + + ::grpc_impl::ServerContext* ctx_; + grpc::internal::Call call_; + grpc::experimental::MessageHolder* const + allocator_state_; + std::function call_requester_; + std::atomic callbacks_outstanding_{ + 2}; // reserve for Finish and CompletionOp + }; +}; + +template +class CallbackClientStreamingHandler : public grpc::internal::MethodHandler { + public: + CallbackClientStreamingHandler( + std::function< + experimental::ServerReadReactor*()> + func) + : func_(std::move(func)) {} + void RunHandler(const HandlerParameter& param) final { + // Arena allocate a reader structure (that includes response) + ::grpc::g_core_codegen_interface->grpc_call_ref(param.call->call()); + + experimental::ServerReadReactor* reactor = + param.status.ok() + ? ::grpc::internal::CatchingReactorCreator< + experimental::ServerReadReactor>( + func_) + : nullptr; + + if (reactor == nullptr) { + // if deserialization or reactor creator failed, we need to fail the call + reactor = new UnimplementedReadReactor; + } + + auto* reader = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + param.call->call(), sizeof(ServerCallbackReaderImpl))) + ServerCallbackReaderImpl(param.server_context, param.call, + std::move(param.call_requester), reactor); + + 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(); + } + + private: + std::function*()> + func_; + + class ServerCallbackReaderImpl + : public experimental::ServerCallbackReader { + public: + void Finish(::grpc::Status s) override { + finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); }, + &finish_ops_); + if (!ctx_->sent_initial_metadata_) { + finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + finish_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + } + // The response is dropped if the status is not OK. + if (s.ok()) { + finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, + finish_ops_.SendMessagePtr(&resp_)); + } else { + finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s); + } + finish_ops_.set_core_cq_tag(&finish_tag_); + call_.PerformOps(&finish_ops_); + } + + void SendInitialMetadata() override { + GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); + callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); + meta_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnSendInitialMetadataDone(ok); + MaybeDone(); + }, + &meta_ops_); + meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + meta_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + meta_ops_.set_core_cq_tag(&meta_tag_); + call_.PerformOps(&meta_ops_); + } + + void Read(RequestType* req) override { + callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); + read_ops_.RecvMessage(req); + call_.PerformOps(&read_ops_); + } + + private: + friend class CallbackClientStreamingHandler; + + ServerCallbackReaderImpl( + ::grpc_impl::ServerContext* ctx, grpc::internal::Call* call, + std::function call_requester, + experimental::ServerReadReactor* reactor) + : ctx_(ctx), + call_(*call), + call_requester_(std::move(call_requester)), + reactor_(reactor) { + ctx_->BeginCompletionOp(call, [this](bool) { MaybeDone(); }, reactor); + read_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnReadDone(ok); + MaybeDone(); + }, + &read_ops_); + read_ops_.set_core_cq_tag(&read_tag_); + } + + ~ServerCallbackReaderImpl() {} + + ResponseType* response() { return &resp_; } + + void MaybeDone() { + if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( + 1, std::memory_order_acq_rel) == 1)) { + reactor_->OnDone(); + grpc_call* call = call_.call(); + auto call_requester = std::move(call_requester_); + this->~ServerCallbackReaderImpl(); // explicitly call destructor + ::grpc::g_core_codegen_interface->grpc_call_unref(call); + call_requester(); + } + } + + grpc::internal::CallOpSet + meta_ops_; + grpc::internal::CallbackWithSuccessTag meta_tag_; + grpc::internal::CallOpSet + finish_ops_; + grpc::internal::CallbackWithSuccessTag finish_tag_; + grpc::internal::CallOpSet> + read_ops_; + grpc::internal::CallbackWithSuccessTag read_tag_; + + ::grpc_impl::ServerContext* ctx_; + grpc::internal::Call call_; + ResponseType resp_; + std::function call_requester_; + experimental::ServerReadReactor* reactor_; + std::atomic callbacks_outstanding_{ + 3}; // reserve for OnStarted, Finish, and CompletionOp + }; +}; + +template +class CallbackServerStreamingHandler : public grpc::internal::MethodHandler { + public: + CallbackServerStreamingHandler( + std::function< + experimental::ServerWriteReactor*()> + func) + : func_(std::move(func)) {} + void RunHandler(const HandlerParameter& param) final { + // Arena allocate a writer structure + ::grpc::g_core_codegen_interface->grpc_call_ref(param.call->call()); + + experimental::ServerWriteReactor* reactor = + param.status.ok() + ? ::grpc::internal::CatchingReactorCreator< + experimental::ServerWriteReactor>( + func_) + : nullptr; + + if (reactor == nullptr) { + // if deserialization or reactor creator failed, we need to fail the call + reactor = new UnimplementedWriteReactor; + } + + auto* writer = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + param.call->call(), sizeof(ServerCallbackWriterImpl))) + ServerCallbackWriterImpl(param.server_context, param.call, + static_cast(param.request), + 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, + ::grpc::Status* status, void** handler_data) final { + ::grpc::ByteBuffer buf; + buf.set_buffer(req); + auto* request = + new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + call, sizeof(RequestType))) RequestType(); + *status = + ::grpc::SerializationTraits::Deserialize(&buf, request); + buf.Release(); + if (status->ok()) { + return request; + } + request->~RequestType(); + return nullptr; + } + + private: + std::function*()> + func_; + + class ServerCallbackWriterImpl + : public experimental::ServerCallbackWriter { + public: + void Finish(::grpc::Status s) override { + finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); }, + &finish_ops_); + finish_ops_.set_core_cq_tag(&finish_tag_); + + if (!ctx_->sent_initial_metadata_) { + finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + finish_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + } + finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s); + call_.PerformOps(&finish_ops_); + } + + void SendInitialMetadata() override { + GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); + callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); + meta_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnSendInitialMetadataDone(ok); + MaybeDone(); + }, + &meta_ops_); + meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + meta_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + meta_ops_.set_core_cq_tag(&meta_tag_); + call_.PerformOps(&meta_ops_); + } + + void Write(const ResponseType* resp, + ::grpc::WriteOptions options) override { + callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); + if (options.is_last_message()) { + options.set_buffer_hint(); + } + if (!ctx_->sent_initial_metadata_) { + write_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + write_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + } + // TODO(vjpai): don't assert + GPR_CODEGEN_ASSERT(write_ops_.SendMessagePtr(resp, options).ok()); + call_.PerformOps(&write_ops_); + } + + void WriteAndFinish(const ResponseType* resp, ::grpc::WriteOptions options, + ::grpc::Status s) override { + // This combines the write into the finish callback + // Don't send any message if the status is bad + if (s.ok()) { + // TODO(vjpai): don't assert + GPR_CODEGEN_ASSERT(finish_ops_.SendMessagePtr(resp, options).ok()); + } + Finish(std::move(s)); + } + + private: + friend class CallbackServerStreamingHandler; + + ServerCallbackWriterImpl( + ::grpc_impl::ServerContext* ctx, grpc::internal::Call* call, + const RequestType* req, std::function call_requester, + experimental::ServerWriteReactor* reactor) + : ctx_(ctx), + call_(*call), + req_(req), + call_requester_(std::move(call_requester)), + reactor_(reactor) { + ctx_->BeginCompletionOp(call, [this](bool) { MaybeDone(); }, reactor); + write_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnWriteDone(ok); + MaybeDone(); + }, + &write_ops_); + write_ops_.set_core_cq_tag(&write_tag_); + } + ~ServerCallbackWriterImpl() { req_->~RequestType(); } + + const RequestType* request() { return req_; } + + void MaybeDone() { + if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( + 1, std::memory_order_acq_rel) == 1)) { + reactor_->OnDone(); + grpc_call* call = call_.call(); + auto call_requester = std::move(call_requester_); + this->~ServerCallbackWriterImpl(); // explicitly call destructor + ::grpc::g_core_codegen_interface->grpc_call_unref(call); + call_requester(); + } + } + + grpc::internal::CallOpSet + meta_ops_; + grpc::internal::CallbackWithSuccessTag meta_tag_; + grpc::internal::CallOpSet + finish_ops_; + grpc::internal::CallbackWithSuccessTag finish_tag_; + grpc::internal::CallOpSet + write_ops_; + grpc::internal::CallbackWithSuccessTag write_tag_; + + ::grpc_impl::ServerContext* ctx_; + grpc::internal::Call call_; + const RequestType* req_; + std::function call_requester_; + experimental::ServerWriteReactor* reactor_; + std::atomic callbacks_outstanding_{ + 3}; // reserve for OnStarted, Finish, and CompletionOp + }; +}; + +template +class CallbackBidiHandler : public grpc::internal::MethodHandler { + public: + CallbackBidiHandler( + std::function< + experimental::ServerBidiReactor*()> + func) + : func_(std::move(func)) {} + void RunHandler(const HandlerParameter& param) final { + ::grpc::g_core_codegen_interface->grpc_call_ref(param.call->call()); + + experimental::ServerBidiReactor* reactor = + param.status.ok() + ? ::grpc::internal::CatchingReactorCreator< + experimental::ServerBidiReactor>( + func_) + : nullptr; + + if (reactor == nullptr) { + // if deserialization or reactor creator failed, we need to fail the call + reactor = new UnimplementedBidiReactor; + } + + auto* stream = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc( + param.call->call(), sizeof(ServerCallbackReaderWriterImpl))) + ServerCallbackReaderWriterImpl(param.server_context, param.call, + std::move(param.call_requester), + reactor); + + stream->BindReactor(reactor); + reactor->OnStarted(param.server_context); + // The earliest that OnCancel can be called is after OnStarted is done. + reactor->MaybeCallOnCancel(); + stream->MaybeDone(); + } + + private: + std::function*()> + func_; + + class ServerCallbackReaderWriterImpl + : public experimental::ServerCallbackReaderWriter { + public: + void Finish(::grpc::Status s) override { + finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); }, + &finish_ops_); + finish_ops_.set_core_cq_tag(&finish_tag_); + + if (!ctx_->sent_initial_metadata_) { + finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + finish_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + } + finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s); + call_.PerformOps(&finish_ops_); + } + + void SendInitialMetadata() override { + GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); + callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); + meta_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnSendInitialMetadataDone(ok); + MaybeDone(); + }, + &meta_ops_); + meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + meta_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + meta_ops_.set_core_cq_tag(&meta_tag_); + call_.PerformOps(&meta_ops_); + } + + void Write(const ResponseType* resp, + ::grpc::WriteOptions options) override { + callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); + if (options.is_last_message()) { + options.set_buffer_hint(); + } + if (!ctx_->sent_initial_metadata_) { + write_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + write_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + } + // TODO(vjpai): don't assert + GPR_CODEGEN_ASSERT(write_ops_.SendMessagePtr(resp, options).ok()); + call_.PerformOps(&write_ops_); + } + + void WriteAndFinish(const ResponseType* resp, ::grpc::WriteOptions options, + ::grpc::Status s) override { + // Don't send any message if the status is bad + if (s.ok()) { + // TODO(vjpai): don't assert + GPR_CODEGEN_ASSERT(finish_ops_.SendMessagePtr(resp, options).ok()); + } + Finish(std::move(s)); + } + + void Read(RequestType* req) override { + callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed); + read_ops_.RecvMessage(req); + call_.PerformOps(&read_ops_); + } + + private: + friend class CallbackBidiHandler; + + ServerCallbackReaderWriterImpl( + ::grpc_impl::ServerContext* ctx, grpc::internal::Call* call, + std::function call_requester, + experimental::ServerBidiReactor* reactor) + : ctx_(ctx), + call_(*call), + call_requester_(std::move(call_requester)), + reactor_(reactor) { + ctx_->BeginCompletionOp(call, [this](bool) { MaybeDone(); }, reactor); + write_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnWriteDone(ok); + MaybeDone(); + }, + &write_ops_); + write_ops_.set_core_cq_tag(&write_tag_); + read_tag_.Set(call_.call(), + [this](bool ok) { + reactor_->OnReadDone(ok); + MaybeDone(); + }, + &read_ops_); + read_ops_.set_core_cq_tag(&read_tag_); + } + ~ServerCallbackReaderWriterImpl() {} + + void MaybeDone() { + if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub( + 1, std::memory_order_acq_rel) == 1)) { + reactor_->OnDone(); + grpc_call* call = call_.call(); + auto call_requester = std::move(call_requester_); + this->~ServerCallbackReaderWriterImpl(); // explicitly call destructor + ::grpc::g_core_codegen_interface->grpc_call_unref(call); + call_requester(); + } + } + + grpc::internal::CallOpSet + meta_ops_; + grpc::internal::CallbackWithSuccessTag meta_tag_; + grpc::internal::CallOpSet + finish_ops_; + grpc::internal::CallbackWithSuccessTag finish_tag_; + grpc::internal::CallOpSet + write_ops_; + grpc::internal::CallbackWithSuccessTag write_tag_; + grpc::internal::CallOpSet> + read_ops_; + grpc::internal::CallbackWithSuccessTag read_tag_; + + ::grpc_impl::ServerContext* ctx_; + grpc::internal::Call call_; + std::function call_requester_; + experimental::ServerBidiReactor* reactor_; + std::atomic callbacks_outstanding_{ + 3}; // reserve for OnStarted, Finish, and CompletionOp + }; +}; + +} // namespace internal + +} // namespace grpc_impl + +#endif // GRPCPP_IMPL_CODEGEN_SERVER_CALLBACK_IMPL_H diff --git a/include/grpcpp/impl/codegen/server_context_impl.h b/include/grpcpp/impl/codegen/server_context_impl.h index 9497735eacc..72137f153b1 100644 --- a/include/grpcpp/impl/codegen/server_context_impl.h +++ b/include/grpcpp/impl/codegen/server_context_impl.h @@ -44,10 +44,6 @@ namespace grpc_impl { class ClientContext; class CompletionQueue; class Server; -} // namespace grpc_impl -namespace grpc { -class GenericServerContext; -class ServerInterface; template class ServerAsyncReader; template @@ -62,14 +58,6 @@ template class ServerWriter; namespace internal { -template -class ServerReaderWriterBody; -template -class RpcMethodHandler; -template -class ClientStreamingHandler; -template -class ServerStreamingHandler; template class BidiStreamingHandler; template @@ -80,12 +68,28 @@ template class CallbackServerStreamingHandler; template class CallbackBidiHandler; +template +class ServerReaderWriterBody; +class ServerReactor; +} // namespace internal + +} // namespace grpc_impl +namespace grpc { +class GenericServerContext; +class ServerInterface; + +namespace internal { +template +class ClientStreamingHandler; +template +class ServerStreamingHandler; +template +class RpcMethodHandler; template class TemplatedBidiStreamingHandler; template class ErrorMethodHandler; class Call; -class ServerReactor; } // namespace internal class ServerInterface; @@ -275,19 +279,19 @@ class ServerContext { friend class ::grpc::ServerInterface; friend class ::grpc_impl::Server; template - friend class ::grpc::ServerAsyncReader; + friend class ::grpc_impl::ServerAsyncReader; template - friend class ::grpc::ServerAsyncWriter; + friend class ::grpc_impl::ServerAsyncWriter; template - friend class ::grpc::ServerAsyncResponseWriter; + friend class ::grpc_impl::ServerAsyncResponseWriter; template - friend class ::grpc::ServerAsyncReaderWriter; + friend class ::grpc_impl::ServerAsyncReaderWriter; template - friend class ::grpc::ServerReader; + friend class ::grpc_impl::ServerReader; template - friend class ::grpc::ServerWriter; + friend class ::grpc_impl::ServerWriter; template - friend class ::grpc::internal::ServerReaderWriterBody; + friend class ::grpc_impl::internal::ServerReaderWriterBody; template friend class ::grpc::internal::RpcMethodHandler; template @@ -297,13 +301,13 @@ class ServerContext { template friend class ::grpc::internal::TemplatedBidiStreamingHandler; template - friend class ::grpc::internal::CallbackUnaryHandler; + friend class ::grpc_impl::internal::CallbackUnaryHandler; template - friend class ::grpc::internal::CallbackClientStreamingHandler; + friend class ::grpc_impl::internal::CallbackClientStreamingHandler; template - friend class ::grpc::internal::CallbackServerStreamingHandler; + friend class ::grpc_impl::internal::CallbackServerStreamingHandler; template - friend class ::grpc::internal::CallbackBidiHandler; + friend class ::grpc_impl::internal::CallbackBidiHandler; template <::grpc::StatusCode code> friend class ::grpc::internal::ErrorMethodHandler; friend class ::grpc_impl::ClientContext; @@ -317,7 +321,7 @@ class ServerContext { void BeginCompletionOp(::grpc::internal::Call* call, std::function callback, - ::grpc::internal::ServerReactor* reactor); + ::grpc_impl::internal::ServerReactor* reactor); /// Return the tag queued by BeginCompletionOp() ::grpc::internal::CompletionQueueTag* GetCompletionOpTag(); diff --git a/include/grpcpp/impl/codegen/service_type.h b/include/grpcpp/impl/codegen/service_type.h index 4109ee1b504..f13dfb99fa0 100644 --- a/include/grpcpp/impl/codegen/service_type.h +++ b/include/grpcpp/impl/codegen/service_type.h @@ -149,8 +149,9 @@ class Service { void RequestAsyncUnary(int index, ::grpc_impl::ServerContext* context, Message* request, internal::ServerAsyncStreamingInterface* stream, - CompletionQueue* call_cq, - ServerCompletionQueue* notification_cq, void* tag) { + ::grpc_impl::CompletionQueue* call_cq, + ::grpc_impl::ServerCompletionQueue* notification_cq, + void* tag) { // Typecast the index to size_t for indexing into a vector // while preserving the API that existed before a compiler // warning was first seen (grpc/grpc#11664) @@ -160,8 +161,9 @@ class Service { } void RequestAsyncClientStreaming( int index, ::grpc_impl::ServerContext* context, - internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, - ServerCompletionQueue* notification_cq, void* tag) { + internal::ServerAsyncStreamingInterface* stream, + ::grpc_impl::CompletionQueue* call_cq, + ::grpc_impl::ServerCompletionQueue* notification_cq, void* tag) { size_t idx = static_cast(index); server_->RequestAsyncCall(methods_[idx].get(), context, stream, call_cq, notification_cq, tag); @@ -169,16 +171,18 @@ class Service { template void RequestAsyncServerStreaming( int index, ::grpc_impl::ServerContext* context, Message* request, - internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, - ServerCompletionQueue* notification_cq, void* tag) { + internal::ServerAsyncStreamingInterface* stream, + ::grpc_impl::CompletionQueue* call_cq, + ::grpc_impl::ServerCompletionQueue* notification_cq, void* tag) { size_t idx = static_cast(index); server_->RequestAsyncCall(methods_[idx].get(), context, stream, call_cq, notification_cq, tag, request); } void RequestAsyncBidiStreaming( int index, ::grpc_impl::ServerContext* context, - internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, - ServerCompletionQueue* notification_cq, void* tag) { + internal::ServerAsyncStreamingInterface* stream, + ::grpc_impl::CompletionQueue* call_cq, + ::grpc_impl::ServerCompletionQueue* notification_cq, void* tag) { size_t idx = static_cast(index); server_->RequestAsyncCall(methods_[idx].get(), context, stream, call_cq, notification_cq, tag); diff --git a/include/grpcpp/impl/codegen/sync_stream.h b/include/grpcpp/impl/codegen/sync_stream.h index 9d030a13a71..cd447d7c5a5 100644 --- a/include/grpcpp/impl/codegen/sync_stream.h +++ b/include/grpcpp/impl/codegen/sync_stream.h @@ -19,918 +19,42 @@ #ifndef GRPCPP_IMPL_CODEGEN_SYNC_STREAM_H #define GRPCPP_IMPL_CODEGEN_SYNC_STREAM_H -#include -#include -#include -#include -#include -#include -#include -#include +#include namespace grpc { - -namespace internal { -/// Common interface for all synchronous client side streaming. -class ClientStreamingInterface { - public: - virtual ~ClientStreamingInterface() {} - - /// Block waiting until the stream finishes and a final status of the call is - /// available. - /// - /// It is appropriate to call this method when both: - /// * the calling code (client-side) has no more message to send - /// (this can be declared implicitly by calling this method, or - /// explicitly through an earlier call to WritesDone method of the - /// class in use, e.g. \a ClientWriterInterface::WritesDone or - /// \a ClientReaderWriterInterface::WritesDone). - /// * there are no more messages to be received from the server (which can - /// be known implicitly, or explicitly from an earlier call to \a - /// ReaderInterface::Read that returned "false"). - /// - /// This function will return either: - /// - when all incoming messages have been read and the server has - /// returned status. - /// - when the server has returned a non-OK status. - /// - OR when the call failed for some reason and the library generated a - /// status. - /// - /// Return values: - /// - \a Status contains the status code, message and details for the call - /// - the \a ClientContext associated with this call is updated with - /// possible trailing metadata sent from the server. - virtual Status Finish() = 0; -}; - -/// Common interface for all synchronous server side streaming. -class ServerStreamingInterface { - public: - virtual ~ServerStreamingInterface() {} - - /// Block to send initial metadata to client. - /// This call is optional, but if it is used, it cannot be used concurrently - /// with or after the \a Finish method. - /// - /// The initial metadata that will be sent to the client will be - /// taken from the \a ServerContext associated with the call. - virtual void SendInitialMetadata() = 0; -}; - -/// An interface that yields a sequence of messages of type \a R. template -class ReaderInterface { - public: - virtual ~ReaderInterface() {} - - /// Get an upper bound on the next message size available for reading on this - /// stream. - virtual bool NextMessageSize(uint32_t* sz) = 0; - - /// Block to read a message and parse to \a msg. Returns \a true on success. - /// This is thread-safe with respect to \a Write or \WritesDone methods on - /// the same stream. It should not be called concurrently with another \a - /// Read on the same stream as the order of delivery will not be defined. - /// - /// \param[out] msg The read message. - /// - /// \return \a false when there will be no more incoming messages, either - /// because the other side has called \a WritesDone() or the stream has failed - /// (or been cancelled). - virtual bool Read(R* msg) = 0; -}; - -/// An interface that can be fed a sequence of messages of type \a W. -template -class WriterInterface { - public: - virtual ~WriterInterface() {} - - /// Block to write \a msg to the stream with WriteOptions \a options. - /// This is thread-safe with respect to \a ReaderInterface::Read - /// - /// \param msg The message to be written to the stream. - /// \param options The WriteOptions affecting the write operation. - /// - /// \return \a true on success, \a false when the stream has been closed. - virtual bool Write(const W& msg, WriteOptions options) = 0; - - /// Block to write \a msg to the stream with default write options. - /// This is thread-safe with respect to \a ReaderInterface::Read - /// - /// \param msg The message to be written to the stream. - /// - /// \return \a true on success, \a false when the stream has been closed. - inline bool Write(const W& msg) { return Write(msg, WriteOptions()); } - - /// Write \a msg and coalesce it with the writing of trailing metadata, using - /// WriteOptions \a options. - /// - /// For client, WriteLast is equivalent of performing Write and WritesDone in - /// a single step. \a msg and trailing metadata are coalesced and sent on wire - /// by calling this function. For server, WriteLast buffers the \a msg. - /// The writing of \a msg is held until the service handler returns, - /// where \a msg and trailing metadata are coalesced and sent on wire. - /// Note that WriteLast can only buffer \a msg up to the flow control window - /// size. If \a msg size is larger than the window size, it will be sent on - /// wire without buffering. - /// - /// \param[in] msg The message to be written to the stream. - /// \param[in] options The WriteOptions to be used to write this message. - void WriteLast(const W& msg, WriteOptions options) { - Write(msg, options.set_last_message()); - } -}; - -} // namespace internal +using ClientReaderInterface = ::grpc_impl::ClientReaderInterface; -/// Client-side interface for streaming reads of message of type \a R. template -class ClientReaderInterface : public internal::ClientStreamingInterface, - public internal::ReaderInterface { - public: - /// Block to wait for initial metadata from server. The received metadata - /// can only be accessed after this call returns. Should only be called before - /// the first read. Calling this method is optional, and if it is not called - /// the metadata will be available in ClientContext after the first read. - virtual void WaitForInitialMetadata() = 0; -}; - -namespace internal { -template -class ClientReaderFactory { - public: - template - static ClientReader* Create(ChannelInterface* channel, - const ::grpc::internal::RpcMethod& method, - ::grpc_impl::ClientContext* context, - const W& request) { - return new ClientReader(channel, method, context, request); - } -}; -} // namespace internal - -/// Synchronous (blocking) client-side API for doing server-streaming RPCs, -/// where the stream of messages coming from the server has messages -/// of type \a R. -template -class ClientReader final : public ClientReaderInterface { - public: - /// See the \a ClientStreamingInterface.WaitForInitialMetadata method for - /// semantics. - /// - // Side effect: - /// Once complete, the initial metadata read from - /// the server will be accessible through the \a ClientContext used to - /// construct this object. - void WaitForInitialMetadata() override { - GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); - - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> - ops; - ops.RecvInitialMetadata(context_); - call_.PerformOps(&ops); - cq_.Pluck(&ops); /// status ignored - } - - bool NextMessageSize(uint32_t* sz) override { - *sz = call_.max_receive_message_size(); - return true; - } - - /// See the \a ReaderInterface.Read method for semantics. - /// Side effect: - /// This also receives initial metadata from the server, if not - /// already received (if initial metadata is received, it can be then - /// accessed through the \a ClientContext associated with this call). - bool Read(R* msg) override { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpRecvMessage> - ops; - if (!context_->initial_metadata_received_) { - ops.RecvInitialMetadata(context_); - } - ops.RecvMessage(msg); - call_.PerformOps(&ops); - return cq_.Pluck(&ops) && ops.got_message; - } - - /// See the \a ClientStreamingInterface.Finish method for semantics. - /// - /// Side effect: - /// The \a ClientContext associated with this call is updated with - /// possible metadata received from the server. - Status Finish() override { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpClientRecvStatus> ops; - Status status; - ops.ClientRecvStatus(context_, &status); - call_.PerformOps(&ops); - GPR_CODEGEN_ASSERT(cq_.Pluck(&ops)); - return status; - } - - private: - friend class internal::ClientReaderFactory; - ::grpc_impl::ClientContext* context_; - ::grpc_impl::CompletionQueue cq_; - ::grpc::internal::Call call_; - - /// Block to create a stream and write the initial metadata and \a request - /// out. Note that \a context will be used to fill in custom initial - /// metadata used to send to the server when starting the call. - template - ClientReader(::grpc::ChannelInterface* channel, - const ::grpc::internal::RpcMethod& method, - ::grpc_impl::ClientContext* context, const W& request) - : context_(context), - cq_(grpc_completion_queue_attributes{ - GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING, - nullptr}), // Pluckable cq - call_(channel->CreateCall(method, context, &cq_)) { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpClientSendClose> - ops; - ops.SendInitialMetadata(&context->send_initial_metadata_, - context->initial_metadata_flags()); - // TODO(ctiller): don't assert - GPR_CODEGEN_ASSERT(ops.SendMessagePtr(&request).ok()); - ops.ClientSendClose(); - call_.PerformOps(&ops); - cq_.Pluck(&ops); - } -}; - -/// Client-side interface for streaming writes of message type \a W. +using ClientReader = ::grpc_impl::ClientReader; template -class ClientWriterInterface : public internal::ClientStreamingInterface, - public internal::WriterInterface { - public: - /// Half close writing from the client. (signal that the stream of messages - /// coming from the client is complete). - /// Blocks until currently-pending writes are completed. - /// Thread safe with respect to \a ReaderInterface::Read operations only - /// - /// \return Whether the writes were successful. - virtual bool WritesDone() = 0; -}; - -namespace internal { +using ClientWriterInterface = ::grpc_impl::ClientWriterInterface; template -class ClientWriterFactory { - public: - template - static ClientWriter* Create(::grpc::ChannelInterface* channel, - const ::grpc::internal::RpcMethod& method, - ::grpc_impl::ClientContext* context, - R* response) { - return new ClientWriter(channel, method, context, response); - } -}; -} // namespace internal - -/// Synchronous (blocking) client-side API for doing client-streaming RPCs, -/// where the outgoing message stream coming from the client has messages of -/// type \a W. -template -class ClientWriter : public ClientWriterInterface { - public: - /// See the \a ClientStreamingInterface.WaitForInitialMetadata method for - /// semantics. - /// - // Side effect: - /// Once complete, the initial metadata read from the server will be - /// accessible through the \a ClientContext used to construct this object. - void WaitForInitialMetadata() { - GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); - - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> - ops; - ops.RecvInitialMetadata(context_); - call_.PerformOps(&ops); - cq_.Pluck(&ops); // status ignored - } - - /// See the WriterInterface.Write(const W& msg, WriteOptions options) method - /// for semantics. - /// - /// Side effect: - /// Also sends initial metadata if not already sent (using the - /// \a ClientContext associated with this call). - using ::grpc::internal::WriterInterface::Write; - bool Write(const W& msg, WriteOptions options) override { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpClientSendClose> - ops; - - if (options.is_last_message()) { - options.set_buffer_hint(); - ops.ClientSendClose(); - } - if (context_->initial_metadata_corked_) { - ops.SendInitialMetadata(&context_->send_initial_metadata_, - context_->initial_metadata_flags()); - context_->set_initial_metadata_corked(false); - } - if (!ops.SendMessagePtr(&msg, options).ok()) { - return false; - } - - call_.PerformOps(&ops); - return cq_.Pluck(&ops); - } - - bool WritesDone() override { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpClientSendClose> ops; - ops.ClientSendClose(); - call_.PerformOps(&ops); - return cq_.Pluck(&ops); - } - - /// See the ClientStreamingInterface.Finish method for semantics. - /// Side effects: - /// - Also receives initial metadata if not already received. - /// - Attempts to fill in the \a response parameter passed - /// to the constructor of this instance with the response - /// message from the server. - Status Finish() override { - Status status; - if (!context_->initial_metadata_received_) { - finish_ops_.RecvInitialMetadata(context_); - } - finish_ops_.ClientRecvStatus(context_, &status); - call_.PerformOps(&finish_ops_); - GPR_CODEGEN_ASSERT(cq_.Pluck(&finish_ops_)); - return status; - } - - private: - friend class internal::ClientWriterFactory; - - /// Block to create a stream (i.e. send request headers and other initial - /// metadata to the server). Note that \a context will be used to fill - /// in custom initial metadata. \a response will be filled in with the - /// single expected response message from the server upon a successful - /// call to the \a Finish method of this instance. - template - ClientWriter(ChannelInterface* channel, - const ::grpc::internal::RpcMethod& method, - ::grpc_impl::ClientContext* context, R* response) - : context_(context), - cq_(grpc_completion_queue_attributes{ - GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING, - nullptr}), // Pluckable cq - call_(channel->CreateCall(method, context, &cq_)) { - finish_ops_.RecvMessage(response); - finish_ops_.AllowNoMessage(); - - if (!context_->initial_metadata_corked_) { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> - ops; - ops.SendInitialMetadata(&context->send_initial_metadata_, - context->initial_metadata_flags()); - call_.PerformOps(&ops); - cq_.Pluck(&ops); - } - } - - ::grpc_impl::ClientContext* context_; - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpGenericRecvMessage, - ::grpc::internal::CallOpClientRecvStatus> - finish_ops_; - ::grpc_impl::CompletionQueue cq_; - ::grpc::internal::Call call_; -}; - -/// Client-side interface for bi-directional streaming with -/// client-to-server stream messages of type \a W and -/// server-to-client stream messages of type \a R. -template -class ClientReaderWriterInterface : public internal::ClientStreamingInterface, - public internal::WriterInterface, - public internal::ReaderInterface { - public: - /// Block to wait for initial metadata from server. The received metadata - /// can only be accessed after this call returns. Should only be called before - /// the first read. Calling this method is optional, and if it is not called - /// the metadata will be available in ClientContext after the first read. - virtual void WaitForInitialMetadata() = 0; - - /// Half close writing from the client. (signal that the stream of messages - /// coming from the clinet is complete). - /// Blocks until currently-pending writes are completed. - /// Thread-safe with respect to \a ReaderInterface::Read - /// - /// \return Whether the writes were successful. - virtual bool WritesDone() = 0; -}; - -namespace internal { +using ClientWriter = ::grpc_impl::ClientWriter; template -class ClientReaderWriterFactory { - public: - static ClientReaderWriter* Create( - ::grpc::ChannelInterface* channel, - const ::grpc::internal::RpcMethod& method, - ::grpc_impl::ClientContext* context) { - return new ClientReaderWriter(channel, method, context); - } -}; -} // namespace internal - -/// Synchronous (blocking) client-side API for bi-directional streaming RPCs, -/// where the outgoing message stream coming from the client has messages of -/// type \a W, and the incoming messages stream coming from the server has -/// messages of type \a R. +using ClientReaderWriterInterface = + ::grpc_impl::ClientReaderWriterInterface; template -class ClientReaderWriter final : public ClientReaderWriterInterface { - public: - /// Block waiting to read initial metadata from the server. - /// This call is optional, but if it is used, it cannot be used concurrently - /// with or after the \a Finish method. - /// - /// Once complete, the initial metadata read from the server will be - /// accessible through the \a ClientContext used to construct this object. - void WaitForInitialMetadata() override { - GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); - - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> - ops; - ops.RecvInitialMetadata(context_); - call_.PerformOps(&ops); - cq_.Pluck(&ops); // status ignored - } - - bool NextMessageSize(uint32_t* sz) override { - *sz = call_.max_receive_message_size(); - return true; - } - - /// See the \a ReaderInterface.Read method for semantics. - /// Side effect: - /// Also receives initial metadata if not already received (updates the \a - /// ClientContext associated with this call in that case). - bool Read(R* msg) override { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpRecvMessage> - ops; - if (!context_->initial_metadata_received_) { - ops.RecvInitialMetadata(context_); - } - ops.RecvMessage(msg); - call_.PerformOps(&ops); - return cq_.Pluck(&ops) && ops.got_message; - } - - /// See the \a WriterInterface.Write method for semantics. - /// - /// Side effect: - /// Also sends initial metadata if not already sent (using the - /// \a ClientContext associated with this call to fill in values). - using ::grpc::internal::WriterInterface::Write; - bool Write(const W& msg, WriteOptions options) override { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, - ::grpc::internal::CallOpSendMessage, - ::grpc::internal::CallOpClientSendClose> - ops; - - if (options.is_last_message()) { - options.set_buffer_hint(); - ops.ClientSendClose(); - } - if (context_->initial_metadata_corked_) { - ops.SendInitialMetadata(&context_->send_initial_metadata_, - context_->initial_metadata_flags()); - context_->set_initial_metadata_corked(false); - } - if (!ops.SendMessagePtr(&msg, options).ok()) { - return false; - } - - call_.PerformOps(&ops); - return cq_.Pluck(&ops); - } - - bool WritesDone() override { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpClientSendClose> ops; - ops.ClientSendClose(); - call_.PerformOps(&ops); - return cq_.Pluck(&ops); - } - - /// See the ClientStreamingInterface.Finish method for semantics. - /// - /// Side effect: - /// - the \a ClientContext associated with this call is updated with - /// possible trailing metadata sent from the server. - Status Finish() override { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, - ::grpc::internal::CallOpClientRecvStatus> - ops; - if (!context_->initial_metadata_received_) { - ops.RecvInitialMetadata(context_); - } - Status status; - ops.ClientRecvStatus(context_, &status); - call_.PerformOps(&ops); - GPR_CODEGEN_ASSERT(cq_.Pluck(&ops)); - return status; - } - - private: - friend class internal::ClientReaderWriterFactory; - - ::grpc_impl::ClientContext* context_; - ::grpc_impl::CompletionQueue cq_; - ::grpc::internal::Call call_; - - /// Block to create a stream and write the initial metadata and \a request - /// out. Note that \a context will be used to fill in custom initial metadata - /// used to send to the server when starting the call. - ClientReaderWriter(::grpc::ChannelInterface* channel, - const ::grpc::internal::RpcMethod& method, - ::grpc_impl::ClientContext* context) - : context_(context), - cq_(grpc_completion_queue_attributes{ - GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING, - nullptr}), // Pluckable cq - call_(channel->CreateCall(method, context, &cq_)) { - if (!context_->initial_metadata_corked_) { - ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> - ops; - ops.SendInitialMetadata(&context->send_initial_metadata_, - context->initial_metadata_flags()); - call_.PerformOps(&ops); - cq_.Pluck(&ops); - } - } -}; - -/// Server-side interface for streaming reads of message of type \a R. +using ClientReaderWriter = ::grpc_impl::ClientReaderWriter; template -class ServerReaderInterface : public internal::ServerStreamingInterface, - public internal::ReaderInterface {}; - -/// Synchronous (blocking) server-side API for doing client-streaming RPCs, -/// where the incoming message stream coming from the client has messages of -/// type \a R. +using ServerReaderInterface = ::grpc_impl::ServerReaderInterface; template -class ServerReader final : public ServerReaderInterface { - public: - /// See the \a ServerStreamingInterface.SendInitialMetadata method - /// for semantics. Note that initial metadata will be affected by the - /// \a ServerContext associated with this call. - void SendInitialMetadata() override { - GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); - - internal::CallOpSet ops; - ops.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - ops.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - call_->PerformOps(&ops); - call_->cq()->Pluck(&ops); - } - - bool NextMessageSize(uint32_t* sz) override { - *sz = call_->max_receive_message_size(); - return true; - } - - bool Read(R* msg) override { - internal::CallOpSet> ops; - ops.RecvMessage(msg); - call_->PerformOps(&ops); - return call_->cq()->Pluck(&ops) && ops.got_message; - } - - private: - internal::Call* const call_; - ::grpc_impl::ServerContext* const ctx_; - - template - friend class internal::ClientStreamingHandler; - - ServerReader(internal::Call* call, ::grpc_impl::ServerContext* ctx) - : call_(call), ctx_(ctx) {} -}; - -/// Server-side interface for streaming writes of message of type \a W. +using ServerReader = ::grpc_impl::ServerReader; template -class ServerWriterInterface : public internal::ServerStreamingInterface, - public internal::WriterInterface {}; - -/// Synchronous (blocking) server-side API for doing for doing a -/// server-streaming RPCs, where the outgoing message stream coming from the -/// server has messages of type \a W. +using ServerWriterInterface = ::grpc_impl::ServerWriterInterface; template -class ServerWriter final : public ServerWriterInterface { - public: - /// See the \a ServerStreamingInterface.SendInitialMetadata method - /// for semantics. - /// Note that initial metadata will be affected by the - /// \a ServerContext associated with this call. - void SendInitialMetadata() override { - GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); - - internal::CallOpSet ops; - ops.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - ops.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - call_->PerformOps(&ops); - call_->cq()->Pluck(&ops); - } - - /// See the \a WriterInterface.Write method for semantics. - /// - /// Side effect: - /// Also sends initial metadata if not already sent (using the - /// \a ClientContext associated with this call to fill in values). - using internal::WriterInterface::Write; - bool Write(const W& msg, WriteOptions options) override { - if (options.is_last_message()) { - options.set_buffer_hint(); - } - - if (!ctx_->pending_ops_.SendMessagePtr(&msg, options).ok()) { - return false; - } - if (!ctx_->sent_initial_metadata_) { - ctx_->pending_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - ctx_->pending_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - } - call_->PerformOps(&ctx_->pending_ops_); - // if this is the last message we defer the pluck until AFTER we start - // the trailing md op. This prevents hangs. See - // https://github.com/grpc/grpc/issues/11546 - if (options.is_last_message()) { - ctx_->has_pending_ops_ = true; - return true; - } - ctx_->has_pending_ops_ = false; - return call_->cq()->Pluck(&ctx_->pending_ops_); - } - - private: - internal::Call* const call_; - ::grpc_impl::ServerContext* const ctx_; - - template - friend class internal::ServerStreamingHandler; - - ServerWriter(internal::Call* call, ::grpc_impl::ServerContext* ctx) - : call_(call), ctx_(ctx) {} -}; - -/// Server-side interface for bi-directional streaming. +using ServerWriter = ::grpc_impl::ServerWriter; template -class ServerReaderWriterInterface : public internal::ServerStreamingInterface, - public internal::WriterInterface, - public internal::ReaderInterface {}; - -/// Actual implementation of bi-directional streaming -namespace internal { -template -class ServerReaderWriterBody final { - public: - ServerReaderWriterBody(Call* call, ::grpc_impl::ServerContext* ctx) - : call_(call), ctx_(ctx) {} - - void SendInitialMetadata() { - GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); - - CallOpSet ops; - ops.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - ops.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - call_->PerformOps(&ops); - call_->cq()->Pluck(&ops); - } - - bool NextMessageSize(uint32_t* sz) { - *sz = call_->max_receive_message_size(); - return true; - } - - bool Read(R* msg) { - CallOpSet> ops; - ops.RecvMessage(msg); - call_->PerformOps(&ops); - return call_->cq()->Pluck(&ops) && ops.got_message; - } - - bool Write(const W& msg, WriteOptions options) { - if (options.is_last_message()) { - options.set_buffer_hint(); - } - if (!ctx_->pending_ops_.SendMessagePtr(&msg, options).ok()) { - return false; - } - if (!ctx_->sent_initial_metadata_) { - ctx_->pending_ops_.SendInitialMetadata(&ctx_->initial_metadata_, - ctx_->initial_metadata_flags()); - if (ctx_->compression_level_set()) { - ctx_->pending_ops_.set_compression_level(ctx_->compression_level()); - } - ctx_->sent_initial_metadata_ = true; - } - call_->PerformOps(&ctx_->pending_ops_); - // if this is the last message we defer the pluck until AFTER we start - // the trailing md op. This prevents hangs. See - // https://github.com/grpc/grpc/issues/11546 - if (options.is_last_message()) { - ctx_->has_pending_ops_ = true; - return true; - } - ctx_->has_pending_ops_ = false; - return call_->cq()->Pluck(&ctx_->pending_ops_); - } - - private: - Call* const call_; - ::grpc_impl::ServerContext* const ctx_; -}; - -} // namespace internal - -/// Synchronous (blocking) server-side API for a bidirectional -/// streaming call, where the incoming message stream coming from the client has -/// messages of type \a R, and the outgoing message streaming coming from -/// the server has messages of type \a W. +using ServerReaderWriterInterface = + ::grpc_impl::ServerReaderWriterInterface; template -class ServerReaderWriter final : public ServerReaderWriterInterface { - public: - /// See the \a ServerStreamingInterface.SendInitialMetadata method - /// for semantics. Note that initial metadata will be affected by the - /// \a ServerContext associated with this call. - void SendInitialMetadata() override { body_.SendInitialMetadata(); } - - bool NextMessageSize(uint32_t* sz) override { - return body_.NextMessageSize(sz); - } - - bool Read(R* msg) override { return body_.Read(msg); } - - /// See the \a WriterInterface.Write(const W& msg, WriteOptions options) - /// method for semantics. - /// Side effect: - /// Also sends initial metadata if not already sent (using the \a - /// ServerContext associated with this call). - using internal::WriterInterface::Write; - bool Write(const W& msg, WriteOptions options) override { - return body_.Write(msg, options); - } - - private: - internal::ServerReaderWriterBody body_; - - friend class internal::TemplatedBidiStreamingHandler, - false>; - ServerReaderWriter(internal::Call* call, ::grpc_impl::ServerContext* ctx) - : body_(call, ctx) {} -}; - -/// A class to represent a flow-controlled unary call. This is something -/// of a hybrid between conventional unary and streaming. This is invoked -/// through a unary call on the client side, but the server responds to it -/// as though it were a single-ping-pong streaming call. The server can use -/// the \a NextMessageSize method to determine an upper-bound on the size of -/// the message. A key difference relative to streaming: ServerUnaryStreamer -/// must have exactly 1 Read and exactly 1 Write, in that order, to function -/// correctly. Otherwise, the RPC is in error. +using ServerReaderWriter = ::grpc_impl::ServerReaderWriter; template -class ServerUnaryStreamer final - : public ServerReaderWriterInterface { - public: - /// Block to send initial metadata to client. - /// Implicit input parameter: - /// - the \a ServerContext associated with this call will be used for - /// sending initial metadata. - void SendInitialMetadata() override { body_.SendInitialMetadata(); } - - /// Get an upper bound on the request message size from the client. - bool NextMessageSize(uint32_t* sz) override { - return body_.NextMessageSize(sz); - } - - /// Read a message of type \a R into \a msg. Completion will be notified by \a - /// tag on the associated completion queue. - /// This is thread-safe with respect to \a Write or \a WritesDone methods. It - /// should not be called concurrently with other streaming APIs - /// on the same stream. It is not meaningful to call it concurrently - /// with another \a ReaderInterface::Read on the same stream since reads on - /// the same stream are delivered in order. - /// - /// \param[out] msg Where to eventually store the read message. - /// \param[in] tag The tag identifying the operation. - bool Read(RequestType* request) override { - if (read_done_) { - return false; - } - read_done_ = true; - return body_.Read(request); - } - - /// Block to write \a msg to the stream with WriteOptions \a options. - /// This is thread-safe with respect to \a ReaderInterface::Read - /// - /// \param msg The message to be written to the stream. - /// \param options The WriteOptions affecting the write operation. - /// - /// \return \a true on success, \a false when the stream has been closed. - using internal::WriterInterface::Write; - bool Write(const ResponseType& response, WriteOptions options) override { - if (write_done_ || !read_done_) { - return false; - } - write_done_ = true; - return body_.Write(response, options); - } - - private: - internal::ServerReaderWriterBody body_; - bool read_done_; - bool write_done_; - - friend class internal::TemplatedBidiStreamingHandler< - ServerUnaryStreamer, true>; - ServerUnaryStreamer(internal::Call* call, ::grpc_impl::ServerContext* ctx) - : body_(call, ctx), read_done_(false), write_done_(false) {} -}; - -/// A class to represent a flow-controlled server-side streaming call. -/// This is something of a hybrid between server-side and bidi streaming. -/// This is invoked through a server-side streaming call on the client side, -/// but the server responds to it as though it were a bidi streaming call that -/// must first have exactly 1 Read and then any number of Writes. +using ServerUnaryStreamer = + ::grpc_impl::ServerUnaryStreamer; template -class ServerSplitStreamer final - : public ServerReaderWriterInterface { - public: - /// Block to send initial metadata to client. - /// Implicit input parameter: - /// - the \a ServerContext associated with this call will be used for - /// sending initial metadata. - void SendInitialMetadata() override { body_.SendInitialMetadata(); } - - /// Get an upper bound on the request message size from the client. - bool NextMessageSize(uint32_t* sz) override { - return body_.NextMessageSize(sz); - } - - /// Read a message of type \a R into \a msg. Completion will be notified by \a - /// tag on the associated completion queue. - /// This is thread-safe with respect to \a Write or \a WritesDone methods. It - /// should not be called concurrently with other streaming APIs - /// on the same stream. It is not meaningful to call it concurrently - /// with another \a ReaderInterface::Read on the same stream since reads on - /// the same stream are delivered in order. - /// - /// \param[out] msg Where to eventually store the read message. - /// \param[in] tag The tag identifying the operation. - bool Read(RequestType* request) override { - if (read_done_) { - return false; - } - read_done_ = true; - return body_.Read(request); - } - - /// Block to write \a msg to the stream with WriteOptions \a options. - /// This is thread-safe with respect to \a ReaderInterface::Read - /// - /// \param msg The message to be written to the stream. - /// \param options The WriteOptions affecting the write operation. - /// - /// \return \a true on success, \a false when the stream has been closed. - using internal::WriterInterface::Write; - bool Write(const ResponseType& response, WriteOptions options) override { - return read_done_ && body_.Write(response, options); - } - - private: - internal::ServerReaderWriterBody body_; - bool read_done_; - - friend class internal::TemplatedBidiStreamingHandler< - ServerSplitStreamer, false>; - ServerSplitStreamer(internal::Call* call, ::grpc_impl::ServerContext* ctx) - : body_(call, ctx), read_done_(false) {} -}; +using ServerSplitStreamer = + ::grpc_impl::ServerSplitStreamer; } // namespace grpc diff --git a/include/grpcpp/impl/codegen/sync_stream_impl.h b/include/grpcpp/impl/codegen/sync_stream_impl.h new file mode 100644 index 00000000000..dc764e0e27b --- /dev/null +++ b/include/grpcpp/impl/codegen/sync_stream_impl.h @@ -0,0 +1,944 @@ +/* + * + * 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_SYNC_STREAM_IMPL_H +#define GRPCPP_IMPL_CODEGEN_SYNC_STREAM_IMPL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace grpc_impl { + +namespace internal { +/// Common interface for all synchronous client side streaming. +class ClientStreamingInterface { + public: + virtual ~ClientStreamingInterface() {} + + /// Block waiting until the stream finishes and a final status of the call is + /// available. + /// + /// It is appropriate to call this method when both: + /// * the calling code (client-side) has no more message to send + /// (this can be declared implicitly by calling this method, or + /// explicitly through an earlier call to WritesDone method of the + /// class in use, e.g. \a ClientWriterInterface::WritesDone or + /// \a ClientReaderWriterInterface::WritesDone). + /// * there are no more messages to be received from the server (which can + /// be known implicitly, or explicitly from an earlier call to \a + /// ReaderInterface::Read that returned "false"). + /// + /// This function will return either: + /// - when all incoming messages have been read and the server has + /// returned status. + /// - when the server has returned a non-OK status. + /// - OR when the call failed for some reason and the library generated a + /// status. + /// + /// Return values: + /// - \a Status contains the status code, message and details for the call + /// - the \a ClientContext associated with this call is updated with + /// possible trailing metadata sent from the server. + virtual ::grpc::Status Finish() = 0; +}; + +/// Common interface for all synchronous server side streaming. +class ServerStreamingInterface { + public: + virtual ~ServerStreamingInterface() {} + + /// Block to send initial metadata to client. + /// This call is optional, but if it is used, it cannot be used concurrently + /// with or after the \a Finish method. + /// + /// The initial metadata that will be sent to the client will be + /// taken from the \a ServerContext associated with the call. + virtual void SendInitialMetadata() = 0; +}; + +/// An interface that yields a sequence of messages of type \a R. +template +class ReaderInterface { + public: + virtual ~ReaderInterface() {} + + /// Get an upper bound on the next message size available for reading on this + /// stream. + virtual bool NextMessageSize(uint32_t* sz) = 0; + + /// Block to read a message and parse to \a msg. Returns \a true on success. + /// This is thread-safe with respect to \a Write or \WritesDone methods on + /// the same stream. It should not be called concurrently with another \a + /// Read on the same stream as the order of delivery will not be defined. + /// + /// \param[out] msg The read message. + /// + /// \return \a false when there will be no more incoming messages, either + /// because the other side has called \a WritesDone() or the stream has failed + /// (or been cancelled). + virtual bool Read(R* msg) = 0; +}; + +/// An interface that can be fed a sequence of messages of type \a W. +template +class WriterInterface { + public: + virtual ~WriterInterface() {} + + /// Block to write \a msg to the stream with WriteOptions \a options. + /// This is thread-safe with respect to \a ReaderInterface::Read + /// + /// \param msg The message to be written to the stream. + /// \param options The WriteOptions affecting the write operation. + /// + /// \return \a true on success, \a false when the stream has been closed. + virtual bool Write(const W& msg, ::grpc::WriteOptions options) = 0; + + /// Block to write \a msg to the stream with default write options. + /// This is thread-safe with respect to \a ReaderInterface::Read + /// + /// \param msg The message to be written to the stream. + /// + /// \return \a true on success, \a false when the stream has been closed. + inline bool Write(const W& msg) { return Write(msg, ::grpc::WriteOptions()); } + + /// Write \a msg and coalesce it with the writing of trailing metadata, using + /// WriteOptions \a options. + /// + /// For client, WriteLast is equivalent of performing Write and WritesDone in + /// a single step. \a msg and trailing metadata are coalesced and sent on wire + /// by calling this function. For server, WriteLast buffers the \a msg. + /// The writing of \a msg is held until the service handler returns, + /// where \a msg and trailing metadata are coalesced and sent on wire. + /// Note that WriteLast can only buffer \a msg up to the flow control window + /// size. If \a msg size is larger than the window size, it will be sent on + /// wire without buffering. + /// + /// \param[in] msg The message to be written to the stream. + /// \param[in] options The WriteOptions to be used to write this message. + void WriteLast(const W& msg, ::grpc::WriteOptions options) { + Write(msg, options.set_last_message()); + } +}; + +} // namespace internal + +/// Client-side interface for streaming reads of message of type \a R. +template +class ClientReaderInterface : public internal::ClientStreamingInterface, + public internal::ReaderInterface { + public: + /// Block to wait for initial metadata from server. The received metadata + /// can only be accessed after this call returns. Should only be called before + /// the first read. Calling this method is optional, and if it is not called + /// the metadata will be available in ClientContext after the first read. + virtual void WaitForInitialMetadata() = 0; +}; + +namespace internal { +template +class ClientReaderFactory { + public: + template + static ClientReader* Create(::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context, + const W& request) { + return new ClientReader(channel, method, context, request); + } +}; +} // namespace internal + +/// Synchronous (blocking) client-side API for doing server-streaming RPCs, +/// where the stream of messages coming from the server has messages +/// of type \a R. +template +class ClientReader final : public ClientReaderInterface { + public: + /// See the \a ClientStreamingInterface.WaitForInitialMetadata method for + /// semantics. + /// + // Side effect: + /// Once complete, the initial metadata read from + /// the server will be accessible through the \a ClientContext used to + /// construct this object. + void WaitForInitialMetadata() override { + GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); + + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> + ops; + ops.RecvInitialMetadata(context_); + call_.PerformOps(&ops); + cq_.Pluck(&ops); /// status ignored + } + + bool NextMessageSize(uint32_t* sz) override { + *sz = call_.max_receive_message_size(); + return true; + } + + /// See the \a ReaderInterface.Read method for semantics. + /// Side effect: + /// This also receives initial metadata from the server, if not + /// already received (if initial metadata is received, it can be then + /// accessed through the \a ClientContext associated with this call). + bool Read(R* msg) override { + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpRecvMessage> + ops; + if (!context_->initial_metadata_received_) { + ops.RecvInitialMetadata(context_); + } + ops.RecvMessage(msg); + call_.PerformOps(&ops); + return cq_.Pluck(&ops) && ops.got_message; + } + + /// See the \a ClientStreamingInterface.Finish method for semantics. + /// + /// Side effect: + /// The \a ClientContext associated with this call is updated with + /// possible metadata received from the server. + ::grpc::Status Finish() override { + ::grpc::internal::CallOpSet<::grpc::internal::CallOpClientRecvStatus> ops; + ::grpc::Status status; + ops.ClientRecvStatus(context_, &status); + call_.PerformOps(&ops); + GPR_CODEGEN_ASSERT(cq_.Pluck(&ops)); + return status; + } + + private: + friend class internal::ClientReaderFactory; + ::grpc_impl::ClientContext* context_; + ::grpc_impl::CompletionQueue cq_; + ::grpc::internal::Call call_; + + /// Block to create a stream and write the initial metadata and \a request + /// out. Note that \a context will be used to fill in custom initial + /// metadata used to send to the server when starting the call. + template + ClientReader(::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context, const W& request) + : context_(context), + cq_(grpc_completion_queue_attributes{ + GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING, + nullptr}), // Pluckable cq + call_(channel->CreateCall(method, context, &cq_)) { + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpClientSendClose> + ops; + ops.SendInitialMetadata(&context->send_initial_metadata_, + context->initial_metadata_flags()); + // TODO(ctiller): don't assert + GPR_CODEGEN_ASSERT(ops.SendMessagePtr(&request).ok()); + ops.ClientSendClose(); + call_.PerformOps(&ops); + cq_.Pluck(&ops); + } +}; + +/// Client-side interface for streaming writes of message type \a W. +template +class ClientWriterInterface : public internal::ClientStreamingInterface, + public internal::WriterInterface { + public: + /// Half close writing from the client. (signal that the stream of messages + /// coming from the client is complete). + /// Blocks until currently-pending writes are completed. + /// Thread safe with respect to \a ReaderInterface::Read operations only + /// + /// \return Whether the writes were successful. + virtual bool WritesDone() = 0; +}; + +namespace internal { +template +class ClientWriterFactory { + public: + template + static ClientWriter* Create(::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context, + R* response) { + return new ClientWriter(channel, method, context, response); + } +}; +} // namespace internal + +/// Synchronous (blocking) client-side API for doing client-streaming RPCs, +/// where the outgoing message stream coming from the client has messages of +/// type \a W. +template +class ClientWriter : public ClientWriterInterface { + public: + /// See the \a ClientStreamingInterface.WaitForInitialMetadata method for + /// semantics. + /// + // Side effect: + /// Once complete, the initial metadata read from the server will be + /// accessible through the \a ClientContext used to construct this object. + void WaitForInitialMetadata() { + GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); + + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> + ops; + ops.RecvInitialMetadata(context_); + call_.PerformOps(&ops); + cq_.Pluck(&ops); // status ignored + } + + /// See the WriterInterface.Write(const W& msg, WriteOptions options) method + /// for semantics. + /// + /// Side effect: + /// Also sends initial metadata if not already sent (using the + /// \a ClientContext associated with this call). + using internal::WriterInterface::Write; + bool Write(const W& msg, ::grpc::WriteOptions options) override { + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpClientSendClose> + ops; + + if (options.is_last_message()) { + options.set_buffer_hint(); + ops.ClientSendClose(); + } + if (context_->initial_metadata_corked_) { + ops.SendInitialMetadata(&context_->send_initial_metadata_, + context_->initial_metadata_flags()); + context_->set_initial_metadata_corked(false); + } + if (!ops.SendMessagePtr(&msg, options).ok()) { + return false; + } + + call_.PerformOps(&ops); + return cq_.Pluck(&ops); + } + + bool WritesDone() override { + ::grpc::internal::CallOpSet<::grpc::internal::CallOpClientSendClose> ops; + ops.ClientSendClose(); + call_.PerformOps(&ops); + return cq_.Pluck(&ops); + } + + /// See the ClientStreamingInterface.Finish method for semantics. + /// Side effects: + /// - Also receives initial metadata if not already received. + /// - Attempts to fill in the \a response parameter passed + /// to the constructor of this instance with the response + /// message from the server. + ::grpc::Status Finish() override { + ::grpc::Status status; + if (!context_->initial_metadata_received_) { + finish_ops_.RecvInitialMetadata(context_); + } + finish_ops_.ClientRecvStatus(context_, &status); + call_.PerformOps(&finish_ops_); + GPR_CODEGEN_ASSERT(cq_.Pluck(&finish_ops_)); + return status; + } + + private: + friend class internal::ClientWriterFactory; + + /// Block to create a stream (i.e. send request headers and other initial + /// metadata to the server). Note that \a context will be used to fill + /// in custom initial metadata. \a response will be filled in with the + /// single expected response message from the server upon a successful + /// call to the \a Finish method of this instance. + template + ClientWriter(::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context, R* response) + : context_(context), + cq_(grpc_completion_queue_attributes{ + GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING, + nullptr}), // Pluckable cq + call_(channel->CreateCall(method, context, &cq_)) { + finish_ops_.RecvMessage(response); + finish_ops_.AllowNoMessage(); + + if (!context_->initial_metadata_corked_) { + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> + ops; + ops.SendInitialMetadata(&context->send_initial_metadata_, + context->initial_metadata_flags()); + call_.PerformOps(&ops); + cq_.Pluck(&ops); + } + } + + ::grpc_impl::ClientContext* context_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpGenericRecvMessage, + ::grpc::internal::CallOpClientRecvStatus> + finish_ops_; + ::grpc_impl::CompletionQueue cq_; + ::grpc::internal::Call call_; +}; + +/// Client-side interface for bi-directional streaming with +/// client-to-server stream messages of type \a W and +/// server-to-client stream messages of type \a R. +template +class ClientReaderWriterInterface : public internal::ClientStreamingInterface, + public internal::WriterInterface, + public internal::ReaderInterface { + public: + /// Block to wait for initial metadata from server. The received metadata + /// can only be accessed after this call returns. Should only be called before + /// the first read. Calling this method is optional, and if it is not called + /// the metadata will be available in ClientContext after the first read. + virtual void WaitForInitialMetadata() = 0; + + /// Half close writing from the client. (signal that the stream of messages + /// coming from the clinet is complete). + /// Blocks until currently-pending writes are completed. + /// Thread-safe with respect to \a ReaderInterface::Read + /// + /// \return Whether the writes were successful. + virtual bool WritesDone() = 0; +}; + +namespace internal { +template +class ClientReaderWriterFactory { + public: + static ClientReaderWriter* Create( + ::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context) { + return new ClientReaderWriter(channel, method, context); + } +}; +} // namespace internal + +/// Synchronous (blocking) client-side API for bi-directional streaming RPCs, +/// where the outgoing message stream coming from the client has messages of +/// type \a W, and the incoming messages stream coming from the server has +/// messages of type \a R. +template +class ClientReaderWriter final : public ClientReaderWriterInterface { + public: + /// Block waiting to read initial metadata from the server. + /// This call is optional, but if it is used, it cannot be used concurrently + /// with or after the \a Finish method. + /// + /// Once complete, the initial metadata read from the server will be + /// accessible through the \a ClientContext used to construct this object. + void WaitForInitialMetadata() override { + GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); + + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> + ops; + ops.RecvInitialMetadata(context_); + call_.PerformOps(&ops); + cq_.Pluck(&ops); // status ignored + } + + bool NextMessageSize(uint32_t* sz) override { + *sz = call_.max_receive_message_size(); + return true; + } + + /// See the \a ReaderInterface.Read method for semantics. + /// Side effect: + /// Also receives initial metadata if not already received (updates the \a + /// ClientContext associated with this call in that case). + bool Read(R* msg) override { + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpRecvMessage> + ops; + if (!context_->initial_metadata_received_) { + ops.RecvInitialMetadata(context_); + } + ops.RecvMessage(msg); + call_.PerformOps(&ops); + return cq_.Pluck(&ops) && ops.got_message; + } + + /// See the \a WriterInterface.Write method for semantics. + /// + /// Side effect: + /// Also sends initial metadata if not already sent (using the + /// \a ClientContext associated with this call to fill in values). + using internal::WriterInterface::Write; + bool Write(const W& msg, ::grpc::WriteOptions options) override { + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpClientSendClose> + ops; + + if (options.is_last_message()) { + options.set_buffer_hint(); + ops.ClientSendClose(); + } + if (context_->initial_metadata_corked_) { + ops.SendInitialMetadata(&context_->send_initial_metadata_, + context_->initial_metadata_flags()); + context_->set_initial_metadata_corked(false); + } + if (!ops.SendMessagePtr(&msg, options).ok()) { + return false; + } + + call_.PerformOps(&ops); + return cq_.Pluck(&ops); + } + + bool WritesDone() override { + ::grpc::internal::CallOpSet<::grpc::internal::CallOpClientSendClose> ops; + ops.ClientSendClose(); + call_.PerformOps(&ops); + return cq_.Pluck(&ops); + } + + /// See the ClientStreamingInterface.Finish method for semantics. + /// + /// Side effect: + /// - the \a ClientContext associated with this call is updated with + /// possible trailing metadata sent from the server. + ::grpc::Status Finish() override { + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpClientRecvStatus> + ops; + if (!context_->initial_metadata_received_) { + ops.RecvInitialMetadata(context_); + } + ::grpc::Status status; + ops.ClientRecvStatus(context_, &status); + call_.PerformOps(&ops); + GPR_CODEGEN_ASSERT(cq_.Pluck(&ops)); + return status; + } + + private: + friend class internal::ClientReaderWriterFactory; + + ::grpc_impl::ClientContext* context_; + ::grpc_impl::CompletionQueue cq_; + ::grpc::internal::Call call_; + + /// Block to create a stream and write the initial metadata and \a request + /// out. Note that \a context will be used to fill in custom initial metadata + /// used to send to the server when starting the call. + ClientReaderWriter(::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context) + : context_(context), + cq_(grpc_completion_queue_attributes{ + GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING, + nullptr}), // Pluckable cq + call_(channel->CreateCall(method, context, &cq_)) { + if (!context_->initial_metadata_corked_) { + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> + ops; + ops.SendInitialMetadata(&context->send_initial_metadata_, + context->initial_metadata_flags()); + call_.PerformOps(&ops); + cq_.Pluck(&ops); + } + } +}; + +/// Server-side interface for streaming reads of message of type \a R. +template +class ServerReaderInterface : public internal::ServerStreamingInterface, + public internal::ReaderInterface {}; + +/// Synchronous (blocking) server-side API for doing client-streaming RPCs, +/// where the incoming message stream coming from the client has messages of +/// type \a R. +template +class ServerReader final : public ServerReaderInterface { + public: + /// See the \a ServerStreamingInterface.SendInitialMetadata method + /// for semantics. Note that initial metadata will be affected by the + /// \a ServerContext associated with this call. + void SendInitialMetadata() override { + GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); + + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> + ops; + ops.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + ops.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + call_->PerformOps(&ops); + call_->cq()->Pluck(&ops); + } + + bool NextMessageSize(uint32_t* sz) override { + *sz = call_->max_receive_message_size(); + return true; + } + + bool Read(R* msg) override { + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage> ops; + ops.RecvMessage(msg); + call_->PerformOps(&ops); + return call_->cq()->Pluck(&ops) && ops.got_message; + } + + private: + ::grpc::internal::Call* const call_; + ServerContext* const ctx_; + + template + friend class ::grpc::internal::ClientStreamingHandler; + + ServerReader(::grpc::internal::Call* call, ::grpc_impl::ServerContext* ctx) + : call_(call), ctx_(ctx) {} +}; + +/// Server-side interface for streaming writes of message of type \a W. +template +class ServerWriterInterface : public internal::ServerStreamingInterface, + public internal::WriterInterface {}; + +/// Synchronous (blocking) server-side API for doing for doing a +/// server-streaming RPCs, where the outgoing message stream coming from the +/// server has messages of type \a W. +template +class ServerWriter final : public ServerWriterInterface { + public: + /// See the \a ServerStreamingInterface.SendInitialMetadata method + /// for semantics. + /// Note that initial metadata will be affected by the + /// \a ServerContext associated with this call. + void SendInitialMetadata() override { + GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); + + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> + ops; + ops.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + ops.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + call_->PerformOps(&ops); + call_->cq()->Pluck(&ops); + } + + /// See the \a WriterInterface.Write method for semantics. + /// + /// Side effect: + /// Also sends initial metadata if not already sent (using the + /// \a ClientContext associated with this call to fill in values). + using internal::WriterInterface::Write; + bool Write(const W& msg, ::grpc::WriteOptions options) override { + if (options.is_last_message()) { + options.set_buffer_hint(); + } + + if (!ctx_->pending_ops_.SendMessagePtr(&msg, options).ok()) { + return false; + } + if (!ctx_->sent_initial_metadata_) { + ctx_->pending_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + ctx_->pending_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + } + call_->PerformOps(&ctx_->pending_ops_); + // if this is the last message we defer the pluck until AFTER we start + // the trailing md op. This prevents hangs. See + // https://github.com/grpc/grpc/issues/11546 + if (options.is_last_message()) { + ctx_->has_pending_ops_ = true; + return true; + } + ctx_->has_pending_ops_ = false; + return call_->cq()->Pluck(&ctx_->pending_ops_); + } + + private: + ::grpc::internal::Call* const call_; + ::grpc_impl::ServerContext* const ctx_; + + template + friend class ::grpc::internal::ServerStreamingHandler; + + ServerWriter(::grpc::internal::Call* call, ::grpc_impl::ServerContext* ctx) + : call_(call), ctx_(ctx) {} +}; + +/// Server-side interface for bi-directional streaming. +template +class ServerReaderWriterInterface : public internal::ServerStreamingInterface, + public internal::WriterInterface, + public internal::ReaderInterface {}; + +/// Actual implementation of bi-directional streaming +namespace internal { +template +class ServerReaderWriterBody final { + public: + ServerReaderWriterBody(grpc::internal::Call* call, + ::grpc_impl::ServerContext* ctx) + : call_(call), ctx_(ctx) {} + + void SendInitialMetadata() { + GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); + + grpc::internal::CallOpSet ops; + ops.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + ops.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + call_->PerformOps(&ops); + call_->cq()->Pluck(&ops); + } + + bool NextMessageSize(uint32_t* sz) { + *sz = call_->max_receive_message_size(); + return true; + } + + bool Read(R* msg) { + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage> ops; + ops.RecvMessage(msg); + call_->PerformOps(&ops); + return call_->cq()->Pluck(&ops) && ops.got_message; + } + + bool Write(const W& msg, ::grpc::WriteOptions options) { + if (options.is_last_message()) { + options.set_buffer_hint(); + } + if (!ctx_->pending_ops_.SendMessagePtr(&msg, options).ok()) { + return false; + } + if (!ctx_->sent_initial_metadata_) { + ctx_->pending_ops_.SendInitialMetadata(&ctx_->initial_metadata_, + ctx_->initial_metadata_flags()); + if (ctx_->compression_level_set()) { + ctx_->pending_ops_.set_compression_level(ctx_->compression_level()); + } + ctx_->sent_initial_metadata_ = true; + } + call_->PerformOps(&ctx_->pending_ops_); + // if this is the last message we defer the pluck until AFTER we start + // the trailing md op. This prevents hangs. See + // https://github.com/grpc/grpc/issues/11546 + if (options.is_last_message()) { + ctx_->has_pending_ops_ = true; + return true; + } + ctx_->has_pending_ops_ = false; + return call_->cq()->Pluck(&ctx_->pending_ops_); + } + + private: + grpc::internal::Call* const call_; + ::grpc_impl::ServerContext* const ctx_; +}; + +} // namespace internal + +/// Synchronous (blocking) server-side API for a bidirectional +/// streaming call, where the incoming message stream coming from the client has +/// messages of type \a R, and the outgoing message streaming coming from +/// the server has messages of type \a W. +template +class ServerReaderWriter final : public ServerReaderWriterInterface { + public: + /// See the \a ServerStreamingInterface.SendInitialMetadata method + /// for semantics. Note that initial metadata will be affected by the + /// \a ServerContext associated with this call. + void SendInitialMetadata() override { body_.SendInitialMetadata(); } + + bool NextMessageSize(uint32_t* sz) override { + return body_.NextMessageSize(sz); + } + + bool Read(R* msg) override { return body_.Read(msg); } + + /// See the \a WriterInterface.Write(const W& msg, WriteOptions options) + /// method for semantics. + /// Side effect: + /// Also sends initial metadata if not already sent (using the \a + /// ServerContext associated with this call). + using internal::WriterInterface::Write; + bool Write(const W& msg, ::grpc::WriteOptions options) override { + return body_.Write(msg, options); + } + + private: + internal::ServerReaderWriterBody body_; + + friend class ::grpc::internal::TemplatedBidiStreamingHandler< + ServerReaderWriter, false>; + ServerReaderWriter(::grpc::internal::Call* call, + ::grpc_impl::ServerContext* ctx) + : body_(call, ctx) {} +}; + +/// A class to represent a flow-controlled unary call. This is something +/// of a hybrid between conventional unary and streaming. This is invoked +/// through a unary call on the client side, but the server responds to it +/// as though it were a single-ping-pong streaming call. The server can use +/// the \a NextMessageSize method to determine an upper-bound on the size of +/// the message. A key difference relative to streaming: ServerUnaryStreamer +/// must have exactly 1 Read and exactly 1 Write, in that order, to function +/// correctly. Otherwise, the RPC is in error. +template +class ServerUnaryStreamer final + : public ServerReaderWriterInterface { + public: + /// Block to send initial metadata to client. + /// Implicit input parameter: + /// - the \a ServerContext associated with this call will be used for + /// sending initial metadata. + void SendInitialMetadata() override { body_.SendInitialMetadata(); } + + /// Get an upper bound on the request message size from the client. + bool NextMessageSize(uint32_t* sz) override { + return body_.NextMessageSize(sz); + } + + /// Read a message of type \a R into \a msg. Completion will be notified by \a + /// tag on the associated completion queue. + /// This is thread-safe with respect to \a Write or \a WritesDone methods. It + /// should not be called concurrently with other streaming APIs + /// on the same stream. It is not meaningful to call it concurrently + /// with another \a ReaderInterface::Read on the same stream since reads on + /// the same stream are delivered in order. + /// + /// \param[out] msg Where to eventually store the read message. + /// \param[in] tag The tag identifying the operation. + bool Read(RequestType* request) override { + if (read_done_) { + return false; + } + read_done_ = true; + return body_.Read(request); + } + + /// Block to write \a msg to the stream with WriteOptions \a options. + /// This is thread-safe with respect to \a ReaderInterface::Read + /// + /// \param msg The message to be written to the stream. + /// \param options The WriteOptions affecting the write operation. + /// + /// \return \a true on success, \a false when the stream has been closed. + using internal::WriterInterface::Write; + bool Write(const ResponseType& response, + ::grpc::WriteOptions options) override { + if (write_done_ || !read_done_) { + return false; + } + write_done_ = true; + return body_.Write(response, options); + } + + private: + internal::ServerReaderWriterBody body_; + bool read_done_; + bool write_done_; + + friend class ::grpc::internal::TemplatedBidiStreamingHandler< + ServerUnaryStreamer, true>; + ServerUnaryStreamer(::grpc::internal::Call* call, + ::grpc_impl::ServerContext* ctx) + : body_(call, ctx), read_done_(false), write_done_(false) {} +}; + +/// A class to represent a flow-controlled server-side streaming call. +/// This is something of a hybrid between server-side and bidi streaming. +/// This is invoked through a server-side streaming call on the client side, +/// but the server responds to it as though it were a bidi streaming call that +/// must first have exactly 1 Read and then any number of Writes. +template +class ServerSplitStreamer final + : public ServerReaderWriterInterface { + public: + /// Block to send initial metadata to client. + /// Implicit input parameter: + /// - the \a ServerContext associated with this call will be used for + /// sending initial metadata. + void SendInitialMetadata() override { body_.SendInitialMetadata(); } + + /// Get an upper bound on the request message size from the client. + bool NextMessageSize(uint32_t* sz) override { + return body_.NextMessageSize(sz); + } + + /// Read a message of type \a R into \a msg. Completion will be notified by \a + /// tag on the associated completion queue. + /// This is thread-safe with respect to \a Write or \a WritesDone methods. It + /// should not be called concurrently with other streaming APIs + /// on the same stream. It is not meaningful to call it concurrently + /// with another \a ReaderInterface::Read on the same stream since reads on + /// the same stream are delivered in order. + /// + /// \param[out] msg Where to eventually store the read message. + /// \param[in] tag The tag identifying the operation. + bool Read(RequestType* request) override { + if (read_done_) { + return false; + } + read_done_ = true; + return body_.Read(request); + } + + /// Block to write \a msg to the stream with WriteOptions \a options. + /// This is thread-safe with respect to \a ReaderInterface::Read + /// + /// \param msg The message to be written to the stream. + /// \param options The WriteOptions affecting the write operation. + /// + /// \return \a true on success, \a false when the stream has been closed. + using internal::WriterInterface::Write; + bool Write(const ResponseType& response, + ::grpc::WriteOptions options) override { + return read_done_ && body_.Write(response, options); + } + + private: + internal::ServerReaderWriterBody body_; + bool read_done_; + + friend class ::grpc::internal::TemplatedBidiStreamingHandler< + ServerSplitStreamer, false>; + ServerSplitStreamer(::grpc::internal::Call* call, + ::grpc_impl::ServerContext* ctx) + : body_(call, ctx), read_done_(false) {} +}; + +} // namespace grpc_impl + +#endif // GRPCPP_IMPL_CODEGEN_SYNC_STREAM_IMPL_H diff --git a/include/grpcpp/support/async_stream_impl.h b/include/grpcpp/support/async_stream_impl.h new file mode 100644 index 00000000000..cff700d3fa9 --- /dev/null +++ b/include/grpcpp/support/async_stream_impl.h @@ -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_ASYNC_STREAM_IMPL_H +#define GRPCPP_SUPPORT_ASYNC_STREAM_IMPL_H + +#include + +#endif // GRPCPP_SUPPORT_ASYNC_STREAM_IMPL_H diff --git a/include/grpcpp/support/async_unary_call_impl.h b/include/grpcpp/support/async_unary_call_impl.h new file mode 100644 index 00000000000..488fe87515a --- /dev/null +++ b/include/grpcpp/support/async_unary_call_impl.h @@ -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_ASYNC_UNARY_CALL_IMPL_H +#define GRPCPP_SUPPORT_ASYNC_UNARY_CALL_IMPL_H + +#include + +#endif // GRPCPP_SUPPORT_ASYNC_UNARY_CALL_IMPL_H diff --git a/include/grpcpp/support/client_callback_impl.h b/include/grpcpp/support/client_callback_impl.h new file mode 100644 index 00000000000..ed8df412496 --- /dev/null +++ b/include/grpcpp/support/client_callback_impl.h @@ -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_CLIENT_CALLBACK_IMPL_H +#define GRPCPP_SUPPORT_CLIENT_CALLBACK_IMPL_H + +#include + +#endif // GRPCPP_SUPPORT_CLIENT_CALLBACK_IMPL_H diff --git a/include/grpcpp/support/server_callback_impl.h b/include/grpcpp/support/server_callback_impl.h new file mode 100644 index 00000000000..a91c8141dd8 --- /dev/null +++ b/include/grpcpp/support/server_callback_impl.h @@ -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_SERVER_CALLBACK_IMPL_H +#define GRPCPP_SUPPORT_SERVER_CALLBACK_IMPL_H + +#include + +#endif // GRPCPP_SUPPORT_SERVER_CALLBACK_IMPL_H diff --git a/include/grpcpp/support/sync_stream_impl.h b/include/grpcpp/support/sync_stream_impl.h new file mode 100644 index 00000000000..a00e425acfc --- /dev/null +++ b/include/grpcpp/support/sync_stream_impl.h @@ -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_SYNC_STREAM_IMPL_H +#define GRPCPP_SUPPORT_SYNC_STREAM_IMPL_H + +#include + +#endif // GRPCPP_SUPPORT_SYNC_STREAM_IMPL_H diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc index 358efe9fd79..044647d9a81 100644 --- a/src/compiler/cpp_generator.cc +++ b/src/compiler/cpp_generator.cc @@ -143,6 +143,7 @@ grpc::string GetHeaderIncludes(grpc_generator::File* file, "grpcpp/impl/codegen/async_unary_call.h", "grpcpp/impl/codegen/client_callback.h", "grpcpp/impl/codegen/client_context.h", + "grpcpp/impl/codegen/completion_queue.h", "grpcpp/impl/codegen/method_handler_impl.h", "grpcpp/impl/codegen/proto_utils.h", "grpcpp/impl/codegen/rpc_method.h", @@ -946,11 +947,12 @@ void PrintHeaderServerCallbackMethodsHelper( " abort();\n" " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" "}\n"); - printer->Print(*vars, - "virtual ::grpc::experimental::ServerReadReactor< " - "$RealRequest$, $RealResponse$>* $Method$() {\n" - " return new ::grpc::internal::UnimplementedReadReactor<\n" - " $RealRequest$, $RealResponse$>;}\n"); + printer->Print( + *vars, + "virtual ::grpc::experimental::ServerReadReactor< " + "$RealRequest$, $RealResponse$>* $Method$() {\n" + " return new ::grpc_impl::internal::UnimplementedReadReactor<\n" + " $RealRequest$, $RealResponse$>;}\n"); } else if (ServerOnlyStreaming(method)) { printer->Print( *vars, @@ -962,11 +964,12 @@ void PrintHeaderServerCallbackMethodsHelper( " abort();\n" " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" "}\n"); - printer->Print(*vars, - "virtual ::grpc::experimental::ServerWriteReactor< " - "$RealRequest$, $RealResponse$>* $Method$() {\n" - " return new ::grpc::internal::UnimplementedWriteReactor<\n" - " $RealRequest$, $RealResponse$>;}\n"); + printer->Print( + *vars, + "virtual ::grpc::experimental::ServerWriteReactor< " + "$RealRequest$, $RealResponse$>* $Method$() {\n" + " return new ::grpc_impl::internal::UnimplementedWriteReactor<\n" + " $RealRequest$, $RealResponse$>;}\n"); } else if (method->BidiStreaming()) { printer->Print( *vars, @@ -978,11 +981,12 @@ void PrintHeaderServerCallbackMethodsHelper( " abort();\n" " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" "}\n"); - printer->Print(*vars, - "virtual ::grpc::experimental::ServerBidiReactor< " - "$RealRequest$, $RealResponse$>* $Method$() {\n" - " return new ::grpc::internal::UnimplementedBidiReactor<\n" - " $RealRequest$, $RealResponse$>;}\n"); + printer->Print( + *vars, + "virtual ::grpc::experimental::ServerBidiReactor< " + "$RealRequest$, $RealResponse$>* $Method$() {\n" + " return new ::grpc_impl::internal::UnimplementedBidiReactor<\n" + " $RealRequest$, $RealResponse$>;}\n"); } } @@ -1010,7 +1014,7 @@ void PrintHeaderServerMethodCallback( printer->Print( *vars, " ::grpc::Service::experimental().MarkMethodCallback($Idx$,\n" - " new ::grpc::internal::CallbackUnaryHandler< " + " new ::grpc_impl::internal::CallbackUnaryHandler< " "$RealRequest$, $RealResponse$>(\n" " [this](::grpc::ServerContext* context,\n" " const $RealRequest$* request,\n" @@ -1024,7 +1028,7 @@ void PrintHeaderServerMethodCallback( "void SetMessageAllocatorFor_$Method$(\n" " ::grpc::experimental::MessageAllocator< " "$RealRequest$, $RealResponse$>* allocator) {\n" - " static_cast<::grpc::internal::CallbackUnaryHandler< " + " static_cast<::grpc_impl::internal::CallbackUnaryHandler< " "$RealRequest$, $RealResponse$>*>(\n" " ::grpc::Service::experimental().GetHandler($Idx$))\n" " ->SetMessageAllocator(allocator);\n"); @@ -1032,21 +1036,21 @@ void PrintHeaderServerMethodCallback( printer->Print( *vars, " ::grpc::Service::experimental().MarkMethodCallback($Idx$,\n" - " new ::grpc::internal::CallbackClientStreamingHandler< " + " new ::grpc_impl::internal::CallbackClientStreamingHandler< " "$RealRequest$, $RealResponse$>(\n" " [this] { return this->$Method$(); }));\n"); } else if (ServerOnlyStreaming(method)) { printer->Print( *vars, " ::grpc::Service::experimental().MarkMethodCallback($Idx$,\n" - " new ::grpc::internal::CallbackServerStreamingHandler< " + " new ::grpc_impl::internal::CallbackServerStreamingHandler< " "$RealRequest$, $RealResponse$>(\n" " [this] { return this->$Method$(); }));\n"); } else if (method->BidiStreaming()) { printer->Print( *vars, " ::grpc::Service::experimental().MarkMethodCallback($Idx$,\n" - " new ::grpc::internal::CallbackBidiHandler< " + " new ::grpc_impl::internal::CallbackBidiHandler< " "$RealRequest$, $RealResponse$>(\n" " [this] { return this->$Method$(); }));\n"); } @@ -1084,7 +1088,7 @@ void PrintHeaderServerMethodRawCallback( printer->Print( *vars, " ::grpc::Service::experimental().MarkMethodRawCallback($Idx$,\n" - " new ::grpc::internal::CallbackUnaryHandler< " + " new ::grpc_impl::internal::CallbackUnaryHandler< " "$RealRequest$, $RealResponse$>(\n" " [this](::grpc::ServerContext* context,\n" " const $RealRequest$* request,\n" @@ -1098,21 +1102,21 @@ void PrintHeaderServerMethodRawCallback( printer->Print( *vars, " ::grpc::Service::experimental().MarkMethodRawCallback($Idx$,\n" - " new ::grpc::internal::CallbackClientStreamingHandler< " + " new ::grpc_impl::internal::CallbackClientStreamingHandler< " "$RealRequest$, $RealResponse$>(\n" " [this] { return this->$Method$(); }));\n"); } else if (ServerOnlyStreaming(method)) { printer->Print( *vars, " ::grpc::Service::experimental().MarkMethodRawCallback($Idx$,\n" - " new ::grpc::internal::CallbackServerStreamingHandler< " + " new ::grpc_impl::internal::CallbackServerStreamingHandler< " "$RealRequest$, $RealResponse$>(\n" " [this] { return this->$Method$(); }));\n"); } else if (method->BidiStreaming()) { printer->Print( *vars, " ::grpc::Service::experimental().MarkMethodRawCallback($Idx$,\n" - " new ::grpc::internal::CallbackBidiHandler< " + " new ::grpc_impl::internal::CallbackBidiHandler< " "$RealRequest$, $RealResponse$>(\n" " [this] { return this->$Method$(); }));\n"); } @@ -1705,7 +1709,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, "const $Request$* request, $Response$* response, " "std::function f) {\n"); printer->Print(*vars, - " ::grpc::internal::CallbackUnaryCall" + " ::grpc_impl::internal::CallbackUnaryCall" "(stub_->channel_.get(), stub_->rpcmethod_$Method$_, " "context, request, response, std::move(f));\n}\n\n"); @@ -1715,7 +1719,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, "const ::grpc::ByteBuffer* request, $Response$* response, " "std::function f) {\n"); printer->Print(*vars, - " ::grpc::internal::CallbackUnaryCall" + " ::grpc_impl::internal::CallbackUnaryCall" "(stub_->channel_.get(), stub_->rpcmethod_$Method$_, " "context, request, response, std::move(f));\n}\n\n"); @@ -1725,7 +1729,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, "const $Request$* request, $Response$* response, " "::grpc::experimental::ClientUnaryReactor* reactor) {\n"); printer->Print(*vars, - " ::grpc::internal::ClientCallbackUnaryFactory::Create" + " ::grpc_impl::internal::ClientCallbackUnaryFactory::Create" "(stub_->channel_.get(), stub_->rpcmethod_$Method$_, " "context, request, response, reactor);\n}\n\n"); @@ -1735,7 +1739,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, "const ::grpc::ByteBuffer* request, $Response$* response, " "::grpc::experimental::ClientUnaryReactor* reactor) {\n"); printer->Print(*vars, - " ::grpc::internal::ClientCallbackUnaryFactory::Create" + " ::grpc_impl::internal::ClientCallbackUnaryFactory::Create" "(stub_->channel_.get(), stub_->rpcmethod_$Method$_, " "context, request, response, reactor);\n}\n\n"); @@ -1751,7 +1755,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, printer->Print( *vars, " return " - "::grpc::internal::ClientAsyncResponseReaderFactory< $Response$>" + "::grpc_impl::internal::ClientAsyncResponseReaderFactory< $Response$>" "::Create(channel_.get(), cq, " "rpcmethod_$Method$_, " "context, request, $AsyncStart$);\n" @@ -1762,13 +1766,13 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, "::grpc::ClientWriter< $Request$>* " "$ns$$Service$::Stub::$Method$Raw(" "::grpc::ClientContext* context, $Response$* response) {\n"); - printer->Print( - *vars, - " return ::grpc::internal::ClientWriterFactory< $Request$>::Create(" - "channel_.get(), " - "rpcmethod_$Method$_, " - "context, response);\n" - "}\n\n"); + printer->Print(*vars, + " return ::grpc_impl::internal::ClientWriterFactory< " + "$Request$>::Create(" + "channel_.get(), " + "rpcmethod_$Method$_, " + "context, response);\n" + "}\n\n"); printer->Print( *vars, @@ -1777,7 +1781,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, "$Response$* response, " "::grpc::experimental::ClientWriteReactor< $Request$>* reactor) {\n"); printer->Print(*vars, - " ::grpc::internal::ClientCallbackWriterFactory< " + " ::grpc_impl::internal::ClientCallbackWriterFactory< " "$Request$>::Create(" "stub_->channel_.get(), " "stub_->rpcmethod_$Method$_, " @@ -1796,7 +1800,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); printer->Print( *vars, - " return ::grpc::internal::ClientAsyncWriterFactory< $Request$>" + " return ::grpc_impl::internal::ClientAsyncWriterFactory< $Request$>" "::Create(channel_.get(), cq, " "rpcmethod_$Method$_, " "context, response, $AsyncStart$$AsyncCreateArgs$);\n" @@ -1808,13 +1812,13 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, "::grpc::ClientReader< $Response$>* " "$ns$$Service$::Stub::$Method$Raw(" "::grpc::ClientContext* context, const $Request$& request) {\n"); - printer->Print( - *vars, - " return ::grpc::internal::ClientReaderFactory< $Response$>::Create(" - "channel_.get(), " - "rpcmethod_$Method$_, " - "context, request);\n" - "}\n\n"); + printer->Print(*vars, + " return ::grpc_impl::internal::ClientReaderFactory< " + "$Response$>::Create(" + "channel_.get(), " + "rpcmethod_$Method$_, " + "context, request);\n" + "}\n\n"); printer->Print( *vars, @@ -1823,7 +1827,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, "$Request$* request, " "::grpc::experimental::ClientReadReactor< $Response$>* reactor) {\n"); printer->Print(*vars, - " ::grpc::internal::ClientCallbackReaderFactory< " + " ::grpc_impl::internal::ClientCallbackReaderFactory< " "$Response$>::Create(" "stub_->channel_.get(), " "stub_->rpcmethod_$Method$_, " @@ -1843,7 +1847,8 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); printer->Print( *vars, - " return ::grpc::internal::ClientAsyncReaderFactory< $Response$>" + " return ::grpc_impl::internal::ClientAsyncReaderFactory< " + "$Response$>" "::Create(channel_.get(), cq, " "rpcmethod_$Method$_, " "context, request, $AsyncStart$$AsyncCreateArgs$);\n" @@ -1855,7 +1860,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, "::grpc::ClientReaderWriter< $Request$, $Response$>* " "$ns$$Service$::Stub::$Method$Raw(::grpc::ClientContext* context) {\n"); printer->Print(*vars, - " return ::grpc::internal::ClientReaderWriterFactory< " + " return ::grpc_impl::internal::ClientReaderWriterFactory< " "$Request$, $Response$>::Create(" "channel_.get(), " "rpcmethod_$Method$_, " @@ -1868,13 +1873,14 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, "ClientContext* context, " "::grpc::experimental::ClientBidiReactor< $Request$,$Response$>* " "reactor) {\n"); - printer->Print(*vars, - " ::grpc::internal::ClientCallbackReaderWriterFactory< " - "$Request$,$Response$>::Create(" - "stub_->channel_.get(), " - "stub_->rpcmethod_$Method$_, " - "context, reactor);\n" - "}\n\n"); + printer->Print( + *vars, + " ::grpc_impl::internal::ClientCallbackReaderWriterFactory< " + "$Request$,$Response$>::Create(" + "stub_->channel_.get(), " + "stub_->rpcmethod_$Method$_, " + "context, reactor);\n" + "}\n\n"); for (auto async_prefix : async_prefixes) { (*vars)["AsyncPrefix"] = async_prefix.prefix; @@ -1888,7 +1894,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer, "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); printer->Print(*vars, " return " - "::grpc::internal::ClientAsyncReaderWriterFactory< " + "::grpc_impl::internal::ClientAsyncReaderWriterFactory< " "$Request$, $Response$>::Create(" "channel_.get(), cq, " "rpcmethod_$Method$_, " @@ -2279,7 +2285,8 @@ void PrintMockClientMethods(grpc_generator::Printer* printer, printer->Print( *vars, "MOCK_METHOD$MockArgs$($AsyncPrefix$$Method$Raw, " - "::grpc::ClientAsyncReaderWriterInterface<$Request$, $Response$>*" + "::grpc::ClientAsyncReaderWriterInterface<$Request$, " + "$Response$>*" "(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq" "$AsyncMethodParams$));\n"); } diff --git a/src/cpp/client/generic_stub.cc b/src/cpp/client/generic_stub.cc index 41631c794f2..e7d3df7a497 100644 --- a/src/cpp/client/generic_stub.cc +++ b/src/cpp/client/generic_stub.cc @@ -27,11 +27,10 @@ namespace grpc_impl { namespace { std::unique_ptr CallInternal( grpc::ChannelInterface* channel, grpc::ClientContext* context, - const grpc::string& method, grpc::CompletionQueue* cq, bool start, - void* tag) { + const grpc::string& method, CompletionQueue* cq, bool start, void* tag) { return std::unique_ptr( - grpc::internal::ClientAsyncReaderWriterFactory:: + internal::ClientAsyncReaderWriterFactory:: Create(channel, cq, grpc::internal::RpcMethod( method.c_str(), grpc::internal::RpcMethod::BIDI_STREAMING), @@ -43,14 +42,14 @@ std::unique_ptr CallInternal( // begin a call to a named method std::unique_ptr GenericStub::Call( grpc::ClientContext* context, const grpc::string& method, - grpc::CompletionQueue* cq, void* tag) { + CompletionQueue* cq, void* tag) { return CallInternal(channel_.get(), context, method, cq, true, tag); } // setup a call to a named method std::unique_ptr GenericStub::PrepareCall( grpc::ClientContext* context, const grpc::string& method, - grpc::CompletionQueue* cq) { + CompletionQueue* cq) { return CallInternal(channel_.get(), context, method, cq, false, nullptr); } @@ -59,21 +58,20 @@ std::unique_ptr GenericStub::PrepareUnaryCall(grpc::ClientContext* context, const grpc::string& method, const grpc::ByteBuffer& request, - grpc::CompletionQueue* cq) { + CompletionQueue* cq) { return std::unique_ptr( - grpc::internal::ClientAsyncResponseReaderFactory< - grpc::ByteBuffer>::Create(channel_.get(), cq, - grpc::internal::RpcMethod( - method.c_str(), - grpc::internal::RpcMethod::NORMAL_RPC), - context, request, false)); + internal::ClientAsyncResponseReaderFactory::Create( + channel_.get(), cq, + grpc::internal::RpcMethod(method.c_str(), + grpc::internal::RpcMethod::NORMAL_RPC), + context, request, false)); } void GenericStub::experimental_type::UnaryCall( grpc::ClientContext* context, const grpc::string& method, const grpc::ByteBuffer* request, grpc::ByteBuffer* response, std::function on_completion) { - grpc::internal::CallbackUnaryCall( + internal::CallbackUnaryCall( stub_->channel_.get(), grpc::internal::RpcMethod(method.c_str(), grpc::internal::RpcMethod::NORMAL_RPC), @@ -82,9 +80,9 @@ void GenericStub::experimental_type::UnaryCall( void GenericStub::experimental_type::PrepareBidiStreamingCall( grpc::ClientContext* context, const grpc::string& method, - grpc::experimental::ClientBidiReactor* + experimental::ClientBidiReactor* reactor) { - grpc::internal::ClientCallbackReaderWriterFactory< + internal::ClientCallbackReaderWriterFactory< grpc::ByteBuffer, grpc::ByteBuffer>::Create(stub_->channel_.get(), grpc::internal::RpcMethod( diff --git a/src/cpp/server/async_generic_service.cc b/src/cpp/server/async_generic_service.cc index 30613768295..556447a7f40 100644 --- a/src/cpp/server/async_generic_service.cc +++ b/src/cpp/server/async_generic_service.cc @@ -24,8 +24,8 @@ namespace grpc { void AsyncGenericService::RequestCall( GenericServerContext* ctx, GenericServerAsyncReaderWriter* reader_writer, - CompletionQueue* call_cq, ServerCompletionQueue* notification_cq, - void* tag) { + ::grpc_impl::CompletionQueue* call_cq, + ::grpc_impl::ServerCompletionQueue* notification_cq, void* tag) { server_->RequestAsyncGenericCall(ctx, reader_writer, call_cq, notification_cq, tag); } diff --git a/src/cpp/server/health/default_health_check_service.h b/src/cpp/server/health/default_health_check_service.h index 4b926efdfe8..14a54d53ee0 100644 --- a/src/cpp/server/health/default_health_check_service.h +++ b/src/cpp/server/health/default_health_check_service.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include diff --git a/src/cpp/server/server_builder.cc b/src/cpp/server/server_builder.cc index 1ba9ae1c9dc..1d68c2bdaea 100644 --- a/src/cpp/server/server_builder.cc +++ b/src/cpp/server/server_builder.cc @@ -69,14 +69,14 @@ ServerBuilder::~ServerBuilder() { } } -std::unique_ptr ServerBuilder::AddCompletionQueue( +std::unique_ptr ServerBuilder::AddCompletionQueue( bool is_frequently_polled) { - grpc::ServerCompletionQueue* cq = new grpc::ServerCompletionQueue( + ServerCompletionQueue* cq = new ServerCompletionQueue( GRPC_CQ_NEXT, is_frequently_polled ? GRPC_CQ_DEFAULT_POLLING : GRPC_CQ_NON_LISTENING, nullptr); cqs_.push_back(cq); - return std::unique_ptr(cq); + return std::unique_ptr(cq); } ServerBuilder& ServerBuilder::RegisterService(grpc::Service* service) { @@ -266,10 +266,9 @@ std::unique_ptr ServerBuilder::BuildAndStart() { // This is different from the completion queues added to the server via // ServerBuilder's AddCompletionQueue() method (those completion queues // are in 'cqs_' member variable of ServerBuilder object) - std::shared_ptr>> - sync_server_cqs( - std::make_shared< - std::vector>>()); + std::shared_ptr>> + sync_server_cqs(std::make_shared< + std::vector>>()); bool has_frequently_polled_cqs = false; for (auto it = cqs_.begin(); it != cqs_.end(); ++it) { @@ -298,7 +297,7 @@ std::unique_ptr ServerBuilder::BuildAndStart() { // Create completion queues to listen to incoming rpc requests for (int i = 0; i < sync_server_settings_.num_cqs; i++) { sync_server_cqs->emplace_back( - new grpc::ServerCompletionQueue(GRPC_CQ_NEXT, polling_type, nullptr)); + new ServerCompletionQueue(GRPC_CQ_NEXT, polling_type, nullptr)); } } diff --git a/src/cpp/server/server_context.cc b/src/cpp/server/server_context.cc index ba834237ae9..1e27fad3988 100644 --- a/src/cpp/server/server_context.cc +++ b/src/cpp/server/server_context.cc @@ -45,8 +45,7 @@ class ServerContext::CompletionOp final public: // initial refs: one in the server context, one in the cq // must ref the call before calling constructor and after deleting this - CompletionOp(::grpc::internal::Call* call, - ::grpc::internal::ServerReactor* reactor) + CompletionOp(::grpc::internal::Call* call, internal::ServerReactor* reactor) : call_(*call), reactor_(reactor), has_tag_(false), @@ -152,7 +151,7 @@ class ServerContext::CompletionOp final } ::grpc::internal::Call call_; - ::grpc::internal::ServerReactor* const reactor_; + internal::ServerReactor* const reactor_; bool has_tag_; void* tag_; void* core_cq_tag_; @@ -294,9 +293,9 @@ void ServerContext::Clear() { } } -void ServerContext::BeginCompletionOp( - ::grpc::internal::Call* call, std::function callback, - ::grpc::internal::ServerReactor* reactor) { +void ServerContext::BeginCompletionOp(::grpc::internal::Call* call, + std::function callback, + internal::ServerReactor* reactor) { GPR_ASSERT(!completion_op_); if (rpc_info_) { rpc_info_->Ref(); diff --git a/test/cpp/codegen/compiler_test_golden b/test/cpp/codegen/compiler_test_golden index 035955023b8..34fb5bfb53f 100644 --- a/test/cpp/codegen/compiler_test_golden +++ b/test/cpp/codegen/compiler_test_golden @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -336,7 +337,7 @@ class ServiceA final { public: ExperimentalWithCallbackMethod_MethodA1() { ::grpc::Service::experimental().MarkMethodCallback(0, - new ::grpc::internal::CallbackUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>( + new ::grpc_impl::internal::CallbackUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>( [this](::grpc::ServerContext* context, const ::grpc::testing::Request* request, ::grpc::testing::Response* response, @@ -346,7 +347,7 @@ class ServiceA final { } void SetMessageAllocatorFor_MethodA1( ::grpc::experimental::MessageAllocator< ::grpc::testing::Request, ::grpc::testing::Response>* allocator) { - static_cast<::grpc::internal::CallbackUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>*>( + static_cast<::grpc_impl::internal::CallbackUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>*>( ::grpc::Service::experimental().GetHandler(0)) ->SetMessageAllocator(allocator); } @@ -367,7 +368,7 @@ class ServiceA final { public: ExperimentalWithCallbackMethod_MethodA2() { ::grpc::Service::experimental().MarkMethodCallback(1, - new ::grpc::internal::CallbackClientStreamingHandler< ::grpc::testing::Request, ::grpc::testing::Response>( + new ::grpc_impl::internal::CallbackClientStreamingHandler< ::grpc::testing::Request, ::grpc::testing::Response>( [this] { return this->MethodA2(); })); } ~ExperimentalWithCallbackMethod_MethodA2() override { @@ -379,7 +380,7 @@ class ServiceA final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } virtual ::grpc::experimental::ServerReadReactor< ::grpc::testing::Request, ::grpc::testing::Response>* MethodA2() { - return new ::grpc::internal::UnimplementedReadReactor< + return new ::grpc_impl::internal::UnimplementedReadReactor< ::grpc::testing::Request, ::grpc::testing::Response>;} }; template @@ -389,7 +390,7 @@ class ServiceA final { public: ExperimentalWithCallbackMethod_MethodA3() { ::grpc::Service::experimental().MarkMethodCallback(2, - new ::grpc::internal::CallbackServerStreamingHandler< ::grpc::testing::Request, ::grpc::testing::Response>( + new ::grpc_impl::internal::CallbackServerStreamingHandler< ::grpc::testing::Request, ::grpc::testing::Response>( [this] { return this->MethodA3(); })); } ~ExperimentalWithCallbackMethod_MethodA3() override { @@ -401,7 +402,7 @@ class ServiceA final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } virtual ::grpc::experimental::ServerWriteReactor< ::grpc::testing::Request, ::grpc::testing::Response>* MethodA3() { - return new ::grpc::internal::UnimplementedWriteReactor< + return new ::grpc_impl::internal::UnimplementedWriteReactor< ::grpc::testing::Request, ::grpc::testing::Response>;} }; template @@ -411,7 +412,7 @@ class ServiceA final { public: ExperimentalWithCallbackMethod_MethodA4() { ::grpc::Service::experimental().MarkMethodCallback(3, - new ::grpc::internal::CallbackBidiHandler< ::grpc::testing::Request, ::grpc::testing::Response>( + new ::grpc_impl::internal::CallbackBidiHandler< ::grpc::testing::Request, ::grpc::testing::Response>( [this] { return this->MethodA4(); })); } ~ExperimentalWithCallbackMethod_MethodA4() override { @@ -423,7 +424,7 @@ class ServiceA final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } virtual ::grpc::experimental::ServerBidiReactor< ::grpc::testing::Request, ::grpc::testing::Response>* MethodA4() { - return new ::grpc::internal::UnimplementedBidiReactor< + return new ::grpc_impl::internal::UnimplementedBidiReactor< ::grpc::testing::Request, ::grpc::testing::Response>;} }; typedef ExperimentalWithCallbackMethod_MethodA1 > > > ExperimentalCallbackService; @@ -582,7 +583,7 @@ class ServiceA final { public: ExperimentalWithRawCallbackMethod_MethodA1() { ::grpc::Service::experimental().MarkMethodRawCallback(0, - new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( + new ::grpc_impl::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this](::grpc::ServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response, @@ -607,7 +608,7 @@ class ServiceA final { public: ExperimentalWithRawCallbackMethod_MethodA2() { ::grpc::Service::experimental().MarkMethodRawCallback(1, - new ::grpc::internal::CallbackClientStreamingHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( + new ::grpc_impl::internal::CallbackClientStreamingHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this] { return this->MethodA2(); })); } ~ExperimentalWithRawCallbackMethod_MethodA2() override { @@ -619,7 +620,7 @@ class ServiceA final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } virtual ::grpc::experimental::ServerReadReactor< ::grpc::ByteBuffer, ::grpc::ByteBuffer>* MethodA2() { - return new ::grpc::internal::UnimplementedReadReactor< + return new ::grpc_impl::internal::UnimplementedReadReactor< ::grpc::ByteBuffer, ::grpc::ByteBuffer>;} }; template @@ -629,7 +630,7 @@ class ServiceA final { public: ExperimentalWithRawCallbackMethod_MethodA3() { ::grpc::Service::experimental().MarkMethodRawCallback(2, - new ::grpc::internal::CallbackServerStreamingHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( + new ::grpc_impl::internal::CallbackServerStreamingHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this] { return this->MethodA3(); })); } ~ExperimentalWithRawCallbackMethod_MethodA3() override { @@ -641,7 +642,7 @@ class ServiceA final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } virtual ::grpc::experimental::ServerWriteReactor< ::grpc::ByteBuffer, ::grpc::ByteBuffer>* MethodA3() { - return new ::grpc::internal::UnimplementedWriteReactor< + return new ::grpc_impl::internal::UnimplementedWriteReactor< ::grpc::ByteBuffer, ::grpc::ByteBuffer>;} }; template @@ -651,7 +652,7 @@ class ServiceA final { public: ExperimentalWithRawCallbackMethod_MethodA4() { ::grpc::Service::experimental().MarkMethodRawCallback(3, - new ::grpc::internal::CallbackBidiHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( + new ::grpc_impl::internal::CallbackBidiHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this] { return this->MethodA4(); })); } ~ExperimentalWithRawCallbackMethod_MethodA4() override { @@ -663,7 +664,7 @@ class ServiceA final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } virtual ::grpc::experimental::ServerBidiReactor< ::grpc::ByteBuffer, ::grpc::ByteBuffer>* MethodA4() { - return new ::grpc::internal::UnimplementedBidiReactor< + return new ::grpc_impl::internal::UnimplementedBidiReactor< ::grpc::ByteBuffer, ::grpc::ByteBuffer>;} }; template @@ -814,7 +815,7 @@ class ServiceB final { public: ExperimentalWithCallbackMethod_MethodB1() { ::grpc::Service::experimental().MarkMethodCallback(0, - new ::grpc::internal::CallbackUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>( + new ::grpc_impl::internal::CallbackUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>( [this](::grpc::ServerContext* context, const ::grpc::testing::Request* request, ::grpc::testing::Response* response, @@ -824,7 +825,7 @@ class ServiceB final { } void SetMessageAllocatorFor_MethodB1( ::grpc::experimental::MessageAllocator< ::grpc::testing::Request, ::grpc::testing::Response>* allocator) { - static_cast<::grpc::internal::CallbackUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>*>( + static_cast<::grpc_impl::internal::CallbackUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>*>( ::grpc::Service::experimental().GetHandler(0)) ->SetMessageAllocator(allocator); } @@ -883,7 +884,7 @@ class ServiceB final { public: ExperimentalWithRawCallbackMethod_MethodB1() { ::grpc::Service::experimental().MarkMethodRawCallback(0, - new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( + new ::grpc_impl::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this](::grpc::ServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response, diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++ index 501be844410..bdb36ae1a7b 100644 --- a/tools/doxygen/Doxyfile.c++ +++ b/tools/doxygen/Doxyfile.c++ @@ -947,7 +947,9 @@ include/grpcpp/impl/channel_argument_option.h \ include/grpcpp/impl/client_unary_call.h \ include/grpcpp/impl/codegen/async_generic_service.h \ include/grpcpp/impl/codegen/async_stream.h \ +include/grpcpp/impl/codegen/async_stream_impl.h \ include/grpcpp/impl/codegen/async_unary_call.h \ +include/grpcpp/impl/codegen/async_unary_call_impl.h \ include/grpcpp/impl/codegen/byte_buffer.h \ include/grpcpp/impl/codegen/call.h \ include/grpcpp/impl/codegen/call_hook.h \ @@ -956,6 +958,7 @@ include/grpcpp/impl/codegen/call_op_set_interface.h \ include/grpcpp/impl/codegen/callback_common.h \ include/grpcpp/impl/codegen/channel_interface.h \ include/grpcpp/impl/codegen/client_callback.h \ +include/grpcpp/impl/codegen/client_callback_impl.h \ include/grpcpp/impl/codegen/client_context.h \ include/grpcpp/impl/codegen/client_context_impl.h \ include/grpcpp/impl/codegen/client_interceptor.h \ @@ -983,6 +986,7 @@ include/grpcpp/impl/codegen/rpc_service_method.h \ include/grpcpp/impl/codegen/security/auth_context.h \ include/grpcpp/impl/codegen/serialization_traits.h \ include/grpcpp/impl/codegen/server_callback.h \ +include/grpcpp/impl/codegen/server_callback_impl.h \ include/grpcpp/impl/codegen/server_context.h \ include/grpcpp/impl/codegen/server_context_impl.h \ include/grpcpp/impl/codegen/server_interceptor.h \ @@ -995,6 +999,7 @@ include/grpcpp/impl/codegen/string_ref.h \ include/grpcpp/impl/codegen/stub_options.h \ include/grpcpp/impl/codegen/sync.h \ include/grpcpp/impl/codegen/sync_stream.h \ +include/grpcpp/impl/codegen/sync_stream_impl.h \ include/grpcpp/impl/codegen/time.h \ include/grpcpp/impl/grpc_library.h \ include/grpcpp/impl/method_handler_impl.h \ @@ -1024,11 +1029,14 @@ include/grpcpp/server_impl.h \ include/grpcpp/server_posix.h \ include/grpcpp/server_posix_impl.h \ include/grpcpp/support/async_stream.h \ +include/grpcpp/support/async_stream_impl.h \ include/grpcpp/support/async_unary_call.h \ +include/grpcpp/support/async_unary_call_impl.h \ include/grpcpp/support/byte_buffer.h \ include/grpcpp/support/channel_arguments.h \ include/grpcpp/support/channel_arguments_impl.h \ include/grpcpp/support/client_callback.h \ +include/grpcpp/support/client_callback_impl.h \ include/grpcpp/support/client_interceptor.h \ include/grpcpp/support/config.h \ include/grpcpp/support/interceptor.h \ @@ -1036,6 +1044,7 @@ 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 \ +include/grpcpp/support/server_callback_impl.h \ include/grpcpp/support/server_interceptor.h \ include/grpcpp/support/slice.h \ include/grpcpp/support/status.h \ @@ -1043,6 +1052,7 @@ include/grpcpp/support/status_code_enum.h \ include/grpcpp/support/string_ref.h \ include/grpcpp/support/stub_options.h \ include/grpcpp/support/sync_stream.h \ +include/grpcpp/support/sync_stream_impl.h \ include/grpcpp/support/time.h \ include/grpcpp/support/validate_service_config.h diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 69ff7eb6098..57d6ca8b761 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -948,7 +948,9 @@ include/grpcpp/impl/channel_argument_option.h \ include/grpcpp/impl/client_unary_call.h \ include/grpcpp/impl/codegen/async_generic_service.h \ include/grpcpp/impl/codegen/async_stream.h \ +include/grpcpp/impl/codegen/async_stream_impl.h \ include/grpcpp/impl/codegen/async_unary_call.h \ +include/grpcpp/impl/codegen/async_unary_call_impl.h \ include/grpcpp/impl/codegen/byte_buffer.h \ include/grpcpp/impl/codegen/call.h \ include/grpcpp/impl/codegen/call_hook.h \ @@ -957,6 +959,7 @@ include/grpcpp/impl/codegen/call_op_set_interface.h \ include/grpcpp/impl/codegen/callback_common.h \ include/grpcpp/impl/codegen/channel_interface.h \ include/grpcpp/impl/codegen/client_callback.h \ +include/grpcpp/impl/codegen/client_callback_impl.h \ include/grpcpp/impl/codegen/client_context.h \ include/grpcpp/impl/codegen/client_context_impl.h \ include/grpcpp/impl/codegen/client_interceptor.h \ @@ -985,6 +988,7 @@ include/grpcpp/impl/codegen/rpc_service_method.h \ include/grpcpp/impl/codegen/security/auth_context.h \ include/grpcpp/impl/codegen/serialization_traits.h \ include/grpcpp/impl/codegen/server_callback.h \ +include/grpcpp/impl/codegen/server_callback_impl.h \ include/grpcpp/impl/codegen/server_context.h \ include/grpcpp/impl/codegen/server_context_impl.h \ include/grpcpp/impl/codegen/server_interceptor.h \ @@ -997,6 +1001,7 @@ include/grpcpp/impl/codegen/string_ref.h \ include/grpcpp/impl/codegen/stub_options.h \ include/grpcpp/impl/codegen/sync.h \ include/grpcpp/impl/codegen/sync_stream.h \ +include/grpcpp/impl/codegen/sync_stream_impl.h \ include/grpcpp/impl/codegen/time.h \ include/grpcpp/impl/grpc_library.h \ include/grpcpp/impl/method_handler_impl.h \ @@ -1026,11 +1031,14 @@ include/grpcpp/server_impl.h \ include/grpcpp/server_posix.h \ include/grpcpp/server_posix_impl.h \ include/grpcpp/support/async_stream.h \ +include/grpcpp/support/async_stream_impl.h \ include/grpcpp/support/async_unary_call.h \ +include/grpcpp/support/async_unary_call_impl.h \ include/grpcpp/support/byte_buffer.h \ include/grpcpp/support/channel_arguments.h \ include/grpcpp/support/channel_arguments_impl.h \ include/grpcpp/support/client_callback.h \ +include/grpcpp/support/client_callback_impl.h \ include/grpcpp/support/client_interceptor.h \ include/grpcpp/support/config.h \ include/grpcpp/support/interceptor.h \ @@ -1038,6 +1046,7 @@ 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 \ +include/grpcpp/support/server_callback_impl.h \ include/grpcpp/support/server_interceptor.h \ include/grpcpp/support/slice.h \ include/grpcpp/support/status.h \ @@ -1045,6 +1054,7 @@ include/grpcpp/support/status_code_enum.h \ include/grpcpp/support/string_ref.h \ include/grpcpp/support/stub_options.h \ include/grpcpp/support/sync_stream.h \ +include/grpcpp/support/sync_stream_impl.h \ include/grpcpp/support/time.h \ include/grpcpp/support/validate_service_config.h \ src/core/ext/filters/client_channel/health/health.pb.c \ diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index e638e305af8..fd8037cf3a3 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -10190,7 +10190,9 @@ "include/grpc++/impl/codegen/time.h", "include/grpcpp/impl/codegen/async_generic_service.h", "include/grpcpp/impl/codegen/async_stream.h", + "include/grpcpp/impl/codegen/async_stream_impl.h", "include/grpcpp/impl/codegen/async_unary_call.h", + "include/grpcpp/impl/codegen/async_unary_call_impl.h", "include/grpcpp/impl/codegen/byte_buffer.h", "include/grpcpp/impl/codegen/call.h", "include/grpcpp/impl/codegen/call_hook.h", @@ -10199,6 +10201,7 @@ "include/grpcpp/impl/codegen/callback_common.h", "include/grpcpp/impl/codegen/channel_interface.h", "include/grpcpp/impl/codegen/client_callback.h", + "include/grpcpp/impl/codegen/client_callback_impl.h", "include/grpcpp/impl/codegen/client_context.h", "include/grpcpp/impl/codegen/client_context_impl.h", "include/grpcpp/impl/codegen/client_interceptor.h", @@ -10221,6 +10224,7 @@ "include/grpcpp/impl/codegen/security/auth_context.h", "include/grpcpp/impl/codegen/serialization_traits.h", "include/grpcpp/impl/codegen/server_callback.h", + "include/grpcpp/impl/codegen/server_callback_impl.h", "include/grpcpp/impl/codegen/server_context.h", "include/grpcpp/impl/codegen/server_context_impl.h", "include/grpcpp/impl/codegen/server_interceptor.h", @@ -10232,6 +10236,7 @@ "include/grpcpp/impl/codegen/string_ref.h", "include/grpcpp/impl/codegen/stub_options.h", "include/grpcpp/impl/codegen/sync_stream.h", + "include/grpcpp/impl/codegen/sync_stream_impl.h", "include/grpcpp/impl/codegen/time.h" ], "is_filegroup": true, @@ -10270,7 +10275,9 @@ "include/grpc++/impl/codegen/time.h", "include/grpcpp/impl/codegen/async_generic_service.h", "include/grpcpp/impl/codegen/async_stream.h", + "include/grpcpp/impl/codegen/async_stream_impl.h", "include/grpcpp/impl/codegen/async_unary_call.h", + "include/grpcpp/impl/codegen/async_unary_call_impl.h", "include/grpcpp/impl/codegen/byte_buffer.h", "include/grpcpp/impl/codegen/call.h", "include/grpcpp/impl/codegen/call_hook.h", @@ -10279,6 +10286,7 @@ "include/grpcpp/impl/codegen/callback_common.h", "include/grpcpp/impl/codegen/channel_interface.h", "include/grpcpp/impl/codegen/client_callback.h", + "include/grpcpp/impl/codegen/client_callback_impl.h", "include/grpcpp/impl/codegen/client_context.h", "include/grpcpp/impl/codegen/client_context_impl.h", "include/grpcpp/impl/codegen/client_interceptor.h", @@ -10301,6 +10309,7 @@ "include/grpcpp/impl/codegen/security/auth_context.h", "include/grpcpp/impl/codegen/serialization_traits.h", "include/grpcpp/impl/codegen/server_callback.h", + "include/grpcpp/impl/codegen/server_callback_impl.h", "include/grpcpp/impl/codegen/server_context.h", "include/grpcpp/impl/codegen/server_context_impl.h", "include/grpcpp/impl/codegen/server_interceptor.h", @@ -10312,6 +10321,7 @@ "include/grpcpp/impl/codegen/string_ref.h", "include/grpcpp/impl/codegen/stub_options.h", "include/grpcpp/impl/codegen/sync_stream.h", + "include/grpcpp/impl/codegen/sync_stream_impl.h", "include/grpcpp/impl/codegen/time.h" ], "third_party": false, @@ -10461,11 +10471,14 @@ "include/grpcpp/server_posix.h", "include/grpcpp/server_posix_impl.h", "include/grpcpp/support/async_stream.h", + "include/grpcpp/support/async_stream_impl.h", "include/grpcpp/support/async_unary_call.h", + "include/grpcpp/support/async_unary_call_impl.h", "include/grpcpp/support/byte_buffer.h", "include/grpcpp/support/channel_arguments.h", "include/grpcpp/support/channel_arguments_impl.h", "include/grpcpp/support/client_callback.h", + "include/grpcpp/support/client_callback_impl.h", "include/grpcpp/support/client_interceptor.h", "include/grpcpp/support/config.h", "include/grpcpp/support/interceptor.h", @@ -10473,6 +10486,7 @@ "include/grpcpp/support/proto_buffer_reader.h", "include/grpcpp/support/proto_buffer_writer.h", "include/grpcpp/support/server_callback.h", + "include/grpcpp/support/server_callback_impl.h", "include/grpcpp/support/server_interceptor.h", "include/grpcpp/support/slice.h", "include/grpcpp/support/status.h", @@ -10480,6 +10494,7 @@ "include/grpcpp/support/string_ref.h", "include/grpcpp/support/stub_options.h", "include/grpcpp/support/sync_stream.h", + "include/grpcpp/support/sync_stream_impl.h", "include/grpcpp/support/time.h", "include/grpcpp/support/validate_service_config.h", "src/cpp/client/create_channel_internal.h", @@ -10589,11 +10604,14 @@ "include/grpcpp/server_posix.h", "include/grpcpp/server_posix_impl.h", "include/grpcpp/support/async_stream.h", + "include/grpcpp/support/async_stream_impl.h", "include/grpcpp/support/async_unary_call.h", + "include/grpcpp/support/async_unary_call_impl.h", "include/grpcpp/support/byte_buffer.h", "include/grpcpp/support/channel_arguments.h", "include/grpcpp/support/channel_arguments_impl.h", "include/grpcpp/support/client_callback.h", + "include/grpcpp/support/client_callback_impl.h", "include/grpcpp/support/client_interceptor.h", "include/grpcpp/support/config.h", "include/grpcpp/support/interceptor.h", @@ -10601,6 +10619,7 @@ "include/grpcpp/support/proto_buffer_reader.h", "include/grpcpp/support/proto_buffer_writer.h", "include/grpcpp/support/server_callback.h", + "include/grpcpp/support/server_callback_impl.h", "include/grpcpp/support/server_interceptor.h", "include/grpcpp/support/slice.h", "include/grpcpp/support/status.h", @@ -10608,6 +10627,7 @@ "include/grpcpp/support/string_ref.h", "include/grpcpp/support/stub_options.h", "include/grpcpp/support/sync_stream.h", + "include/grpcpp/support/sync_stream_impl.h", "include/grpcpp/support/time.h", "include/grpcpp/support/validate_service_config.h", "src/cpp/client/channel_cc.cc", From d8c01823606f5ff1597b3316183c01ceef57c49a Mon Sep 17 00:00:00 2001 From: Moiz Haidry Date: Tue, 2 Jul 2019 12:32:14 -0700 Subject: [PATCH 3/4] Expose some of the internal codegen interfaces --- include/grpcpp/impl/codegen/async_stream.h | 30 ++++++++++++++ .../grpcpp/impl/codegen/async_unary_call.h | 10 +++++ include/grpcpp/impl/codegen/client_callback.h | 12 ++++++ include/grpcpp/impl/codegen/sync_stream.h | 39 +++++++++++++++++++ third_party/googletest | 2 +- third_party/protobuf | 2 +- 6 files changed, 93 insertions(+), 2 deletions(-) diff --git a/include/grpcpp/impl/codegen/async_stream.h b/include/grpcpp/impl/codegen/async_stream.h index 14dfe67962e..d76a8982a4b 100644 --- a/include/grpcpp/impl/codegen/async_stream.h +++ b/include/grpcpp/impl/codegen/async_stream.h @@ -22,6 +22,20 @@ #include namespace grpc { + +namespace internal { + +typedef ::grpc_impl::internal::ClientAsyncStreamingInterface + ClientAsyncStreamingInterface; + +template +using AsyncReaderInterface = ::grpc_impl::internal::AsyncReaderInterface; + +template +using AsyncWriterInterface = ::grpc_impl::internal::AsyncWriterInterface; + +} // namespace internal + template using ClientAsyncReaderInterface = ::grpc_impl::ClientAsyncReaderInterface; @@ -60,6 +74,22 @@ using ServerAsyncReaderWriterInterface = template using ServerAsyncReaderWriter = ::grpc_impl::ServerAsyncReaderWriter; + +namespace internal { +template +using ClientAsyncReaderFactory = + ::grpc_impl::internal::ClientAsyncReaderFactory; + +template +using ClientAsyncWriterFactory = + ::grpc_impl::internal::ClientAsyncWriterFactory; + +template +using ClientAsyncReaderWriterFactory = + ::grpc_impl::internal::ClientAsyncReaderWriterFactory; + +} // namespace internal + } // namespace grpc #endif // GRPCPP_IMPL_CODEGEN_ASYNC_STREAM_H diff --git a/include/grpcpp/impl/codegen/async_unary_call.h b/include/grpcpp/impl/codegen/async_unary_call.h index 64ee17dec0d..cbbe70172c8 100644 --- a/include/grpcpp/impl/codegen/async_unary_call.h +++ b/include/grpcpp/impl/codegen/async_unary_call.h @@ -22,15 +22,25 @@ #include namespace grpc { + template using ClientAsyncResponseReaderInterface = grpc_impl::ClientAsyncResponseReaderInterface; + template using ClientAsyncResponseReader = grpc_impl::ClientAsyncResponseReader; template using ServerAsyncResponseWriter = ::grpc_impl::ServerAsyncResponseWriter; +namespace internal { + +template +using ClientAsyncResponseReaderFactory = + ::grpc_impl::internal::ClientAsyncResponseReaderFactory; + +} // namespace internal + } // namespace grpc #endif // GRPCPP_IMPL_CODEGEN_ASYNC_UNARY_CALL_H diff --git a/include/grpcpp/impl/codegen/client_callback.h b/include/grpcpp/impl/codegen/client_callback.h index 4f60741624a..9d183725b57 100644 --- a/include/grpcpp/impl/codegen/client_callback.h +++ b/include/grpcpp/impl/codegen/client_callback.h @@ -24,6 +24,18 @@ namespace grpc { namespace experimental { +template +using ClientCallbackReader = + ::grpc_impl::experimental::ClientCallbackReader; + +template +using ClientCallbackWriter = + ::grpc_impl::experimental::ClientCallbackWriter; + +template +using ClientCallbackReaderWriter = + ::grpc_impl::experimental::ClientCallbackReaderWriter; + template using ClientReadReactor = ::grpc_impl::experimental::ClientReadReactor; diff --git a/include/grpcpp/impl/codegen/sync_stream.h b/include/grpcpp/impl/codegen/sync_stream.h index cd447d7c5a5..852fe6676bf 100644 --- a/include/grpcpp/impl/codegen/sync_stream.h +++ b/include/grpcpp/impl/codegen/sync_stream.h @@ -22,36 +22,75 @@ #include namespace grpc { + +namespace internal { + +typedef ::grpc_impl::internal::ClientStreamingInterface + ClientStreamingInterface; + +typedef ::grpc_impl::internal::ServerStreamingInterface + ServerStreamingInterface; + +template +using ReaderInterface = ::grpc_impl::internal::ReaderInterface; + +template +using WriterInterface = ::grpc_impl::internal::WriterInterface; + +template +using ClientReaderFactory = ::grpc_impl::internal::ClientReaderFactory; + +template +using ClientWriterFactory = ::grpc_impl::internal::ClientWriterFactory; + +template +using ClientReaderWriterFactory = + ::grpc_impl::internal::ClientReaderWriterFactory; + +} // namespace internal + template using ClientReaderInterface = ::grpc_impl::ClientReaderInterface; template using ClientReader = ::grpc_impl::ClientReader; + template using ClientWriterInterface = ::grpc_impl::ClientWriterInterface; + template using ClientWriter = ::grpc_impl::ClientWriter; + template using ClientReaderWriterInterface = ::grpc_impl::ClientReaderWriterInterface; + template using ClientReaderWriter = ::grpc_impl::ClientReaderWriter; + template using ServerReaderInterface = ::grpc_impl::ServerReaderInterface; + template using ServerReader = ::grpc_impl::ServerReader; + template using ServerWriterInterface = ::grpc_impl::ServerWriterInterface; + template using ServerWriter = ::grpc_impl::ServerWriter; + template using ServerReaderWriterInterface = ::grpc_impl::ServerReaderWriterInterface; + template using ServerReaderWriter = ::grpc_impl::ServerReaderWriter; + template using ServerUnaryStreamer = ::grpc_impl::ServerUnaryStreamer; + template using ServerSplitStreamer = ::grpc_impl::ServerSplitStreamer; diff --git a/third_party/googletest b/third_party/googletest index 2fe3bd994b3..ec44c6c1675 160000 --- a/third_party/googletest +++ b/third_party/googletest @@ -1 +1 @@ -Subproject commit 2fe3bd994b3189899d93f1d5a881e725e046fdc2 +Subproject commit ec44c6c1675c25b9827aacd08c02433cccde7780 diff --git a/third_party/protobuf b/third_party/protobuf index 09745575a92..582743bf40c 160000 --- a/third_party/protobuf +++ b/third_party/protobuf @@ -1 +1 @@ -Subproject commit 09745575a923640154bcf307fba8aedff47f240a +Subproject commit 582743bf40c5d3639a70f98f183914a2c0cd0680 From 5f55921b088b07af2348a894550874841a7a9b18 Mon Sep 17 00:00:00 2001 From: Moiz Haidry Date: Tue, 2 Jul 2019 12:37:08 -0700 Subject: [PATCH 4/4] Remove third_party --- third_party/googletest | 2 +- third_party/protobuf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/third_party/googletest b/third_party/googletest index ec44c6c1675..2fe3bd994b3 160000 --- a/third_party/googletest +++ b/third_party/googletest @@ -1 +1 @@ -Subproject commit ec44c6c1675c25b9827aacd08c02433cccde7780 +Subproject commit 2fe3bd994b3189899d93f1d5a881e725e046fdc2 diff --git a/third_party/protobuf b/third_party/protobuf index 582743bf40c..09745575a92 160000 --- a/third_party/protobuf +++ b/third_party/protobuf @@ -1 +1 @@ -Subproject commit 582743bf40c5d3639a70f98f183914a2c0cd0680 +Subproject commit 09745575a923640154bcf307fba8aedff47f240a