Merge remote-tracking branch 'upstream/master' into fake_handshaker

pull/16648/head
Lizan Zhou 6 years ago
commit 91e15f65dc
  1. 3
      BUILD
  2. 9
      CMakeLists.txt
  3. 10
      Makefile
  4. 4
      build.yaml
  5. 1
      config.m4
  6. 1
      config.w32
  7. 2
      gRPC-C++.podspec
  8. 3
      gRPC-Core.podspec
  9. 2
      grpc.gemspec
  10. 6
      grpc.gyp
  11. 3
      include/grpc/grpc.h
  12. 4
      include/grpc/grpc_security.h
  13. 15
      include/grpc/impl/codegen/grpc_types.h
  14. 27
      include/grpcpp/alarm.h
  15. 93
      include/grpcpp/impl/codegen/callback_common.h
  16. 2
      include/grpcpp/impl/codegen/client_callback.h
  17. 2
      package.xml
  18. 148
      src/compiler/cpp_generator.cc
  19. 6
      src/core/ext/filters/client_channel/subchannel_index.cc
  20. 17
      src/core/ext/transport/chttp2/transport/hpack_encoder.cc
  21. 39
      src/core/ext/transport/chttp2/transport/hpack_mapping.cc
  22. 38
      src/core/ext/transport/chttp2/transport/hpack_mapping.h
  23. 29
      src/core/ext/transport/chttp2/transport/hpack_table.cc
  24. 9
      src/core/ext/transport/chttp2/transport/hpack_table.h
  25. 133
      src/core/ext/transport/chttp2/transport/parsing.cc
  26. 3
      src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc
  27. 3
      src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc
  28. 34
      src/core/lib/surface/completion_queue.cc
  29. 19
      src/core/lib/surface/completion_queue.h
  30. 6
      src/core/lib/surface/completion_queue_factory.cc
  31. 18
      src/core/lib/transport/metadata.cc
  32. 3
      src/core/lib/transport/metadata.h
  33. 4
      src/core/lib/transport/metadata_batch.cc
  34. 2
      src/core/lib/transport/metadata_batch.h
  35. 27
      src/core/lib/transport/static_metadata.cc
  36. 2
      src/core/lib/transport/static_metadata.h
  37. 10
      src/cpp/client/channel_cc.cc
  38. 47
      src/cpp/common/alarm.cc
  39. 149
      src/cpp/common/callback_common.cc
  40. 1
      src/python/grpcio/grpc_core_dependencies.py
  41. 6
      src/ruby/ext/grpc/rb_grpc_imports.generated.h
  42. 6
      src/ruby/lib/grpc/generic/rpc_desc.rb
  43. 10
      src/ruby/spec/client_auth_spec.rb
  44. 22
      src/ruby/spec/generic/client_stub_spec.rb
  45. 6
      src/ruby/spec/generic/rpc_server_spec.rb
  46. 50
      src/ruby/spec/support/services.rb
  47. 31
      test/core/end2end/inproc_callback_test.cc
  48. 25
      test/core/surface/completion_queue_test.cc
  49. 2
      test/core/transport/chttp2/hpack_encoder_test.cc
  50. 5
      test/core/transport/metadata_test.cc
  51. 50
      test/cpp/codegen/compiler_test_golden
  52. 106
      test/cpp/common/alarm_test.cc
  53. 2
      test/cpp/end2end/async_end2end_test.cc
  54. 113
      test/cpp/end2end/client_callback_end2end_test.cc
  55. 41
      test/cpp/end2end/client_lb_end2end_test.cc
  56. 74
      test/cpp/microbenchmarks/bm_chttp2_hpack.cc
  57. 1
      test/cpp/microbenchmarks/fullstack_fixtures.h
  58. 1
      test/cpp/microbenchmarks/helpers.h
  59. 279
      tools/codegen/core/gen_static_metadata.py
  60. 1
      tools/doxygen/Doxyfile.c++.internal
  61. 2
      tools/doxygen/Doxyfile.core.internal
  62. 4
      tools/run_tests/generated/sources_and_headers.json

@ -119,7 +119,6 @@ GRPCXX_SRCS = [
"src/cpp/client/credentials_cc.cc",
"src/cpp/client/generic_stub.cc",
"src/cpp/common/alarm.cc",
"src/cpp/common/callback_common.cc",
"src/cpp/common/channel_arguments.cc",
"src/cpp/common/channel_filter.cc",
"src/cpp/common/completion_queue_cc.cc",
@ -1575,6 +1574,7 @@ grpc_cc_library(
"src/core/ext/transport/chttp2/transport/frame_window_update.cc",
"src/core/ext/transport/chttp2/transport/hpack_encoder.cc",
"src/core/ext/transport/chttp2/transport/hpack_parser.cc",
"src/core/ext/transport/chttp2/transport/hpack_mapping.cc",
"src/core/ext/transport/chttp2/transport/hpack_table.cc",
"src/core/ext/transport/chttp2/transport/http2_settings.cc",
"src/core/ext/transport/chttp2/transport/huffsyms.cc",
@ -1599,6 +1599,7 @@ grpc_cc_library(
"src/core/ext/transport/chttp2/transport/frame_window_update.h",
"src/core/ext/transport/chttp2/transport/hpack_encoder.h",
"src/core/ext/transport/chttp2/transport/hpack_parser.h",
"src/core/ext/transport/chttp2/transport/hpack_mapping.h",
"src/core/ext/transport/chttp2/transport/hpack_table.h",
"src/core/ext/transport/chttp2/transport/http2_settings.h",
"src/core/ext/transport/chttp2/transport/huffsyms.h",

@ -1105,6 +1105,7 @@ add_library(grpc
src/core/ext/transport/chttp2/transport/frame_settings.cc
src/core/ext/transport/chttp2/transport/frame_window_update.cc
src/core/ext/transport/chttp2/transport/hpack_encoder.cc
src/core/ext/transport/chttp2/transport/hpack_mapping.cc
src/core/ext/transport/chttp2/transport/hpack_parser.cc
src/core/ext/transport/chttp2/transport/hpack_table.cc
src/core/ext/transport/chttp2/transport/http2_settings.cc
@ -1516,6 +1517,7 @@ add_library(grpc_cronet
src/core/ext/transport/chttp2/transport/frame_settings.cc
src/core/ext/transport/chttp2/transport/frame_window_update.cc
src/core/ext/transport/chttp2/transport/hpack_encoder.cc
src/core/ext/transport/chttp2/transport/hpack_mapping.cc
src/core/ext/transport/chttp2/transport/hpack_parser.cc
src/core/ext/transport/chttp2/transport/hpack_table.cc
src/core/ext/transport/chttp2/transport/http2_settings.cc
@ -1929,6 +1931,7 @@ add_library(grpc_test_util
src/core/ext/transport/chttp2/transport/frame_settings.cc
src/core/ext/transport/chttp2/transport/frame_window_update.cc
src/core/ext/transport/chttp2/transport/hpack_encoder.cc
src/core/ext/transport/chttp2/transport/hpack_mapping.cc
src/core/ext/transport/chttp2/transport/hpack_parser.cc
src/core/ext/transport/chttp2/transport/hpack_table.cc
src/core/ext/transport/chttp2/transport/http2_settings.cc
@ -2239,6 +2242,7 @@ add_library(grpc_test_util_unsecure
src/core/ext/transport/chttp2/transport/frame_settings.cc
src/core/ext/transport/chttp2/transport/frame_window_update.cc
src/core/ext/transport/chttp2/transport/hpack_encoder.cc
src/core/ext/transport/chttp2/transport/hpack_mapping.cc
src/core/ext/transport/chttp2/transport/hpack_parser.cc
src/core/ext/transport/chttp2/transport/hpack_table.cc
src/core/ext/transport/chttp2/transport/http2_settings.cc
@ -2507,6 +2511,7 @@ add_library(grpc_unsecure
src/core/ext/transport/chttp2/transport/frame_settings.cc
src/core/ext/transport/chttp2/transport/frame_window_update.cc
src/core/ext/transport/chttp2/transport/hpack_encoder.cc
src/core/ext/transport/chttp2/transport/hpack_mapping.cc
src/core/ext/transport/chttp2/transport/hpack_parser.cc
src/core/ext/transport/chttp2/transport/hpack_table.cc
src/core/ext/transport/chttp2/transport/http2_settings.cc
@ -2773,7 +2778,6 @@ add_library(grpc++
src/cpp/client/credentials_cc.cc
src/cpp/client/generic_stub.cc
src/cpp/common/alarm.cc
src/cpp/common/callback_common.cc
src/cpp/common/channel_arguments.cc
src/cpp/common/channel_filter.cc
src/cpp/common/completion_queue_cc.cc
@ -3135,7 +3139,6 @@ add_library(grpc++_cronet
src/cpp/client/credentials_cc.cc
src/cpp/client/generic_stub.cc
src/cpp/common/alarm.cc
src/cpp/common/callback_common.cc
src/cpp/common/channel_arguments.cc
src/cpp/common/channel_filter.cc
src/cpp/common/completion_queue_cc.cc
@ -3178,6 +3181,7 @@ add_library(grpc++_cronet
src/core/ext/transport/chttp2/transport/frame_settings.cc
src/core/ext/transport/chttp2/transport/frame_window_update.cc
src/core/ext/transport/chttp2/transport/hpack_encoder.cc
src/core/ext/transport/chttp2/transport/hpack_mapping.cc
src/core/ext/transport/chttp2/transport/hpack_parser.cc
src/core/ext/transport/chttp2/transport/hpack_table.cc
src/core/ext/transport/chttp2/transport/http2_settings.cc
@ -4261,7 +4265,6 @@ add_library(grpc++_unsecure
src/cpp/client/credentials_cc.cc
src/cpp/client/generic_stub.cc
src/cpp/common/alarm.cc
src/cpp/common/callback_common.cc
src/cpp/common/channel_arguments.cc
src/cpp/common/channel_filter.cc
src/cpp/common/completion_queue_cc.cc

@ -352,6 +352,7 @@ CXXFLAGS += -std=c++11
ifeq ($(SYSTEM),Darwin)
CXXFLAGS += -stdlib=libc++
endif
CXXFLAGS += -Wnon-virtual-dtor
CPPFLAGS += -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter -DOSATOMIC_USE_INLINED=1 -Wno-deprecated-declarations -Ithird_party/nanopb -DPB_FIELD_32BIT
COREFLAGS += -fno-rtti -fno-exceptions
LDFLAGS += -g
@ -3614,6 +3615,7 @@ LIBGRPC_SRC = \
src/core/ext/transport/chttp2/transport/frame_settings.cc \
src/core/ext/transport/chttp2/transport/frame_window_update.cc \
src/core/ext/transport/chttp2/transport/hpack_encoder.cc \
src/core/ext/transport/chttp2/transport/hpack_mapping.cc \
src/core/ext/transport/chttp2/transport/hpack_parser.cc \
src/core/ext/transport/chttp2/transport/hpack_table.cc \
src/core/ext/transport/chttp2/transport/http2_settings.cc \
@ -4024,6 +4026,7 @@ LIBGRPC_CRONET_SRC = \
src/core/ext/transport/chttp2/transport/frame_settings.cc \
src/core/ext/transport/chttp2/transport/frame_window_update.cc \
src/core/ext/transport/chttp2/transport/hpack_encoder.cc \
src/core/ext/transport/chttp2/transport/hpack_mapping.cc \
src/core/ext/transport/chttp2/transport/hpack_parser.cc \
src/core/ext/transport/chttp2/transport/hpack_table.cc \
src/core/ext/transport/chttp2/transport/http2_settings.cc \
@ -4435,6 +4438,7 @@ LIBGRPC_TEST_UTIL_SRC = \
src/core/ext/transport/chttp2/transport/frame_settings.cc \
src/core/ext/transport/chttp2/transport/frame_window_update.cc \
src/core/ext/transport/chttp2/transport/hpack_encoder.cc \
src/core/ext/transport/chttp2/transport/hpack_mapping.cc \
src/core/ext/transport/chttp2/transport/hpack_parser.cc \
src/core/ext/transport/chttp2/transport/hpack_table.cc \
src/core/ext/transport/chttp2/transport/http2_settings.cc \
@ -4736,6 +4740,7 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \
src/core/ext/transport/chttp2/transport/frame_settings.cc \
src/core/ext/transport/chttp2/transport/frame_window_update.cc \
src/core/ext/transport/chttp2/transport/hpack_encoder.cc \
src/core/ext/transport/chttp2/transport/hpack_mapping.cc \
src/core/ext/transport/chttp2/transport/hpack_parser.cc \
src/core/ext/transport/chttp2/transport/hpack_table.cc \
src/core/ext/transport/chttp2/transport/http2_settings.cc \
@ -4982,6 +4987,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/ext/transport/chttp2/transport/frame_settings.cc \
src/core/ext/transport/chttp2/transport/frame_window_update.cc \
src/core/ext/transport/chttp2/transport/hpack_encoder.cc \
src/core/ext/transport/chttp2/transport/hpack_mapping.cc \
src/core/ext/transport/chttp2/transport/hpack_parser.cc \
src/core/ext/transport/chttp2/transport/hpack_table.cc \
src/core/ext/transport/chttp2/transport/http2_settings.cc \
@ -5228,7 +5234,6 @@ LIBGRPC++_SRC = \
src/cpp/client/credentials_cc.cc \
src/cpp/client/generic_stub.cc \
src/cpp/common/alarm.cc \
src/cpp/common/callback_common.cc \
src/cpp/common/channel_arguments.cc \
src/cpp/common/channel_filter.cc \
src/cpp/common/completion_queue_cc.cc \
@ -5598,7 +5603,6 @@ LIBGRPC++_CRONET_SRC = \
src/cpp/client/credentials_cc.cc \
src/cpp/client/generic_stub.cc \
src/cpp/common/alarm.cc \
src/cpp/common/callback_common.cc \
src/cpp/common/channel_arguments.cc \
src/cpp/common/channel_filter.cc \
src/cpp/common/completion_queue_cc.cc \
@ -5641,6 +5645,7 @@ LIBGRPC++_CRONET_SRC = \
src/core/ext/transport/chttp2/transport/frame_settings.cc \
src/core/ext/transport/chttp2/transport/frame_window_update.cc \
src/core/ext/transport/chttp2/transport/hpack_encoder.cc \
src/core/ext/transport/chttp2/transport/hpack_mapping.cc \
src/core/ext/transport/chttp2/transport/hpack_parser.cc \
src/core/ext/transport/chttp2/transport/hpack_table.cc \
src/core/ext/transport/chttp2/transport/http2_settings.cc \
@ -6682,7 +6687,6 @@ LIBGRPC++_UNSECURE_SRC = \
src/cpp/client/credentials_cc.cc \
src/cpp/client/generic_stub.cc \
src/cpp/common/alarm.cc \
src/cpp/common/callback_common.cc \
src/cpp/common/channel_arguments.cc \
src/cpp/common/channel_filter.cc \
src/cpp/common/completion_queue_cc.cc \

@ -936,6 +936,7 @@ filegroups:
- src/core/ext/transport/chttp2/transport/frame_settings.h
- src/core/ext/transport/chttp2/transport/frame_window_update.h
- src/core/ext/transport/chttp2/transport/hpack_encoder.h
- src/core/ext/transport/chttp2/transport/hpack_mapping.h
- src/core/ext/transport/chttp2/transport/hpack_parser.h
- src/core/ext/transport/chttp2/transport/hpack_table.h
- src/core/ext/transport/chttp2/transport/http2_settings.h
@ -957,6 +958,7 @@ filegroups:
- src/core/ext/transport/chttp2/transport/frame_settings.cc
- src/core/ext/transport/chttp2/transport/frame_window_update.cc
- src/core/ext/transport/chttp2/transport/hpack_encoder.cc
- src/core/ext/transport/chttp2/transport/hpack_mapping.cc
- src/core/ext/transport/chttp2/transport/hpack_parser.cc
- src/core/ext/transport/chttp2/transport/hpack_table.cc
- src/core/ext/transport/chttp2/transport/http2_settings.cc
@ -1327,7 +1329,6 @@ filegroups:
- src/cpp/client/credentials_cc.cc
- src/cpp/client/generic_stub.cc
- src/cpp/common/alarm.cc
- src/cpp/common/callback_common.cc
- src/cpp/common/channel_arguments.cc
- src/cpp/common/channel_filter.cc
- src/cpp/common/completion_queue_cc.cc
@ -5859,6 +5860,7 @@ defaults:
COREFLAGS: -fno-rtti -fno-exceptions
CPPFLAGS: -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter -DOSATOMIC_USE_INLINED=1
-Wno-deprecated-declarations -Ithird_party/nanopb -DPB_FIELD_32BIT
CXXFLAGS: -Wnon-virtual-dtor
LDFLAGS: -g
zlib:
CFLAGS: -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-implicit-function-declaration

@ -249,6 +249,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/transport/chttp2/transport/frame_settings.cc \
src/core/ext/transport/chttp2/transport/frame_window_update.cc \
src/core/ext/transport/chttp2/transport/hpack_encoder.cc \
src/core/ext/transport/chttp2/transport/hpack_mapping.cc \
src/core/ext/transport/chttp2/transport/hpack_parser.cc \
src/core/ext/transport/chttp2/transport/hpack_table.cc \
src/core/ext/transport/chttp2/transport/http2_settings.cc \

@ -224,6 +224,7 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\transport\\chttp2\\transport\\frame_settings.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\frame_window_update.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\hpack_encoder.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\hpack_mapping.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\hpack_parser.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\hpack_table.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\http2_settings.cc " +

@ -190,7 +190,6 @@ Pod::Spec.new do |s|
'src/cpp/client/credentials_cc.cc',
'src/cpp/client/generic_stub.cc',
'src/cpp/common/alarm.cc',
'src/cpp/common/callback_common.cc',
'src/cpp/common/channel_arguments.cc',
'src/cpp/common/channel_filter.cc',
'src/cpp/common/completion_queue_cc.cc',
@ -255,6 +254,7 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/frame_settings.h',
'src/core/ext/transport/chttp2/transport/frame_window_update.h',
'src/core/ext/transport/chttp2/transport/hpack_encoder.h',
'src/core/ext/transport/chttp2/transport/hpack_mapping.h',
'src/core/ext/transport/chttp2/transport/hpack_parser.h',
'src/core/ext/transport/chttp2/transport/hpack_table.h',
'src/core/ext/transport/chttp2/transport/http2_settings.h',

@ -263,6 +263,7 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/frame_settings.h',
'src/core/ext/transport/chttp2/transport/frame_window_update.h',
'src/core/ext/transport/chttp2/transport/hpack_encoder.h',
'src/core/ext/transport/chttp2/transport/hpack_mapping.h',
'src/core/ext/transport/chttp2/transport/hpack_parser.h',
'src/core/ext/transport/chttp2/transport/hpack_table.h',
'src/core/ext/transport/chttp2/transport/http2_settings.h',
@ -681,6 +682,7 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/frame_settings.cc',
'src/core/ext/transport/chttp2/transport/frame_window_update.cc',
'src/core/ext/transport/chttp2/transport/hpack_encoder.cc',
'src/core/ext/transport/chttp2/transport/hpack_mapping.cc',
'src/core/ext/transport/chttp2/transport/hpack_parser.cc',
'src/core/ext/transport/chttp2/transport/hpack_table.cc',
'src/core/ext/transport/chttp2/transport/http2_settings.cc',
@ -866,6 +868,7 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/frame_settings.h',
'src/core/ext/transport/chttp2/transport/frame_window_update.h',
'src/core/ext/transport/chttp2/transport/hpack_encoder.h',
'src/core/ext/transport/chttp2/transport/hpack_mapping.h',
'src/core/ext/transport/chttp2/transport/hpack_parser.h',
'src/core/ext/transport/chttp2/transport/hpack_table.h',
'src/core/ext/transport/chttp2/transport/http2_settings.h',

@ -195,6 +195,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/transport/chttp2/transport/frame_settings.h )
s.files += %w( src/core/ext/transport/chttp2/transport/frame_window_update.h )
s.files += %w( src/core/ext/transport/chttp2/transport/hpack_encoder.h )
s.files += %w( src/core/ext/transport/chttp2/transport/hpack_mapping.h )
s.files += %w( src/core/ext/transport/chttp2/transport/hpack_parser.h )
s.files += %w( src/core/ext/transport/chttp2/transport/hpack_table.h )
s.files += %w( src/core/ext/transport/chttp2/transport/http2_settings.h )
@ -617,6 +618,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/transport/chttp2/transport/frame_settings.cc )
s.files += %w( src/core/ext/transport/chttp2/transport/frame_window_update.cc )
s.files += %w( src/core/ext/transport/chttp2/transport/hpack_encoder.cc )
s.files += %w( src/core/ext/transport/chttp2/transport/hpack_mapping.cc )
s.files += %w( src/core/ext/transport/chttp2/transport/hpack_parser.cc )
s.files += %w( src/core/ext/transport/chttp2/transport/hpack_table.cc )
s.files += %w( src/core/ext/transport/chttp2/transport/http2_settings.cc )

@ -441,6 +441,7 @@
'src/core/ext/transport/chttp2/transport/frame_settings.cc',
'src/core/ext/transport/chttp2/transport/frame_window_update.cc',
'src/core/ext/transport/chttp2/transport/hpack_encoder.cc',
'src/core/ext/transport/chttp2/transport/hpack_mapping.cc',
'src/core/ext/transport/chttp2/transport/hpack_parser.cc',
'src/core/ext/transport/chttp2/transport/hpack_table.cc',
'src/core/ext/transport/chttp2/transport/http2_settings.cc',
@ -825,6 +826,7 @@
'src/core/ext/transport/chttp2/transport/frame_settings.cc',
'src/core/ext/transport/chttp2/transport/frame_window_update.cc',
'src/core/ext/transport/chttp2/transport/hpack_encoder.cc',
'src/core/ext/transport/chttp2/transport/hpack_mapping.cc',
'src/core/ext/transport/chttp2/transport/hpack_parser.cc',
'src/core/ext/transport/chttp2/transport/hpack_table.cc',
'src/core/ext/transport/chttp2/transport/http2_settings.cc',
@ -1060,6 +1062,7 @@
'src/core/ext/transport/chttp2/transport/frame_settings.cc',
'src/core/ext/transport/chttp2/transport/frame_window_update.cc',
'src/core/ext/transport/chttp2/transport/hpack_encoder.cc',
'src/core/ext/transport/chttp2/transport/hpack_mapping.cc',
'src/core/ext/transport/chttp2/transport/hpack_parser.cc',
'src/core/ext/transport/chttp2/transport/hpack_table.cc',
'src/core/ext/transport/chttp2/transport/http2_settings.cc',
@ -1252,6 +1255,7 @@
'src/core/ext/transport/chttp2/transport/frame_settings.cc',
'src/core/ext/transport/chttp2/transport/frame_window_update.cc',
'src/core/ext/transport/chttp2/transport/hpack_encoder.cc',
'src/core/ext/transport/chttp2/transport/hpack_mapping.cc',
'src/core/ext/transport/chttp2/transport/hpack_parser.cc',
'src/core/ext/transport/chttp2/transport/hpack_table.cc',
'src/core/ext/transport/chttp2/transport/http2_settings.cc',
@ -1381,7 +1385,6 @@
'src/cpp/client/credentials_cc.cc',
'src/cpp/client/generic_stub.cc',
'src/cpp/common/alarm.cc',
'src/cpp/common/callback_common.cc',
'src/cpp/common/channel_arguments.cc',
'src/cpp/common/channel_filter.cc',
'src/cpp/common/completion_queue_cc.cc',
@ -1529,7 +1532,6 @@
'src/cpp/client/credentials_cc.cc',
'src/cpp/client/generic_stub.cc',
'src/cpp/common/alarm.cc',
'src/cpp/common/callback_common.cc',
'src/cpp/common/channel_arguments.cc',
'src/cpp/common/channel_filter.cc',
'src/cpp/common/completion_queue_cc.cc',

@ -111,7 +111,8 @@ GRPCAPI grpc_completion_queue* grpc_completion_queue_create_for_pluck(
of GRPC_CQ_CALLBACK and grpc_cq_polling_type of GRPC_CQ_DEFAULT_POLLING.
This function is experimental. */
GRPCAPI grpc_completion_queue* grpc_completion_queue_create_for_callback(
void* shutdown_callback, void* reserved);
grpc_experimental_completion_queue_functor* shutdown_callback,
void* reserved);
/** Create a completion queue */
GRPCAPI grpc_completion_queue* grpc_completion_queue_create(

@ -532,14 +532,14 @@ typedef struct grpc_alts_credentials_options grpc_alts_credentials_options;
* It is used for experimental purpose for now and subject to change.
*/
GRPCAPI grpc_alts_credentials_options*
grpc_alts_credentials_client_options_create();
grpc_alts_credentials_client_options_create(void);
/**
* This method creates a grpc ALTS credentials server options instance.
* It is used for experimental purpose for now and subject to change.
*/
GRPCAPI grpc_alts_credentials_options*
grpc_alts_credentials_server_options_create();
grpc_alts_credentials_server_options_create(void);
/**
* This method adds a target service account to grpc client's ALTS credentials

@ -660,6 +660,19 @@ typedef enum {
GRPC_CQ_CALLBACK
} grpc_cq_completion_type;
/** EXPERIMENTAL: Specifies an interface class to be used as a tag
for callback-based completion queues. This can be used directly,
as the first element of a struct in C, or as a base class in C++.
Its "run" value should be assigned to some non-member function, such as
a static method. */
typedef struct grpc_experimental_completion_queue_functor {
/** The run member specifies a function that will be called when this
tag is extracted from the completion queue. Its arguments will be a
pointer to this functor and a boolean that indicates whether the
operation succeeded (non-zero) or failed (zero) */
void (*functor_run)(struct grpc_experimental_completion_queue_functor*, int);
} grpc_experimental_completion_queue_functor;
/* The upgrade to version 2 is currently experimental. */
#define GRPC_CQ_CURRENT_VERSION 2
@ -678,7 +691,7 @@ typedef struct grpc_completion_queue_attributes {
/* EXPERIMENTAL: START OF VERSION 2 CQ ATTRIBUTES */
/** When creating a callbackable CQ, pass in a functor to get invoked when
* shutdown is complete */
void* cq_shutdown_cb;
grpc_experimental_completion_queue_functor* cq_shutdown_cb;
/* END OF VERSION 2 CQ ATTRIBUTES */
} grpc_completion_queue_attributes;

@ -21,6 +21,8 @@
#ifndef GRPCPP_ALARM_H
#define GRPCPP_ALARM_H
#include <functional>
#include <grpc/grpc.h>
#include <grpcpp/impl/codegen/completion_queue.h>
#include <grpcpp/impl/codegen/completion_queue_tag.h>
@ -76,8 +78,33 @@ class Alarm : private GrpcLibraryCodegen {
/// has already fired has no effect.
void Cancel();
/// NOTE: class experimental_type is not part of the public API of this class
/// TODO(vjpai): Move these contents to the public API of Alarm when
/// they are no longer experimental
class experimental_type {
public:
explicit experimental_type(Alarm* alarm) : alarm_(alarm) {}
/// Set an alarm to invoke callback \a f. The argument to the callback
/// states whether the alarm expired at \a deadline (true) or was cancelled
/// (false)
template <typename T>
void Set(const T& deadline, std::function<void(bool)> f) {
alarm_->SetInternal(TimePoint<T>(deadline).raw_time(), std::move(f));
}
private:
Alarm* alarm_;
};
/// NOTE: The function experimental() is not stable public API. It is a view
/// to the experimental components of this class. It may be changed or removed
/// at any time.
experimental_type experimental() { return experimental_type(this); }
private:
void SetInternal(CompletionQueue* cq, gpr_timespec deadline, void* tag);
void SetInternal(gpr_timespec deadline, std::function<void(bool)> f);
internal::CompletionQueueTag* alarm_;
};

@ -21,25 +21,36 @@
#include <functional>
#include <grpc/impl/codegen/grpc_types.h>
#include <grpcpp/impl/codegen/call.h>
#include <grpcpp/impl/codegen/channel_interface.h>
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/core_codegen_interface.h>
#include <grpcpp/impl/codegen/status.h>
// Forward declarations
namespace grpc_core {
class CQCallbackInterface;
};
namespace grpc {
namespace internal {
/// An exception-safe way of invoking a user-specified callback function
template <class Func, class Arg>
void CatchingCallback(Func&& func, Arg&& arg) {
#if GRPC_ALLOW_EXCEPTIONS
try {
func(arg);
} catch (...) {
// nothing to return or change here, just don't crash the library
}
#else // GRPC_ALLOW_EXCEPTIONS
func(arg);
#endif // GRPC_ALLOW_EXCEPTIONS
}
// The contract on these tags is that they are single-shot. They must be
// constructed and then fired at exactly one point. There is no expectation
// that they can be reused without reconstruction.
class CallbackWithStatusTag {
class CallbackWithStatusTag
: public grpc_experimental_completion_queue_functor {
public:
// always allocated against a call arena, no memory free required
static void operator delete(void* ptr, std::size_t size) {
@ -54,24 +65,49 @@ class CallbackWithStatusTag {
static void operator delete(void*, void*) { assert(0); }
CallbackWithStatusTag(grpc_call* call, std::function<void(Status)> f,
CompletionQueueTag* ops);
CompletionQueueTag* ops)
: call_(call), func_(std::move(f)), ops_(ops) {
g_core_codegen_interface->grpc_call_ref(call);
functor_run = &CallbackWithStatusTag::StaticRun;
}
~CallbackWithStatusTag() {}
void* tag() { return static_cast<void*>(impl_); }
Status* status_ptr() { return status_; }
CompletionQueueTag* ops() { return ops_; }
Status* status_ptr() { return &status_; }
// force_run can not be performed on a tag if operations using this tag
// have been sent to PerformOpsOnCall. It is intended for error conditions
// that are detected before the operations are internally processed.
void force_run(Status s);
void force_run(Status s) {
status_ = std::move(s);
Run(true);
}
private:
grpc_core::CQCallbackInterface* impl_;
Status* status_;
grpc_call* call_;
std::function<void(Status)> func_;
CompletionQueueTag* ops_;
Status status_;
static void StaticRun(grpc_experimental_completion_queue_functor* cb,
int ok) {
static_cast<CallbackWithStatusTag*>(cb)->Run(static_cast<bool>(ok));
}
void Run(bool ok) {
void* ignored = ops_;
GPR_CODEGEN_ASSERT(ops_->FinalizeResult(&ignored, &ok));
GPR_CODEGEN_ASSERT(ignored == ops_);
// Last use of func_ or status_, so ok to move them out
CatchingCallback(std::move(func_), std::move(status_));
func_ = nullptr; // reset to clear this out for sure
status_ = Status(); // reset to clear this out for sure
g_core_codegen_interface->grpc_call_unref(call_);
}
};
class CallbackWithSuccessTag {
class CallbackWithSuccessTag
: public grpc_experimental_completion_queue_functor {
public:
// always allocated against a call arena, no memory free required
static void operator delete(void* ptr, std::size_t size) {
@ -86,19 +122,40 @@ class CallbackWithSuccessTag {
static void operator delete(void*, void*) { assert(0); }
CallbackWithSuccessTag(grpc_call* call, std::function<void(bool)> f,
CompletionQueueTag* ops);
CompletionQueueTag* ops)
: call_(call), func_(std::move(f)), ops_(ops) {
g_core_codegen_interface->grpc_call_ref(call);
functor_run = &CallbackWithSuccessTag::StaticRun;
}
void* tag() { return static_cast<void*>(impl_); }
CompletionQueueTag* ops() { return ops_; }
// force_run can not be performed on a tag if operations using this tag
// have been sent to PerformOpsOnCall. It is intended for error conditions
// that are detected before the operations are internally processed.
void force_run(bool ok);
void force_run(bool ok) { Run(ok); }
private:
grpc_core::CQCallbackInterface* impl_;
grpc_call* call_;
std::function<void(bool)> func_;
CompletionQueueTag* ops_;
static void StaticRun(grpc_experimental_completion_queue_functor* cb,
int ok) {
static_cast<CallbackWithSuccessTag*>(cb)->Run(static_cast<bool>(ok));
}
void Run(bool ok) {
void* ignored = ops_;
bool new_ok = ok;
GPR_CODEGEN_ASSERT(ops_->FinalizeResult(&ignored, &new_ok));
GPR_CODEGEN_ASSERT(ignored == ops_);
// Last use of func_, so ok to move it out for rvalue call above
CatchingCallback(std::move(func_), ok);
func_ = nullptr; // reset to clear this out for sure
g_core_codegen_interface->grpc_call_unref(call_);
}
};
} // namespace internal

@ -84,7 +84,7 @@ class CallbackUnaryCallImpl {
ops->AllowNoMessage();
ops->ClientSendClose();
ops->ClientRecvStatus(context, tag->status_ptr());
ops->set_cq_tag(tag->tag());
ops->set_cq_tag(tag);
call.PerformOps(ops);
}
};

@ -200,6 +200,7 @@
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_settings.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_window_update.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_encoder.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_mapping.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_parser.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_table.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/http2_settings.h" role="src" />
@ -622,6 +623,7 @@
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_settings.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_window_update.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_encoder.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_mapping.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_parser.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_table.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/http2_settings.cc" role="src" />

@ -128,6 +128,7 @@ grpc::string GetHeaderIncludes(grpc_generator::File* file,
"");
}
static const char* headers_strs[] = {
"functional",
"grpcpp/impl/codegen/async_generic_service.h",
"grpcpp/impl/codegen/async_stream.h",
"grpcpp/impl/codegen/async_unary_call.h",
@ -547,6 +548,116 @@ void PrintHeaderClientMethod(grpc_generator::Printer* printer,
}
}
void PrintHeaderClientMethodCallbackInterfacesStart(
grpc_generator::Printer* printer,
std::map<grpc::string, grpc::string>* vars) {
// This declares the interface for the callback-based API. The components
// are pure; even though this is new (post-1.0) API, it can be pure because
// it is an entirely new interface that happens to be scoped within
// StubInterface, not new additions to StubInterface itself
printer->Print("class experimental_async_interface {\n");
// All methods in this new interface are public. There is no need for private
// "Raw" methods since the callback-based API returns unowned raw pointers
printer->Print(" public:\n");
printer->Indent();
printer->Print("virtual ~experimental_async_interface() {}\n");
}
void PrintHeaderClientMethodCallbackInterfaces(
grpc_generator::Printer* printer, const grpc_generator::Method* method,
std::map<grpc::string, grpc::string>* vars, bool is_public) {
// Reserve is_public for future expansion
assert(is_public);
(*vars)["Method"] = method->name();
(*vars)["Request"] = method->input_type_name();
(*vars)["Response"] = method->output_type_name();
if (method->NoStreaming()) {
printer->Print(*vars,
"virtual void $Method$(::grpc::ClientContext* context, "
"const $Request$* request, $Response$* response, "
"std::function<void(::grpc::Status)>) = 0;\n");
} else if (ClientOnlyStreaming(method)) {
// TODO(vjpai): Add support for client-side streaming
} else if (ServerOnlyStreaming(method)) {
// TODO(vjpai): Add support for server-side streaming
} else if (method->BidiStreaming()) {
// TODO(vjpai): Add support for bidi streaming
}
}
void PrintHeaderClientMethodCallbackInterfacesEnd(
grpc_generator::Printer* printer,
std::map<grpc::string, grpc::string>* vars) {
printer->Outdent();
printer->Print("};\n");
// Declare a function to give the async stub contents. It can't be pure
// since this is a new API in StubInterface, but it is meaningless by default
// (since any stub that wants to use it must have its own implementation of
// the callback functions therein), so make the default return value nullptr.
// Intentionally include the word "class" to avoid possible shadowing.
printer->Print(
"virtual class experimental_async_interface* experimental_async() { "
"return nullptr; }\n");
}
void PrintHeaderClientMethodCallbackStart(
grpc_generator::Printer* printer,
std::map<grpc::string, grpc::string>* vars) {
// This declares the stub entry for the callback-based API.
printer->Print("class experimental_async final :\n");
printer->Print(" public StubInterface::experimental_async_interface {\n");
printer->Print(" public:\n");
printer->Indent();
}
void PrintHeaderClientMethodCallback(grpc_generator::Printer* printer,
const grpc_generator::Method* method,
std::map<grpc::string, grpc::string>* vars,
bool is_public) {
// Reserve is_public for future expansion
assert(is_public);
(*vars)["Method"] = method->name();
(*vars)["Request"] = method->input_type_name();
(*vars)["Response"] = method->output_type_name();
if (method->NoStreaming()) {
printer->Print(*vars,
"void $Method$(::grpc::ClientContext* context, "
"const $Request$* request, $Response$* response, "
"std::function<void(::grpc::Status)>) override;\n");
} else if (ClientOnlyStreaming(method)) {
// TODO(vjpai): Add support for client-side streaming
} else if (ServerOnlyStreaming(method)) {
// TODO(vjpai): Add support for server-side streaming
} else if (method->BidiStreaming()) {
// TODO(vjpai): Add support for bidi streaming
}
}
void PrintHeaderClientMethodCallbackEnd(
grpc_generator::Printer* printer,
std::map<grpc::string, grpc::string>* vars) {
printer->Outdent();
printer->Print(" private:\n");
printer->Indent();
printer->Print("friend class Stub;\n");
printer->Print("explicit experimental_async(Stub* stub): stub_(stub) { }\n");
// include a function with a dummy use of stub_ to avoid an unused
// private member warning for service with no methods
printer->Print("Stub* stub() { return stub_; }\n");
printer->Print("Stub* stub_;\n");
printer->Outdent();
printer->Print("};\n");
printer->Print(
"class experimental_async_interface* experimental_async() override { "
"return &async_stub_; }\n");
}
void PrintHeaderClientMethodData(grpc_generator::Printer* printer,
const grpc_generator::Method* method,
std::map<grpc::string, grpc::string>* vars) {
@ -951,6 +1062,14 @@ void PrintHeaderService(grpc_generator::Printer* printer,
true);
printer->Print(service->method(i)->GetTrailingComments("//").c_str());
}
PrintHeaderClientMethodCallbackInterfacesStart(printer, vars);
for (int i = 0; i < service->method_count(); ++i) {
printer->Print(service->method(i)->GetLeadingComments("//").c_str());
PrintHeaderClientMethodCallbackInterfaces(printer, service->method(i).get(),
vars, true);
printer->Print(service->method(i)->GetTrailingComments("//").c_str());
}
PrintHeaderClientMethodCallbackInterfacesEnd(printer, vars);
printer->Outdent();
printer->Print("private:\n");
printer->Indent();
@ -970,10 +1089,17 @@ void PrintHeaderService(grpc_generator::Printer* printer,
for (int i = 0; i < service->method_count(); ++i) {
PrintHeaderClientMethod(printer, service->method(i).get(), vars, true);
}
PrintHeaderClientMethodCallbackStart(printer, vars);
for (int i = 0; i < service->method_count(); ++i) {
PrintHeaderClientMethodCallback(printer, service->method(i).get(), vars,
true);
}
PrintHeaderClientMethodCallbackEnd(printer, vars);
printer->Outdent();
printer->Print("\n private:\n");
printer->Indent();
printer->Print("std::shared_ptr< ::grpc::ChannelInterface> channel_;\n");
printer->Print("class experimental_async async_stub_{this};\n");
for (int i = 0; i < service->method_count(); ++i) {
PrintHeaderClientMethod(printer, service->method(i).get(), vars, false);
}
@ -1199,10 +1325,12 @@ grpc::string GetSourceIncludes(grpc_generator::File* file,
std::map<grpc::string, grpc::string> vars;
static const char* headers_strs[] = {
"functional",
"grpcpp/impl/codegen/async_stream.h",
"grpcpp/impl/codegen/async_unary_call.h",
"grpcpp/impl/codegen/channel_interface.h",
"grpcpp/impl/codegen/client_unary_call.h",
"grpcpp/impl/codegen/client_callback.h",
"grpcpp/impl/codegen/method_handler_impl.h",
"grpcpp/impl/codegen/rpc_service_method.h",
"grpcpp/impl/codegen/service_type.h",
@ -1247,6 +1375,17 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
" return ::grpc::internal::BlockingUnaryCall"
"(channel_.get(), rpcmethod_$Method$_, "
"context, request, response);\n}\n\n");
printer->Print(*vars,
"void $ns$$Service$::Stub::experimental_async::$Method$("
"::grpc::ClientContext* context, "
"const $Request$* request, $Response$* response, "
"std::function<void(::grpc::Status)> f) {\n");
printer->Print(*vars,
" return ::grpc::internal::CallbackUnaryCall"
"(stub_->channel_.get(), stub_->rpcmethod_$Method$_, "
"context, request, response, std::move(f));\n}\n\n");
for (auto async_prefix : async_prefixes) {
(*vars)["AsyncPrefix"] = async_prefix.prefix;
(*vars)["AsyncStart"] = async_prefix.start;
@ -1277,6 +1416,9 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
"rpcmethod_$Method$_, "
"context, response);\n"
"}\n\n");
// TODO(vjpai): Add callback version
for (auto async_prefix : async_prefixes) {
(*vars)["AsyncPrefix"] = async_prefix.prefix;
(*vars)["AsyncStart"] = async_prefix.start;
@ -1308,6 +1450,9 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
"rpcmethod_$Method$_, "
"context, request);\n"
"}\n\n");
// TODO(vjpai): Add callback version
for (auto async_prefix : async_prefixes) {
(*vars)["AsyncPrefix"] = async_prefix.prefix;
(*vars)["AsyncStart"] = async_prefix.start;
@ -1339,6 +1484,9 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
"rpcmethod_$Method$_, "
"context);\n"
"}\n\n");
// TODO(vjpai): Add callback version
for (auto async_prefix : async_prefixes) {
(*vars)["AsyncPrefix"] = async_prefix.prefix;
(*vars)["AsyncStart"] = async_prefix.start;

@ -42,7 +42,7 @@ struct grpc_subchannel_key {
grpc_subchannel_args args;
};
static gpr_atm g_force_creation = false;
static bool g_force_creation = false;
static grpc_subchannel_key* create_key(
const grpc_subchannel_args* args,
@ -74,7 +74,7 @@ static grpc_subchannel_key* subchannel_key_copy(grpc_subchannel_key* k) {
int grpc_subchannel_key_compare(const grpc_subchannel_key* a,
const grpc_subchannel_key* b) {
// To pretend the keys are different, return a non-zero value.
if (GPR_UNLIKELY(gpr_atm_no_barrier_load(&g_force_creation))) return 1;
if (GPR_UNLIKELY(g_force_creation)) return 1;
int c = GPR_ICMP(a->args.filter_count, b->args.filter_count);
if (c != 0) return c;
if (a->args.filter_count > 0) {
@ -251,5 +251,5 @@ void grpc_subchannel_index_unregister(grpc_subchannel_key* key,
}
void grpc_subchannel_index_test_only_set_force_creation(bool force_creation) {
gpr_atm_no_barrier_store(&g_force_creation, force_creation);
g_force_creation = force_creation;
}

@ -525,7 +525,7 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
/* should this elem be in the table? */
size_t decoder_space_usage =
grpc_mdelem_get_size_in_hpack_table(elem, st->use_true_binary_metadata);
grpc_chttp2_get_size_in_hpack_table(elem, st->use_true_binary_metadata);
bool should_add_elem = elem_interned &&
decoder_space_usage < MAX_DECODER_SPACE_USAGE &&
c->filter_elems[HASH_FRAGMENT_1(elem_hash)] >=
@ -688,11 +688,22 @@ void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor* c,
emit_advertise_table_size_change(c, &st);
}
for (size_t i = 0; i < extra_headers_size; ++i) {
hpack_enc(c, *extra_headers[i], &st);
grpc_mdelem md = *extra_headers[i];
uint8_t static_index = grpc_chttp2_get_static_hpack_table_index(md);
if (static_index) {
emit_indexed(c, static_index, &st);
} else {
hpack_enc(c, md, &st);
}
}
grpc_metadata_batch_assert_ok(metadata);
for (grpc_linked_mdelem* l = metadata->list.head; l; l = l->next) {
hpack_enc(c, l->md, &st);
uint8_t static_index = grpc_chttp2_get_static_hpack_table_index(l->md);
if (static_index) {
emit_indexed(c, static_index, &st);
} else {
hpack_enc(c, l->md, &st);
}
}
grpc_millis deadline = metadata->deadline;
if (deadline != GRPC_MILLIS_INF_FUTURE) {

@ -0,0 +1,39 @@
/*
* 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.
*/
/*
* WARNING: Auto-generated code.
*
* To make changes to this file, change
* tools/codegen/core/gen_static_metadata.py, and then re-run it.
*
* This file contains the mapping from the index of each metadata element in the
* grpc static metadata table to the index of that element in the hpack static
* metadata table. If the element is not contained in the static hpack table,
* then the returned index is 0.
*/
#include <grpc/support/port_platform.h>
#include "src/core/ext/transport/chttp2/transport/hpack_mapping.h"
const uint8_t grpc_hpack_static_mdelem_indices[GRPC_STATIC_MDELEM_COUNT] = {
0, 0, 0, 0, 0, 0, 0, 0, 3, 8, 13, 6, 7, 0, 1, 2, 0, 4,
5, 9, 10, 11, 12, 14, 15, 0, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
42, 43, 44, 0, 0, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};

@ -0,0 +1,38 @@
/*
* Copyright 2015 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* WARNING: Auto-generated code.
*
* To make changes to this file, change
* tools/codegen/core/gen_static_metadata.py, and then re-run it.
*
* This file contains the mapping from the index of each metadata element in the
* grpc static metadata table to the index of that element in the hpack static
* metadata table. If the element is not contained in the static hpack table,
* then the returned index is 0.
*/
#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_MAPPING_H
#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_MAPPING_H
#include <grpc/support/port_platform.h>
#include "src/core/lib/transport/static_metadata.h"
extern const uint8_t grpc_hpack_static_mdelem_indices[GRPC_STATIC_MDELEM_COUNT];
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_MAPPING_H */

@ -27,8 +27,10 @@
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/ext/transport/chttp2/transport/hpack_mapping.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gpr/murmur_hash.h"
#include "src/core/lib/transport/static_metadata.h"
extern grpc_core::TraceFlag grpc_http_trace;
@ -366,3 +368,30 @@ grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find(
return r;
}
static size_t get_base64_encoded_size(size_t raw_length) {
static const uint8_t tail_xtra[3] = {0, 2, 3};
return raw_length / 3 * 4 + tail_xtra[raw_length % 3];
}
size_t grpc_chttp2_get_size_in_hpack_table(grpc_mdelem elem,
bool use_true_binary_metadata) {
size_t overhead_and_key = 32 + GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
size_t value_len = GRPC_SLICE_LENGTH(GRPC_MDVALUE(elem));
if (grpc_is_binary_header(GRPC_MDKEY(elem))) {
return overhead_and_key + (use_true_binary_metadata
? value_len + 1
: get_base64_encoded_size(value_len));
} else {
return overhead_and_key + value_len;
}
}
uint8_t grpc_chttp2_get_static_hpack_table_index(grpc_mdelem md) {
if (GRPC_MDELEM_STORAGE(md) == GRPC_MDELEM_STORAGE_STATIC) {
return grpc_hpack_static_mdelem_indices[GRPC_MDELEM_DATA(md) -
grpc_static_mdelem_table];
} else {
return 0;
}
}

@ -83,6 +83,15 @@ grpc_mdelem grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl* tbl,
/* add a table entry to the index */
grpc_error* grpc_chttp2_hptbl_add(grpc_chttp2_hptbl* tbl,
grpc_mdelem md) GRPC_MUST_USE_RESULT;
size_t grpc_chttp2_get_size_in_hpack_table(grpc_mdelem elem,
bool use_true_binary_metadata);
/* Returns the static hpack table index that corresponds to /a elem. Returns 0
if /a elem is not statically stored or if it is not in the static hpack
table */
uint8_t grpc_chttp2_get_static_hpack_table_index(grpc_mdelem md);
/* Find a key/value pair in the table... returns the index in the table of the
most similar entry, or 0 if the value was not found */
typedef struct {

@ -409,67 +409,81 @@ static void on_initial_header(void* tp, grpc_mdelem md) {
gpr_free(value);
}
if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) &&
!grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) {
/* TODO(ctiller): check for a status like " 0" */
s->seen_error = true;
}
if (GRPC_MDELEM_STORAGE(md) == GRPC_MDELEM_STORAGE_STATIC) {
// We don't use grpc_mdelem_eq here to avoid executing additional
// instructions. The reasoning is if the payload is not equal, we already
// know that the metadata elements are not equal because the md is
// confirmed to be static. If we had used grpc_mdelem_eq here, then if the
// payloads are not equal, grpc_mdelem_eq executes more instructions to
// determine if they're equal or not.
if (md.payload == GRPC_MDELEM_GRPC_STATUS_1.payload ||
md.payload == GRPC_MDELEM_GRPC_STATUS_2.payload) {
s->seen_error = true;
}
} else {
if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) &&
!grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) {
/* TODO(ctiller): check for a status like " 0" */
s->seen_error = true;
}
if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) {
grpc_millis* cached_timeout =
static_cast<grpc_millis*>(grpc_mdelem_get_user_data(md, free_timeout));
grpc_millis timeout;
if (cached_timeout != nullptr) {
timeout = *cached_timeout;
} else {
if (GPR_UNLIKELY(
!grpc_http2_decode_timeout(GRPC_MDVALUE(md), &timeout))) {
char* val = grpc_slice_to_c_string(GRPC_MDVALUE(md));
gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val);
gpr_free(val);
timeout = GRPC_MILLIS_INF_FUTURE;
if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) {
grpc_millis* cached_timeout = static_cast<grpc_millis*>(
grpc_mdelem_get_user_data(md, free_timeout));
grpc_millis timeout;
if (cached_timeout != nullptr) {
timeout = *cached_timeout;
} else {
if (GPR_UNLIKELY(
!grpc_http2_decode_timeout(GRPC_MDVALUE(md), &timeout))) {
char* val = grpc_slice_to_c_string(GRPC_MDVALUE(md));
gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val);
gpr_free(val);
timeout = GRPC_MILLIS_INF_FUTURE;
}
if (GRPC_MDELEM_IS_INTERNED(md)) {
/* store the result */
cached_timeout =
static_cast<grpc_millis*>(gpr_malloc(sizeof(grpc_millis)));
*cached_timeout = timeout;
grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
}
}
if (GRPC_MDELEM_IS_INTERNED(md)) {
/* store the result */
cached_timeout =
static_cast<grpc_millis*>(gpr_malloc(sizeof(grpc_millis)));
*cached_timeout = timeout;
grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
if (timeout != GRPC_MILLIS_INF_FUTURE) {
grpc_chttp2_incoming_metadata_buffer_set_deadline(
&s->metadata_buffer[0], grpc_core::ExecCtx::Get()->Now() + timeout);
}
GRPC_MDELEM_UNREF(md);
return;
}
if (timeout != GRPC_MILLIS_INF_FUTURE) {
grpc_chttp2_incoming_metadata_buffer_set_deadline(
&s->metadata_buffer[0], grpc_core::ExecCtx::Get()->Now() + timeout);
}
}
const size_t new_size = s->metadata_buffer[0].size + GRPC_MDELEM_LENGTH(md);
const size_t metadata_size_limit =
t->settings[GRPC_ACKED_SETTINGS]
[GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE];
if (new_size > metadata_size_limit) {
gpr_log(GPR_DEBUG,
"received initial metadata size exceeds limit (%" PRIuPTR
" vs. %" PRIuPTR ")",
new_size, metadata_size_limit);
grpc_chttp2_cancel_stream(
t, s,
grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"received initial metadata size exceeds limit"),
GRPC_ERROR_INT_GRPC_STATUS,
GRPC_STATUS_RESOURCE_EXHAUSTED));
grpc_chttp2_parsing_become_skip_parser(t);
s->seen_error = true;
GRPC_MDELEM_UNREF(md);
} else {
const size_t new_size = s->metadata_buffer[0].size + GRPC_MDELEM_LENGTH(md);
const size_t metadata_size_limit =
t->settings[GRPC_ACKED_SETTINGS]
[GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE];
if (new_size > metadata_size_limit) {
gpr_log(GPR_DEBUG,
"received initial metadata size exceeds limit (%" PRIuPTR
" vs. %" PRIuPTR ")",
new_size, metadata_size_limit);
grpc_chttp2_cancel_stream(
t, s,
grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"received initial metadata size exceeds limit"),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED));
grpc_error* error =
grpc_chttp2_incoming_metadata_buffer_add(&s->metadata_buffer[0], md);
if (error != GRPC_ERROR_NONE) {
grpc_chttp2_cancel_stream(t, s, error);
grpc_chttp2_parsing_become_skip_parser(t);
s->seen_error = true;
GRPC_MDELEM_UNREF(md);
} else {
grpc_error* error =
grpc_chttp2_incoming_metadata_buffer_add(&s->metadata_buffer[0], md);
if (error != GRPC_ERROR_NONE) {
grpc_chttp2_cancel_stream(t, s, error);
grpc_chttp2_parsing_become_skip_parser(t);
s->seen_error = true;
GRPC_MDELEM_UNREF(md);
}
}
}
}
@ -491,8 +505,19 @@ static void on_trailing_header(void* tp, grpc_mdelem md) {
gpr_free(value);
}
if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) &&
!grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) {
if (GRPC_MDELEM_STORAGE(md) == GRPC_MDELEM_STORAGE_STATIC) {
// We don't use grpc_mdelem_eq here to avoid executing additional
// instructions. The reasoning is if the payload is not equal, we already
// know that the metadata elements are not equal because the md is
// confirmed to be static. If we had used grpc_mdelem_eq here, then if the
// payloads are not equal, grpc_mdelem_eq executes more instructions to
// determine if they're equal or not.
if (md.payload == GRPC_MDELEM_GRPC_STATUS_1.payload ||
md.payload == GRPC_MDELEM_GRPC_STATUS_2.payload) {
s->seen_error = true;
}
} else if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) &&
!grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) {
/* TODO(ctiller): check for a status like " 0" */
s->seen_error = true;
}

@ -72,7 +72,8 @@ static void target_service_account_destroy(
static const grpc_alts_credentials_options_vtable vtable = {
alts_client_options_copy, alts_client_options_destroy};
grpc_alts_credentials_options* grpc_alts_credentials_client_options_create() {
grpc_alts_credentials_options* grpc_alts_credentials_client_options_create(
void) {
auto client_options = static_cast<grpc_alts_credentials_client_options*>(
gpr_zalloc(sizeof(grpc_alts_credentials_client_options)));
client_options->base.vtable = &vtable;

@ -36,7 +36,8 @@ static void alts_server_options_destroy(
static const grpc_alts_credentials_options_vtable vtable = {
alts_server_options_copy, alts_server_options_destroy};
grpc_alts_credentials_options* grpc_alts_credentials_server_options_create() {
grpc_alts_credentials_options* grpc_alts_credentials_server_options_create(
void) {
grpc_alts_credentials_server_options* server_options =
static_cast<grpc_alts_credentials_server_options*>(
gpr_zalloc(sizeof(*server_options)));

@ -184,7 +184,8 @@ static const cq_poller_vtable g_poller_vtable_by_poller_type[] = {
typedef struct cq_vtable {
grpc_cq_completion_type cq_completion_type;
size_t data_size;
void (*init)(void* data, grpc_core::CQCallbackInterface* shutdown_callback);
void (*init)(void* data,
grpc_experimental_completion_queue_functor* shutdown_callback);
void (*shutdown)(grpc_completion_queue* cq);
void (*destroy)(void* data);
bool (*begin_op)(grpc_completion_queue* cq, void* tag);
@ -267,7 +268,7 @@ typedef struct cq_callback_data {
bool shutdown_called;
/** A callback that gets invoked when the CQ completes shutdown */
grpc_core::CQCallbackInterface* shutdown_callback;
grpc_experimental_completion_queue_functor* shutdown_callback;
} cq_callback_data;
/* Completion queue structure */
@ -333,12 +334,12 @@ static grpc_event cq_pluck(grpc_completion_queue* cq, void* tag,
gpr_timespec deadline, void* reserved);
// Note that cq_init_next and cq_init_pluck do not use the shutdown_callback
static void cq_init_next(void* data,
grpc_core::CQCallbackInterface* shutdown_callback);
static void cq_init_pluck(void* data,
grpc_core::CQCallbackInterface* shutdown_callback);
static void cq_init_callback(void* data,
grpc_core::CQCallbackInterface* shutdown_callback);
static void cq_init_next(
void* data, grpc_experimental_completion_queue_functor* shutdown_callback);
static void cq_init_pluck(
void* data, grpc_experimental_completion_queue_functor* shutdown_callback);
static void cq_init_callback(
void* data, grpc_experimental_completion_queue_functor* shutdown_callback);
static void cq_destroy_next(void* data);
static void cq_destroy_pluck(void* data);
static void cq_destroy_callback(void* data);
@ -462,7 +463,7 @@ static long cq_event_queue_num_items(grpc_cq_event_queue* q) {
grpc_completion_queue* grpc_completion_queue_create_internal(
grpc_cq_completion_type completion_type, grpc_cq_polling_type polling_type,
grpc_core::CQCallbackInterface* shutdown_callback) {
grpc_experimental_completion_queue_functor* shutdown_callback) {
GPR_TIMER_SCOPE("grpc_completion_queue_create_internal", 0);
grpc_completion_queue* cq;
@ -497,8 +498,8 @@ grpc_completion_queue* grpc_completion_queue_create_internal(
return cq;
}
static void cq_init_next(void* data,
grpc_core::CQCallbackInterface* shutdown_callback) {
static void cq_init_next(
void* data, grpc_experimental_completion_queue_functor* shutdown_callback) {
cq_next_data* cqd = static_cast<cq_next_data*>(data);
/* Initial count is dropped by grpc_completion_queue_shutdown */
gpr_atm_no_barrier_store(&cqd->pending_events, 1);
@ -513,8 +514,8 @@ static void cq_destroy_next(void* data) {
cq_event_queue_destroy(&cqd->queue);
}
static void cq_init_pluck(void* data,
grpc_core::CQCallbackInterface* shutdown_callback) {
static void cq_init_pluck(
void* data, grpc_experimental_completion_queue_functor* shutdown_callback) {
cq_pluck_data* cqd = static_cast<cq_pluck_data*>(data);
/* Initial count is dropped by grpc_completion_queue_shutdown */
gpr_atm_no_barrier_store(&cqd->pending_events, 1);
@ -532,7 +533,7 @@ static void cq_destroy_pluck(void* data) {
}
static void cq_init_callback(
void* data, grpc_core::CQCallbackInterface* shutdown_callback) {
void* data, grpc_experimental_completion_queue_functor* shutdown_callback) {
cq_callback_data* cqd = static_cast<cq_callback_data*>(data);
/* Initial count is dropped by grpc_completion_queue_shutdown */
gpr_atm_no_barrier_store(&cqd->pending_events, 1);
@ -859,7 +860,8 @@ static void cq_end_op_for_callback(
GRPC_ERROR_UNREF(error);
(static_cast<grpc_core::CQCallbackInterface*>(tag))->Run(is_success);
auto* functor = static_cast<grpc_experimental_completion_queue_functor*>(tag);
(*functor->functor_run)(functor, is_success);
}
void grpc_cq_end_op(grpc_completion_queue* cq, void* tag, grpc_error* error,
@ -1343,7 +1345,7 @@ static void cq_finish_shutdown_callback(grpc_completion_queue* cq) {
GPR_ASSERT(cqd->shutdown_called);
cq->poller_vtable->shutdown(POLLSET_FROM_CQ(cq), &cq->pollset_shutdown_done);
callback->Run(true);
(*callback->functor_run)(callback, true);
}
static void cq_shutdown_callback(grpc_completion_queue* cq) {

@ -48,23 +48,6 @@ typedef struct grpc_cq_completion {
uintptr_t next;
} grpc_cq_completion;
/// For callback CQs, the tag that is passed in for an operation must
/// actually be a pointer to an implementation of the following class.
/// When the operation completes, the tag will be typecasted from void*
/// to grpc_core::CQCallbackInterface* and then the Run method will be
/// invoked on it. In practice, the language binding (e.g., C++ API
/// implementation) is responsible for providing and using an implementation
/// of this abstract base class.
namespace grpc_core {
class CQCallbackInterface {
public:
virtual ~CQCallbackInterface() {}
virtual void Run(bool) GRPC_ABSTRACT;
GRPC_ABSTRACT_BASE_CLASS
};
} // namespace grpc_core
#ifndef NDEBUG
void grpc_cq_internal_ref(grpc_completion_queue* cc, const char* reason,
const char* file, int line);
@ -106,6 +89,6 @@ int grpc_get_cq_poll_num(grpc_completion_queue* cc);
grpc_completion_queue* grpc_completion_queue_create_internal(
grpc_cq_completion_type completion_type, grpc_cq_polling_type polling_type,
grpc_core::CQCallbackInterface* shutdown_callback);
grpc_experimental_completion_queue_functor* shutdown_callback);
#endif /* GRPC_CORE_LIB_SURFACE_COMPLETION_QUEUE_H */

@ -31,8 +31,7 @@ static grpc_completion_queue* default_create(
const grpc_completion_queue_factory* factory,
const grpc_completion_queue_attributes* attr) {
return grpc_completion_queue_create_internal(
attr->cq_completion_type, attr->cq_polling_type,
static_cast<grpc_core::CQCallbackInterface*>(attr->cq_shutdown_cb));
attr->cq_completion_type, attr->cq_polling_type, attr->cq_shutdown_cb);
}
static grpc_completion_queue_factory_vtable default_vtable = {default_create};
@ -73,7 +72,8 @@ grpc_completion_queue* grpc_completion_queue_create_for_pluck(void* reserved) {
}
grpc_completion_queue* grpc_completion_queue_create_for_callback(
void* shutdown_callback, void* reserved) {
grpc_experimental_completion_queue_functor* shutdown_callback,
void* reserved) {
GPR_ASSERT(!reserved);
grpc_completion_queue_attributes attr = {
2, GRPC_CQ_CALLBACK, GRPC_CQ_DEFAULT_POLLING, shutdown_callback};

@ -342,24 +342,6 @@ grpc_mdelem grpc_mdelem_from_grpc_metadata(grpc_metadata* metadata) {
changed ? nullptr : reinterpret_cast<grpc_mdelem_data*>(metadata));
}
static size_t get_base64_encoded_size(size_t raw_length) {
static const uint8_t tail_xtra[3] = {0, 2, 3};
return raw_length / 3 * 4 + tail_xtra[raw_length % 3];
}
size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem elem,
bool use_true_binary_metadata) {
size_t overhead_and_key = 32 + GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
size_t value_len = GRPC_SLICE_LENGTH(GRPC_MDVALUE(elem));
if (grpc_is_binary_header(GRPC_MDKEY(elem))) {
return overhead_and_key + (use_true_binary_metadata
? value_len + 1
: get_base64_encoded_size(value_len));
} else {
return overhead_and_key + value_len;
}
}
grpc_mdelem grpc_mdelem_ref(grpc_mdelem gmd DEBUG_ARGS) {
switch (GRPC_MDELEM_STORAGE(gmd)) {
case GRPC_MDELEM_STORAGE_EXTERNAL:

@ -125,9 +125,6 @@ grpc_mdelem grpc_mdelem_create(
bool grpc_mdelem_eq(grpc_mdelem a, grpc_mdelem b);
size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem elem,
bool use_true_binary_metadata);
/* Mutator and accessor for grpc_mdelem user data. The destructor function
is used as a type tag and is checked during user_data fetch. */
void* grpc_mdelem_get_user_data(grpc_mdelem md, void (*if_destroy_func)(void*));

@ -105,7 +105,7 @@ static grpc_error* maybe_link_callout(grpc_metadata_batch* batch,
return GRPC_ERROR_NONE;
}
if (batch->idx.array[idx] == nullptr) {
if (grpc_static_callout_is_default[idx]) ++batch->list.default_count;
++batch->list.default_count;
batch->idx.array[idx] = storage;
return GRPC_ERROR_NONE;
}
@ -121,7 +121,7 @@ static void maybe_unlink_callout(grpc_metadata_batch* batch,
if (idx == GRPC_BATCH_CALLOUTS_COUNT) {
return;
}
if (grpc_static_callout_is_default[idx]) --batch->list.default_count;
--batch->list.default_count;
GPR_ASSERT(batch->idx.array[idx] != nullptr);
batch->idx.array[idx] = nullptr;
}

@ -82,6 +82,7 @@ void grpc_metadata_batch_set_value(grpc_linked_mdelem* storage,
grpc_error* grpc_metadata_batch_link_head(grpc_metadata_batch* batch,
grpc_linked_mdelem* storage)
GRPC_MUST_USE_RESULT;
/** Add \a storage to the end of \a batch. storage->md is
assumed to be valid.
\a storage is owned by the caller and must survive for the
@ -100,6 +101,7 @@ grpc_error* grpc_metadata_batch_link_tail(grpc_metadata_batch* batch,
grpc_error* grpc_metadata_batch_add_head(
grpc_metadata_batch* batch, grpc_linked_mdelem* storage,
grpc_mdelem elem_to_add) GRPC_MUST_USE_RESULT;
/** Add \a elem_to_add as the last element in \a batch, using
\a storage as backing storage for the linked list element.
\a storage is owned by the caller and must survive for the

@ -568,33 +568,6 @@ grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT] = {
{{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
{&grpc_static_metadata_refcounts[102], {{g_bytes + 1101, 13}}}},
};
bool grpc_static_callout_is_default[GRPC_BATCH_CALLOUTS_COUNT] = {
true, // :path
true, // :method
true, // :status
true, // :authority
true, // :scheme
true, // te
true, // grpc-message
true, // grpc-status
true, // grpc-payload-bin
true, // grpc-encoding
true, // grpc-accept-encoding
true, // grpc-server-stats-bin
true, // grpc-tags-bin
true, // grpc-trace-bin
true, // content-type
true, // content-encoding
true, // accept-encoding
true, // grpc-internal-encoding-request
true, // grpc-internal-stream-encoding-request
true, // user-agent
true, // host
true, // lb-token
true, // grpc-previous-rpc-attempts
true, // grpc-retry-pushback-ms
};
const uint8_t grpc_static_accept_encoding_metadata[8] = {0, 76, 77, 78,
79, 80, 81, 82};

@ -587,8 +587,6 @@ typedef union {
GRPC_BATCH_CALLOUTS_COUNT) \
: GRPC_BATCH_CALLOUTS_COUNT)
extern bool grpc_static_callout_is_default[GRPC_BATCH_CALLOUTS_COUNT];
extern const uint8_t grpc_static_accept_encoding_metadata[8];
#define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs) \
(GRPC_MAKE_MDELEM( \

@ -193,17 +193,19 @@ bool Channel::WaitForStateChangeImpl(grpc_connectivity_state last_observed,
}
namespace {
class ShutdownCallback : public grpc_core::CQCallbackInterface {
class ShutdownCallback : public grpc_experimental_completion_queue_functor {
public:
ShutdownCallback() { functor_run = &ShutdownCallback::Run; }
// TakeCQ takes ownership of the cq into the shutdown callback
// so that the shutdown callback will be responsible for destroying it
void TakeCQ(CompletionQueue* cq) { cq_ = cq; }
// The Run function will get invoked by the completion queue library
// when the shutdown is actually complete
void Run(bool) override {
delete cq_;
grpc_core::Delete(this);
static void Run(grpc_experimental_completion_queue_functor* cb, int) {
auto* callback = static_cast<ShutdownCallback*>(cb);
delete callback->cq_;
grpc_core::Delete(callback);
}
private:

@ -39,17 +39,6 @@ class AlarmImpl : public CompletionQueueTag {
AlarmImpl() : cq_(nullptr), tag_(nullptr) {
gpr_ref_init(&refs_, 1);
grpc_timer_init_unset(&timer_);
GRPC_CLOSURE_INIT(&on_alarm_,
[](void* arg, grpc_error* error) {
// queue the op on the completion queue
AlarmImpl* alarm = static_cast<AlarmImpl*>(arg);
alarm->Ref();
grpc_cq_end_op(
alarm->cq_, alarm, error,
[](void* arg, grpc_cq_completion* completion) {},
arg, &alarm->completion_);
},
this, grpc_schedule_on_exec_ctx);
}
~AlarmImpl() {
grpc_core::ExecCtx exec_ctx;
@ -68,6 +57,32 @@ class AlarmImpl : public CompletionQueueTag {
cq_ = cq->cq();
tag_ = tag;
GPR_ASSERT(grpc_cq_begin_op(cq_, this));
GRPC_CLOSURE_INIT(&on_alarm_,
[](void* arg, grpc_error* error) {
// queue the op on the completion queue
AlarmImpl* alarm = static_cast<AlarmImpl*>(arg);
alarm->Ref();
grpc_cq_end_op(
alarm->cq_, alarm, error,
[](void* arg, grpc_cq_completion* completion) {},
arg, &alarm->completion_);
},
this, grpc_schedule_on_exec_ctx);
grpc_timer_init(&timer_, grpc_timespec_to_millis_round_up(deadline),
&on_alarm_);
}
void Set(gpr_timespec deadline, std::function<void(bool)> f) {
grpc_core::ExecCtx exec_ctx;
// Don't use any CQ at all. Instead just use the timer to fire the function
callback_ = std::move(f);
Ref();
GRPC_CLOSURE_INIT(&on_alarm_,
[](void* arg, grpc_error* error) {
AlarmImpl* alarm = static_cast<AlarmImpl*>(arg);
alarm->callback_(error == GRPC_ERROR_NONE);
alarm->Unref();
},
this, grpc_schedule_on_exec_ctx);
grpc_timer_init(&timer_, grpc_timespec_to_millis_round_up(deadline),
&on_alarm_);
}
@ -95,6 +110,7 @@ class AlarmImpl : public CompletionQueueTag {
// completion queue where events about this alarm will be posted
grpc_completion_queue* cq_;
void* tag_;
std::function<void(bool)> callback_;
};
} // namespace internal
@ -113,6 +129,15 @@ void Alarm::SetInternal(CompletionQueue* cq, gpr_timespec deadline, void* tag) {
static_cast<internal::AlarmImpl*>(alarm_)->Set(cq, deadline, tag);
}
void Alarm::SetInternal(gpr_timespec deadline, std::function<void(bool)> f) {
// Note that we know that alarm_ is actually an internal::AlarmImpl
// but we declared it as the base pointer to avoid a forward declaration
// or exposing core data structures in the C++ public headers.
// Thus it is safe to use a static_cast to the subclass here, and the
// C++ style guide allows us to do so in this case
static_cast<internal::AlarmImpl*>(alarm_)->Set(deadline, std::move(f));
}
Alarm::~Alarm() {
if (alarm_ != nullptr) {
static_cast<internal::AlarmImpl*>(alarm_)->Destroy();

@ -1,149 +0,0 @@
/*
*
* Copyright 2018 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <functional>
#include <grpcpp/impl/codegen/callback_common.h>
#include <grpcpp/impl/codegen/status.h>
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/surface/completion_queue.h"
namespace grpc {
namespace internal {
namespace {
template <class Func, class Arg>
void CatchingCallback(Func&& func, Arg&& arg) {
#if GRPC_ALLOW_EXCEPTIONS
try {
func(arg);
} catch (...) {
// nothing to return or change here, just don't crash the library
}
#else // GRPC_ALLOW_EXCEPTIONS
func(arg);
#endif // GRPC_ALLOW_EXCEPTIONS
}
class CallbackWithSuccessImpl : public grpc_core::CQCallbackInterface {
public:
static void operator delete(void* ptr, std::size_t size) {
assert(size == sizeof(CallbackWithSuccessImpl));
}
// 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); }
CallbackWithSuccessImpl(grpc_call* call, CallbackWithSuccessTag* parent,
std::function<void(bool)> f)
: call_(call), parent_(parent), func_(std::move(f)) {
grpc_call_ref(call);
}
void Run(bool ok) override {
void* ignored = parent_->ops();
bool new_ok = ok;
GPR_ASSERT(parent_->ops()->FinalizeResult(&ignored, &new_ok));
GPR_ASSERT(ignored == parent_->ops());
// Last use of func_ or ok, so ok to move them out for rvalue call above
CatchingCallback(std::move(func_), std::move(ok));
func_ = nullptr; // reset to clear this out for sure
grpc_call_unref(call_);
}
private:
grpc_call* call_;
CallbackWithSuccessTag* parent_;
std::function<void(bool)> func_;
};
class CallbackWithStatusImpl : public grpc_core::CQCallbackInterface {
public:
static void operator delete(void* ptr, std::size_t size) {
assert(size == sizeof(CallbackWithStatusImpl));
}
// 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); }
CallbackWithStatusImpl(grpc_call* call, CallbackWithStatusTag* parent,
std::function<void(Status)> f)
: call_(call), parent_(parent), func_(std::move(f)), status_() {
grpc_call_ref(call);
}
void Run(bool ok) override {
void* ignored = parent_->ops();
GPR_ASSERT(parent_->ops()->FinalizeResult(&ignored, &ok));
GPR_ASSERT(ignored == parent_->ops());
// Last use of func_ or status_, so ok to move them out
CatchingCallback(std::move(func_), std::move(status_));
func_ = nullptr; // reset to clear this out for sure
grpc_call_unref(call_);
}
Status* status_ptr() { return &status_; }
private:
grpc_call* call_;
CallbackWithStatusTag* parent_;
std::function<void(Status)> func_;
Status status_;
};
} // namespace
CallbackWithSuccessTag::CallbackWithSuccessTag(grpc_call* call,
std::function<void(bool)> f,
CompletionQueueTag* ops)
: impl_(new (grpc_call_arena_alloc(call, sizeof(CallbackWithSuccessImpl)))
CallbackWithSuccessImpl(call, this, std::move(f))),
ops_(ops) {}
void CallbackWithSuccessTag::force_run(bool ok) { impl_->Run(ok); }
CallbackWithStatusTag::CallbackWithStatusTag(grpc_call* call,
std::function<void(Status)> f,
CompletionQueueTag* ops)
: ops_(ops) {
auto* impl = new (grpc_call_arena_alloc(call, sizeof(CallbackWithStatusImpl)))
CallbackWithStatusImpl(call, this, std::move(f));
impl_ = impl;
status_ = impl->status_ptr();
}
void CallbackWithStatusTag::force_run(Status s) {
*status_ = std::move(s);
impl_->Run(true);
}
} // namespace internal
} // namespace grpc

@ -223,6 +223,7 @@ CORE_SOURCE_FILES = [
'src/core/ext/transport/chttp2/transport/frame_settings.cc',
'src/core/ext/transport/chttp2/transport/frame_window_update.cc',
'src/core/ext/transport/chttp2/transport/hpack_encoder.cc',
'src/core/ext/transport/chttp2/transport/hpack_mapping.cc',
'src/core/ext/transport/chttp2/transport/hpack_parser.cc',
'src/core/ext/transport/chttp2/transport/hpack_table.cc',
'src/core/ext/transport/chttp2/transport/http2_settings.cc',

@ -107,7 +107,7 @@ extern grpc_completion_queue_create_for_next_type grpc_completion_queue_create_f
typedef grpc_completion_queue*(*grpc_completion_queue_create_for_pluck_type)(void* reserved);
extern grpc_completion_queue_create_for_pluck_type grpc_completion_queue_create_for_pluck_import;
#define grpc_completion_queue_create_for_pluck grpc_completion_queue_create_for_pluck_import
typedef grpc_completion_queue*(*grpc_completion_queue_create_for_callback_type)(void* shutdown_callback, void* reserved);
typedef grpc_completion_queue*(*grpc_completion_queue_create_for_callback_type)(grpc_experimental_completion_queue_functor* shutdown_callback, void* reserved);
extern grpc_completion_queue_create_for_callback_type grpc_completion_queue_create_for_callback_import;
#define grpc_completion_queue_create_for_callback grpc_completion_queue_create_for_callback_import
typedef grpc_completion_queue*(*grpc_completion_queue_create_type)(const grpc_completion_queue_factory* factory, const grpc_completion_queue_attributes* attributes, void* reserved);
@ -407,10 +407,10 @@ extern grpc_call_set_credentials_type grpc_call_set_credentials_import;
typedef void(*grpc_server_credentials_set_auth_metadata_processor_type)(grpc_server_credentials* creds, grpc_auth_metadata_processor processor);
extern grpc_server_credentials_set_auth_metadata_processor_type grpc_server_credentials_set_auth_metadata_processor_import;
#define grpc_server_credentials_set_auth_metadata_processor grpc_server_credentials_set_auth_metadata_processor_import
typedef grpc_alts_credentials_options*(*grpc_alts_credentials_client_options_create_type)();
typedef grpc_alts_credentials_options*(*grpc_alts_credentials_client_options_create_type)(void);
extern grpc_alts_credentials_client_options_create_type grpc_alts_credentials_client_options_create_import;
#define grpc_alts_credentials_client_options_create grpc_alts_credentials_client_options_create_import
typedef grpc_alts_credentials_options*(*grpc_alts_credentials_server_options_create_type)();
typedef grpc_alts_credentials_options*(*grpc_alts_credentials_server_options_create_type)(void);
extern grpc_alts_credentials_server_options_create_type grpc_alts_credentials_server_options_create_import;
#define grpc_alts_credentials_server_options_create grpc_alts_credentials_server_options_create_import
typedef void(*grpc_alts_credentials_client_options_add_target_service_account_type)(grpc_alts_credentials_options* options, const char* service_account);

@ -32,7 +32,7 @@ module GRPC
# @return [Proc] { |instance| marshalled(instance) }
def marshal_proc
proc { |o| o.class.method(marshal_method).call(o).to_s }
proc { |o| o.class.send(marshal_method, o).to_s }
end
# @param [:input, :output] target determines whether to produce the an
@ -42,9 +42,9 @@ module GRPC
# @return [Proc] An unmarshal proc { |marshalled(instance)| instance }
def unmarshal_proc(target)
fail ArgumentError unless [:input, :output].include?(target)
unmarshal_class = method(target).call
unmarshal_class = send(target)
unmarshal_class = unmarshal_class.type if unmarshal_class.is_a? Stream
proc { |o| unmarshal_class.method(unmarshal_method).call(o) }
proc { |o| unmarshal_class.send(unmarshal_method, o) }
end
def handle_request_response(active_call, mth, inter_ctx)

@ -30,7 +30,7 @@ end
def create_server_creds
test_root = File.join(File.dirname(__FILE__), 'testdata')
p "test root: #{test_root}"
GRPC.logger.info("test root: #{test_root}")
files = ['ca.pem', 'server1.key', 'server1.pem']
creds = files.map { |f| File.open(File.join(test_root, f)).read }
GRPC::Core::ServerCredentials.new(
@ -59,7 +59,7 @@ class SslTestService
def a_client_streaming_rpc(call)
check_peer_cert(call)
call.each_remote_read.each { |r| p r }
call.each_remote_read.each { |r| GRPC.logger.info(r) }
EchoMsg.new
end
@ -70,7 +70,7 @@ class SslTestService
def a_bidi_rpc(requests, call)
check_peer_cert(call)
requests.each { |r| p r }
requests.each { |r| GRPC.logger.info(r) }
[EchoMsg.new, EchoMsg.new]
end
end
@ -116,11 +116,11 @@ describe 'client-server auth' do
it 'client-server auth with server streaming RPCs' do
responses = @stub.a_server_streaming_rpc(EchoMsg.new)
responses.each { |r| p r }
responses.each { |r| GRPC.logger.info(r) }
end
it 'client-server auth with bidi RPCs' do
responses = @stub.a_bidi_rpc([EchoMsg.new, EchoMsg.new])
responses.each { |r| p r }
responses.each { |r| GRPC.logger.info(r) }
end
end

@ -293,7 +293,7 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength
describe 'without a call operation' do
def get_response(stub, credentials: nil)
puts credentials.inspect
GRPC.logger.info(credentials.inspect)
stub.request_response(@method, @sent_msg, noop, noop,
metadata: @metadata,
credentials: credentials)
@ -342,13 +342,15 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength
it 'sends metadata to the server ok when running start_call first' do
run_op_view_metadata_test(true)
check_op_view_of_finished_client_call(
@op, @server_initial_md, @server_trailing_md) { |r| p r }
@op, @server_initial_md, @server_trailing_md
) { |r| GRPC.logger.info(r) }
end
it 'does not crash when used after the call has been finished' do
run_op_view_metadata_test(false)
check_op_view_of_finished_client_call(
@op, @server_initial_md, @server_trailing_md) { |r| p r }
@op, @server_initial_md, @server_trailing_md
) { |r| GRPC.logger.info(r) }
end
end
end
@ -435,13 +437,15 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength
it 'sends metadata to the server ok when running start_call first' do
run_op_view_metadata_test(true)
check_op_view_of_finished_client_call(
@op, @server_initial_md, @server_trailing_md) { |r| p r }
@op, @server_initial_md, @server_trailing_md
) { |r| GRPC.logger.info(r) }
end
it 'does not crash when used after the call has been finished' do
run_op_view_metadata_test(false)
check_op_view_of_finished_client_call(
@op, @server_initial_md, @server_trailing_md) { |r| p r }
@op, @server_initial_md, @server_trailing_md
) { |r| GRPC.logger.info(r) }
end
end
end
@ -578,7 +582,7 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength
run_op_view_metadata_test(true)
check_op_view_of_finished_client_call(
@op, @server_initial_md, @server_trailing_md) do |responses|
responses.each { |r| p r }
responses.each { |r| GRPC.logger.info(r) }
end
end
@ -586,7 +590,7 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength
run_op_view_metadata_test(false)
check_op_view_of_finished_client_call(
@op, @server_initial_md, @server_trailing_md) do |responses|
responses.each { |r| p r }
responses.each { |r| GRPC.logger.info(r) }
end
end
@ -895,7 +899,7 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength
run_op_view_metadata_test(true)
check_op_view_of_finished_client_call(
@op, @server_initial_md, @server_trailing_md) do |responses|
responses.each { |r| p r }
responses.each { |r| GRPC.logger.info(r) }
end
end
@ -903,7 +907,7 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength
run_op_view_metadata_test(false)
check_op_view_of_finished_client_call(
@op, @server_initial_md, @server_trailing_md) do |responses|
responses.each { |r| p r }
responses.each { |r| GRPC.logger.info(r) }
end
end

@ -125,7 +125,7 @@ class CheckCallAfterFinishedService
fail 'shouldnt reuse service' unless @server_side_call.nil?
@server_side_call = call
# iterate through requests so call can complete
call.each_remote_read.each { |r| p r }
call.each_remote_read.each { |r| GRPC.logger.info(r) }
EchoMsg.new
end
@ -138,7 +138,7 @@ class CheckCallAfterFinishedService
def a_bidi_rpc(requests, call)
fail 'shouldnt reuse service' unless @server_side_call.nil?
@server_side_call = call
requests.each { |r| p r }
requests.each { |r| GRPC.logger.info(r) }
[EchoMsg.new, EchoMsg.new]
end
end
@ -560,7 +560,7 @@ describe GRPC::RpcServer do
'connect_k1' => 'connect_v1'
}
wanted_md.each do |key, value|
puts "key: #{key}"
GRPC.logger.info("key: #{key}")
expect(op.metadata[key]).to eq(value)
end
@srv.stop

@ -50,7 +50,9 @@ class EchoService
def a_client_streaming_rpc(call)
# iterate through requests so call can complete
call.output_metadata.update(@trailing_metadata)
call.each_remote_read.each { |r| p r }
call.each_remote_read.each do |r|
GRPC.logger.info(r)
end
EchoMsg.new
end
@ -61,7 +63,9 @@ class EchoService
def a_bidi_rpc(requests, call)
call.output_metadata.update(@trailing_metadata)
requests.each { |r| p r }
requests.each do |r|
GRPC.logger.info(r)
end
[EchoMsg.new, EchoMsg.new]
end
end
@ -71,35 +75,37 @@ EchoStub = EchoService.rpc_stub_class
# For testing server interceptors
class TestServerInterceptor < GRPC::ServerInterceptor
def request_response(request:, call:, method:)
p "Received request/response call at method #{method}" \
" with request #{request} for call #{call}"
GRPC.logger.info("Received request/response call at method #{method}" \
" with request #{request} for call #{call}")
call.output_metadata[:interc] = 'from_request_response'
p "[GRPC::Ok] (#{method.owner.name}.#{method.name})"
GRPC.logger.info("[GRPC::Ok] (#{method.owner.name}.#{method.name})")
yield
end
def client_streamer(call:, method:)
call.output_metadata[:interc] = 'from_client_streamer'
call.each_remote_read.each do |r|
p "In interceptor: #{r}"
GRPC.logger.info("In interceptor: #{r}")
end
p "Received client streamer call at method #{method} for call #{call}"
GRPC.logger.info(
"Received client streamer call at method #{method} for call #{call}"
)
yield
end
def server_streamer(request:, call:, method:)
p "Received server streamer call at method #{method} with request" \
" #{request} for call #{call}"
GRPC.logger.info("Received server streamer call at method #{method} with request" \
" #{request} for call #{call}")
call.output_metadata[:interc] = 'from_server_streamer'
yield
end
def bidi_streamer(requests:, call:, method:)
requests.each do |r|
p "Bidi request: #{r}"
GRPC.logger.info("Bidi request: #{r}")
end
p "Received bidi streamer call at method #{method} with requests" \
" #{requests} for call #{call}"
GRPC.logger.info("Received bidi streamer call at method #{method} with requests" \
" #{requests} for call #{call}")
call.output_metadata[:interc] = 'from_bidi_streamer'
yield
end
@ -108,38 +114,38 @@ end
# For testing client interceptors
class TestClientInterceptor < GRPC::ClientInterceptor
def request_response(request:, call:, method:, metadata: {})
p "Intercepted request/response call at method #{method}" \
GRPC.logger.info("Intercepted request/response call at method #{method}" \
" with request #{request} for call #{call}" \
" and metadata: #{metadata}"
" and metadata: #{metadata}")
metadata['foo'] = 'bar_from_request_response'
yield
end
def client_streamer(requests:, call:, method:, metadata: {})
p "Received client streamer call at method #{method}" \
GRPC.logger.info("Received client streamer call at method #{method}" \
" with requests #{requests} for call #{call}" \
" and metadata: #{metadata}"
" and metadata: #{metadata}")
requests.each do |r|
p "In client interceptor: #{r}"
GRPC.logger.info("In client interceptor: #{r}")
end
metadata['foo'] = 'bar_from_client_streamer'
yield
end
def server_streamer(request:, call:, method:, metadata: {})
p "Received server streamer call at method #{method}" \
GRPC.logger.info("Received server streamer call at method #{method}" \
" with request #{request} for call #{call}" \
" and metadata: #{metadata}"
" and metadata: #{metadata}")
metadata['foo'] = 'bar_from_server_streamer'
yield
end
def bidi_streamer(requests:, call:, method:, metadata: {})
p "Received bidi streamer call at method #{method}" \
GRPC.logger.info("Received bidi streamer call at method #{method}" \
"with requests #{requests} for call #{call}" \
" and metadata: #{metadata}"
" and metadata: #{metadata}")
requests.each do |r|
p "In client interceptor: #{r}"
GRPC.logger.info("In client interceptor: #{r}")
end
metadata['foo'] = 'bar_from_bidi_streamer'
yield

@ -37,13 +37,16 @@ typedef struct inproc_fixture_data {
namespace {
template <typename F>
class CQDeletingCallback : public grpc_core::CQCallbackInterface {
class CQDeletingCallback : public grpc_experimental_completion_queue_functor {
public:
explicit CQDeletingCallback(F f) : func_(f) {}
~CQDeletingCallback() override {}
void Run(bool ok) override {
func_(ok);
grpc_core::Delete(this);
explicit CQDeletingCallback(F f) : func_(f) {
functor_run = &CQDeletingCallback::Run;
}
~CQDeletingCallback() {}
static void Run(grpc_experimental_completion_queue_functor* cb, int ok) {
auto* callback = static_cast<CQDeletingCallback*>(cb);
callback->func_(static_cast<bool>(ok));
grpc_core::Delete(callback);
}
private:
@ -51,18 +54,24 @@ class CQDeletingCallback : public grpc_core::CQCallbackInterface {
};
template <typename F>
grpc_core::CQCallbackInterface* NewDeletingCallback(F f) {
grpc_experimental_completion_queue_functor* NewDeletingCallback(F f) {
return grpc_core::New<CQDeletingCallback<F>>(f);
}
class ShutdownCallback : public grpc_core::CQCallbackInterface {
class ShutdownCallback : public grpc_experimental_completion_queue_functor {
public:
ShutdownCallback() : done_(false) {
functor_run = &ShutdownCallback::StaticRun;
gpr_mu_init(&mu_);
gpr_cv_init(&cv_);
}
~ShutdownCallback() override {}
void Run(bool ok) override {
~ShutdownCallback() {}
static void StaticRun(grpc_experimental_completion_queue_functor* cb,
int ok) {
auto* callback = static_cast<ShutdownCallback*>(cb);
callback->Run(static_cast<bool>(ok));
}
void Run(bool ok) {
gpr_log(GPR_DEBUG, "CQ shutdown notification invoked");
gpr_mu_lock(&mu_);
done_ = true;
@ -170,7 +179,7 @@ static void verify_tags(gpr_timespec deadline) {
// This function creates a callback functor that emits the
// desired tag into the global tag set
static grpc_core::CQCallbackInterface* tag(intptr_t t) {
static grpc_experimental_completion_queue_functor* tag(intptr_t t) {
auto func = [t](bool ok) {
gpr_mu_lock(&tags_mu);
gpr_log(GPR_DEBUG, "Completing operation %" PRIdPTR, t);

@ -369,11 +369,15 @@ static void test_callback(void) {
LOG_TEST("test_callback");
bool got_shutdown = false;
class ShutdownCallback : public grpc_core::CQCallbackInterface {
class ShutdownCallback : public grpc_experimental_completion_queue_functor {
public:
ShutdownCallback(bool* done) : done_(done) {}
ShutdownCallback(bool* done) : done_(done) {
functor_run = &ShutdownCallback::Run;
}
~ShutdownCallback() {}
void Run(bool ok) override { *done_ = ok; }
static void Run(grpc_experimental_completion_queue_functor* cb, int ok) {
*static_cast<ShutdownCallback*>(cb)->done_ = static_cast<bool>(ok);
}
private:
bool* done_;
@ -391,14 +395,17 @@ static void test_callback(void) {
grpc_completion_queue_factory_lookup(&attr), &attr, nullptr);
int counter = 0;
class TagCallback : public grpc_core::CQCallbackInterface {
class TagCallback : public grpc_experimental_completion_queue_functor {
public:
TagCallback(int* counter, int tag) : counter_(counter), tag_(tag) {}
TagCallback(int* counter, int tag) : counter_(counter), tag_(tag) {
functor_run = &TagCallback::Run;
}
~TagCallback() {}
void Run(bool ok) override {
GPR_ASSERT(ok);
*counter_ += tag_;
grpc_core::Delete(this);
static void Run(grpc_experimental_completion_queue_functor* cb, int ok) {
GPR_ASSERT(static_cast<bool>(ok));
auto* callback = static_cast<TagCallback*>(cb);
*callback->counter_ += callback->tag_;
grpc_core::Delete(callback);
};
private:

@ -202,7 +202,7 @@ static void verify_table_size_change_match_elem_size(const char* key,
grpc_mdelem elem = grpc_mdelem_from_slices(
grpc_slice_intern(grpc_slice_from_static_string(key)),
grpc_slice_intern(grpc_slice_from_static_string(value)));
size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem, use_true_binary);
size_t elem_size = grpc_chttp2_get_size_in_hpack_table(elem, use_true_binary);
size_t initial_table_size = g_compressor.table_size;
grpc_linked_mdelem* e =
static_cast<grpc_linked_mdelem*>(gpr_malloc(sizeof(*e)));

@ -27,6 +27,7 @@
#include <grpc/support/string_util.h>
#include "src/core/ext/transport/chttp2/transport/bin_encoder.h"
#include "src/core/ext/transport/chttp2/transport/hpack_table.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/slice/slice_internal.h"
@ -293,7 +294,7 @@ static void verify_ascii_header_size(const char* key, const char* value,
grpc_mdelem elem = grpc_mdelem_from_slices(
maybe_intern(grpc_slice_from_static_string(key), intern_key),
maybe_intern(grpc_slice_from_static_string(value), intern_value));
size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem, false);
size_t elem_size = grpc_chttp2_get_size_in_hpack_table(elem, false);
size_t expected_size = 32 + strlen(key) + strlen(value);
GPR_ASSERT(expected_size == elem_size);
GRPC_MDELEM_UNREF(elem);
@ -307,7 +308,7 @@ static void verify_binary_header_size(const char* key, const uint8_t* value,
maybe_intern(grpc_slice_from_static_buffer(value, value_len),
intern_value));
GPR_ASSERT(grpc_is_binary_header(GRPC_MDKEY(elem)));
size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem, false);
size_t elem_size = grpc_chttp2_get_size_in_hpack_table(elem, false);
grpc_slice value_slice = grpc_slice_from_copied_buffer(
reinterpret_cast<const char*>(value), value_len);
grpc_slice base64_encoded = grpc_chttp2_base64_encode(value_slice);

@ -26,6 +26,7 @@
#include "src/proto/grpc/testing/compiler_test.pb.h"
#include <functional>
#include <grpcpp/impl/codegen/async_generic_service.h>
#include <grpcpp/impl/codegen/async_stream.h>
#include <grpcpp/impl/codegen/async_unary_call.h>
@ -105,6 +106,23 @@ class ServiceA final {
return std::unique_ptr< ::grpc::ClientAsyncReaderWriterInterface< ::grpc::testing::Request, ::grpc::testing::Response>>(PrepareAsyncMethodA4Raw(context, cq));
}
// Method A4 trailing comment 1
class experimental_async_interface {
public:
virtual ~experimental_async_interface() {}
// MethodA1 leading comment 1
virtual void MethodA1(::grpc::ClientContext* context, const ::grpc::testing::Request* request, ::grpc::testing::Response* response, std::function<void(::grpc::Status)>) = 0;
// MethodA1 trailing comment 1
// MethodA2 detached leading comment 1
//
// Method A2 leading comment 1
// Method A2 leading comment 2
// MethodA2 trailing comment 1
// Method A3 leading comment 1
// Method A3 trailing comment 1
// Method A4 leading comment 1
// Method A4 trailing comment 1
};
virtual class experimental_async_interface* experimental_async() { return nullptr; }
private:
virtual ::grpc::ClientAsyncResponseReaderInterface< ::grpc::testing::Response>* AsyncMethodA1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) = 0;
virtual ::grpc::ClientAsyncResponseReaderInterface< ::grpc::testing::Response>* PrepareAsyncMethodA1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) = 0;
@ -155,9 +173,21 @@ class ServiceA final {
std::unique_ptr< ::grpc::ClientAsyncReaderWriter< ::grpc::testing::Request, ::grpc::testing::Response>> PrepareAsyncMethodA4(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncReaderWriter< ::grpc::testing::Request, ::grpc::testing::Response>>(PrepareAsyncMethodA4Raw(context, cq));
}
class experimental_async final :
public StubInterface::experimental_async_interface {
public:
void MethodA1(::grpc::ClientContext* context, const ::grpc::testing::Request* request, ::grpc::testing::Response* response, std::function<void(::grpc::Status)>) override;
private:
friend class Stub;
explicit experimental_async(Stub* stub): stub_(stub) { }
Stub* stub() { return stub_; }
Stub* stub_;
};
class experimental_async_interface* experimental_async() override { return &async_stub_; }
private:
std::shared_ptr< ::grpc::ChannelInterface> channel_;
class experimental_async async_stub_{this};
::grpc::ClientAsyncResponseReader< ::grpc::testing::Response>* AsyncMethodA1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) override;
::grpc::ClientAsyncResponseReader< ::grpc::testing::Response>* PrepareAsyncMethodA1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) override;
::grpc::ClientWriter< ::grpc::testing::Request>* MethodA2Raw(::grpc::ClientContext* context, ::grpc::testing::Response* response) override;
@ -488,6 +518,14 @@ class ServiceB final {
return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::grpc::testing::Response>>(PrepareAsyncMethodB1Raw(context, request, cq));
}
// MethodB1 trailing comment 1
class experimental_async_interface {
public:
virtual ~experimental_async_interface() {}
// MethodB1 leading comment 1
virtual void MethodB1(::grpc::ClientContext* context, const ::grpc::testing::Request* request, ::grpc::testing::Response* response, std::function<void(::grpc::Status)>) = 0;
// MethodB1 trailing comment 1
};
virtual class experimental_async_interface* experimental_async() { return nullptr; }
private:
virtual ::grpc::ClientAsyncResponseReaderInterface< ::grpc::testing::Response>* AsyncMethodB1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) = 0;
virtual ::grpc::ClientAsyncResponseReaderInterface< ::grpc::testing::Response>* PrepareAsyncMethodB1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) = 0;
@ -502,9 +540,21 @@ class ServiceB final {
std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::grpc::testing::Response>> PrepareAsyncMethodB1(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::grpc::testing::Response>>(PrepareAsyncMethodB1Raw(context, request, cq));
}
class experimental_async final :
public StubInterface::experimental_async_interface {
public:
void MethodB1(::grpc::ClientContext* context, const ::grpc::testing::Request* request, ::grpc::testing::Response* response, std::function<void(::grpc::Status)>) override;
private:
friend class Stub;
explicit experimental_async(Stub* stub): stub_(stub) { }
Stub* stub() { return stub_; }
Stub* stub_;
};
class experimental_async_interface* experimental_async() override { return &async_stub_; }
private:
std::shared_ptr< ::grpc::ChannelInterface> channel_;
class experimental_async async_stub_{this};
::grpc::ClientAsyncResponseReader< ::grpc::testing::Response>* AsyncMethodB1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) override;
::grpc::ClientAsyncResponseReader< ::grpc::testing::Response>* PrepareAsyncMethodB1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) override;
const ::grpc::internal::RpcMethod rpcmethod_MethodB1_;

@ -16,9 +16,13 @@
*
*/
#include <condition_variable>
#include <memory>
#include <mutex>
#include <thread>
#include <grpcpp/alarm.h>
#include <grpcpp/completion_queue.h>
#include <thread>
#include <gtest/gtest.h>
@ -43,6 +47,66 @@ TEST(AlarmTest, RegularExpiry) {
EXPECT_EQ(junk, output_tag);
}
struct Completion {
bool completed = false;
std::mutex mu;
std::condition_variable cv;
};
TEST(AlarmTest, CallbackRegularExpiry) {
Alarm alarm;
auto c = std::make_shared<Completion>();
alarm.experimental().Set(
std::chrono::system_clock::now() + std::chrono::seconds(1), [c](bool ok) {
EXPECT_TRUE(ok);
std::lock_guard<std::mutex> l(c->mu);
c->completed = true;
c->cv.notify_one();
});
std::unique_lock<std::mutex> l(c->mu);
EXPECT_TRUE(c->cv.wait_until(
l, std::chrono::system_clock::now() + std::chrono::seconds(10),
[c] { return c->completed; }));
}
TEST(AlarmTest, CallbackZeroExpiry) {
Alarm alarm;
auto c = std::make_shared<Completion>();
alarm.experimental().Set(grpc_timeout_seconds_to_deadline(0), [c](bool ok) {
EXPECT_TRUE(ok);
std::lock_guard<std::mutex> l(c->mu);
c->completed = true;
c->cv.notify_one();
});
std::unique_lock<std::mutex> l(c->mu);
EXPECT_TRUE(c->cv.wait_until(
l, std::chrono::system_clock::now() + std::chrono::seconds(10),
[c] { return c->completed; }));
}
TEST(AlarmTest, CallbackNegativeExpiry) {
Alarm alarm;
auto c = std::make_shared<Completion>();
alarm.experimental().Set(
std::chrono::system_clock::now() + std::chrono::seconds(-1),
[c](bool ok) {
EXPECT_TRUE(ok);
std::lock_guard<std::mutex> l(c->mu);
c->completed = true;
c->cv.notify_one();
});
std::unique_lock<std::mutex> l(c->mu);
EXPECT_TRUE(c->cv.wait_until(
l, std::chrono::system_clock::now() + std::chrono::seconds(10),
[c] { return c->completed; }));
}
TEST(AlarmTest, MultithreadedRegularExpiry) {
CompletionQueue cq;
void* junk = reinterpret_cast<void*>(1618033);
@ -182,6 +246,26 @@ TEST(AlarmTest, Cancellation) {
EXPECT_EQ(junk, output_tag);
}
TEST(AlarmTest, CallbackCancellation) {
Alarm alarm;
auto c = std::make_shared<Completion>();
alarm.experimental().Set(
std::chrono::system_clock::now() + std::chrono::seconds(10),
[c](bool ok) {
EXPECT_FALSE(ok);
std::lock_guard<std::mutex> l(c->mu);
c->completed = true;
c->cv.notify_one();
});
alarm.Cancel();
std::unique_lock<std::mutex> l(c->mu);
EXPECT_TRUE(c->cv.wait_until(
l, std::chrono::system_clock::now() + std::chrono::seconds(1),
[c] { return c->completed; }));
}
TEST(AlarmTest, SetDestruction) {
CompletionQueue cq;
void* junk = reinterpret_cast<void*>(1618033);
@ -200,6 +284,26 @@ TEST(AlarmTest, SetDestruction) {
EXPECT_EQ(junk, output_tag);
}
TEST(AlarmTest, CallbackSetDestruction) {
auto c = std::make_shared<Completion>();
{
Alarm alarm;
alarm.experimental().Set(
std::chrono::system_clock::now() + std::chrono::seconds(10),
[c](bool ok) {
EXPECT_FALSE(ok);
std::lock_guard<std::mutex> l(c->mu);
c->completed = true;
c->cv.notify_one();
});
}
std::unique_lock<std::mutex> l(c->mu);
EXPECT_TRUE(c->cv.wait_until(
l, std::chrono::system_clock::now() + std::chrono::seconds(1),
[c] { return c->completed; }));
}
TEST(AlarmTest, UnsetDestruction) {
CompletionQueue cq;
Alarm alarm;

@ -178,7 +178,7 @@ class Verifier {
EXPECT_EQ(it2->second.ok, ok);
}
} else {
gpr_log(GPR_ERROR, "Unexpected tag: %p", tag);
gpr_log(GPR_ERROR, "Unexpected tag: %p", got_tag);
abort();
}
}

@ -18,6 +18,7 @@
#include <functional>
#include <mutex>
#include <thread>
#include <grpcpp/channel.h>
#include <grpcpp/client_context.h>
@ -55,7 +56,8 @@ class ClientCallbackEnd2endTest : public ::testing::Test {
void ResetStub() {
ChannelArguments args;
channel_ = server_->InProcessChannel(args);
stub_.reset(new GenericStub(channel_));
stub_ = grpc::testing::EchoTestService::NewStub(channel_);
generic_stub_.reset(new GenericStub(channel_));
}
void TearDown() override {
@ -64,7 +66,45 @@ class ClientCallbackEnd2endTest : public ::testing::Test {
}
}
void SendRpcs(int num_rpcs, bool maybe_except) {
void SendRpcs(int num_rpcs, bool with_binary_metadata) {
grpc::string test_string("");
for (int i = 0; i < num_rpcs; i++) {
EchoRequest request;
EchoResponse response;
ClientContext cli_ctx;
test_string += "Hello world. ";
request.set_message(test_string);
if (with_binary_metadata) {
char bytes[8] = {'\0', '\1', '\2', '\3',
'\4', '\5', '\6', static_cast<char>(i)};
cli_ctx.AddMetadata("custom-bin", grpc::string(bytes, 8));
}
cli_ctx.set_compression_algorithm(GRPC_COMPRESS_GZIP);
std::mutex mu;
std::condition_variable cv;
bool done = false;
stub_->experimental_async()->Echo(
&cli_ctx, &request, &response,
[&request, &response, &done, &mu, &cv](Status s) {
GPR_ASSERT(s.ok());
EXPECT_EQ(request.message(), response.message());
std::lock_guard<std::mutex> l(mu);
done = true;
cv.notify_one();
});
std::unique_lock<std::mutex> l(mu);
while (!done) {
cv.wait(l);
}
}
}
void SendRpcsGeneric(int num_rpcs, bool maybe_except) {
const grpc::string kMethodName("/grpc.testing.EchoTestService/Echo");
grpc::string test_string("");
for (int i = 0; i < num_rpcs; i++) {
@ -80,7 +120,7 @@ class ClientCallbackEnd2endTest : public ::testing::Test {
std::mutex mu;
std::condition_variable cv;
bool done = false;
stub_->experimental().UnaryCall(
generic_stub_->experimental().UnaryCall(
&cli_ctx, kMethodName, send_buf.get(), &recv_buf,
[&request, &recv_buf, &done, &mu, &cv, maybe_except](Status s) {
GPR_ASSERT(s.ok());
@ -95,6 +135,8 @@ class ClientCallbackEnd2endTest : public ::testing::Test {
if (maybe_except) {
throw - 1;
}
#else
GPR_ASSERT(!maybe_except);
#endif
});
std::unique_lock<std::mutex> l(mu);
@ -103,9 +145,11 @@ class ClientCallbackEnd2endTest : public ::testing::Test {
}
}
}
bool is_server_started_;
std::shared_ptr<Channel> channel_;
std::unique_ptr<grpc::GenericStub> stub_;
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
std::unique_ptr<grpc::GenericStub> generic_stub_;
TestServiceImpl service_;
std::unique_ptr<Server> server_;
};
@ -120,13 +164,72 @@ TEST_F(ClientCallbackEnd2endTest, SequentialRpcs) {
SendRpcs(10, false);
}
TEST_F(ClientCallbackEnd2endTest, SequentialRpcsWithVariedBinaryMetadataValue) {
ResetStub();
SendRpcs(10, true);
}
TEST_F(ClientCallbackEnd2endTest, SequentialGenericRpcs) {
ResetStub();
SendRpcsGeneric(10, false);
}
#if GRPC_ALLOW_EXCEPTIONS
TEST_F(ClientCallbackEnd2endTest, ExceptingRpc) {
ResetStub();
SendRpcs(10, true);
SendRpcsGeneric(10, true);
}
#endif
TEST_F(ClientCallbackEnd2endTest, MultipleRpcsWithVariedBinaryMetadataValue) {
ResetStub();
std::vector<std::thread> threads;
threads.reserve(10);
for (int i = 0; i < 10; ++i) {
threads.emplace_back([this] { SendRpcs(10, true); });
}
for (int i = 0; i < 10; ++i) {
threads[i].join();
}
}
TEST_F(ClientCallbackEnd2endTest, MultipleRpcs) {
ResetStub();
std::vector<std::thread> threads;
threads.reserve(10);
for (int i = 0; i < 10; ++i) {
threads.emplace_back([this] { SendRpcs(10, false); });
}
for (int i = 0; i < 10; ++i) {
threads[i].join();
}
}
TEST_F(ClientCallbackEnd2endTest, CancelRpcBeforeStart) {
ResetStub();
EchoRequest request;
EchoResponse response;
ClientContext context;
request.set_message("hello");
context.TryCancel();
std::mutex mu;
std::condition_variable cv;
bool done = false;
stub_->experimental_async()->Echo(
&context, &request, &response, [&response, &done, &mu, &cv](Status s) {
EXPECT_EQ("", response.message());
EXPECT_EQ(grpc::StatusCode::CANCELLED, s.error_code());
std::lock_guard<std::mutex> l(mu);
done = true;
cv.notify_one();
});
std::unique_lock<std::mutex> l(mu);
while (!done) {
cv.wait(l);
}
}
} // namespace
} // namespace testing
} // namespace grpc

@ -119,6 +119,7 @@ class ClientLbEnd2endTest : public ::testing::Test {
}
void SetUp() override {
grpc_init();
response_generator_ =
grpc_core::MakeRefCounted<grpc_core::FakeResolverResponseGenerator>();
}
@ -127,6 +128,7 @@ class ClientLbEnd2endTest : public ::testing::Test {
for (size_t i = 0; i < servers_.size(); ++i) {
servers_[i]->Shutdown();
}
grpc_shutdown();
}
void CreateServers(size_t num_servers,
@ -560,7 +562,23 @@ TEST_F(ClientLbEnd2endTest, PickFirstUpdateSuperset) {
EXPECT_EQ("pick_first", channel->GetLoadBalancingPolicyName());
}
TEST_F(ClientLbEnd2endTest, PickFirstManyUpdates) {
class ClientLbEnd2endWithParamTest
: public ClientLbEnd2endTest,
public ::testing::WithParamInterface<bool> {
protected:
void SetUp() override {
grpc_subchannel_index_test_only_set_force_creation(GetParam());
ClientLbEnd2endTest::SetUp();
}
void TearDown() override {
ClientLbEnd2endTest::TearDown();
grpc_subchannel_index_test_only_set_force_creation(false);
}
};
TEST_P(ClientLbEnd2endWithParamTest, PickFirstManyUpdates) {
gpr_log(GPR_INFO, "subchannel force creation: %d", GetParam());
// Start servers and send one RPC per server.
const int kNumServers = 3;
StartServers(kNumServers);
@ -570,20 +588,21 @@ TEST_F(ClientLbEnd2endTest, PickFirstManyUpdates) {
for (size_t i = 0; i < servers_.size(); ++i) {
ports.emplace_back(servers_[i]->port_);
}
for (const bool force_creation : {true, false}) {
grpc_subchannel_index_test_only_set_force_creation(force_creation);
gpr_log(GPR_INFO, "Force subchannel creation: %d", force_creation);
for (size_t i = 0; i < 1000; ++i) {
std::shuffle(ports.begin(), ports.end(),
std::mt19937(std::random_device()()));
SetNextResolution(ports);
if (i % 10 == 0) CheckRpcSendOk(stub, DEBUG_LOCATION);
}
for (size_t i = 0; i < 1000; ++i) {
std::shuffle(ports.begin(), ports.end(),
std::mt19937(std::random_device()()));
SetNextResolution(ports);
// We should re-enter core at the end of the loop to give the resolution
// setting closure a chance to run.
if ((i + 1) % 10 == 0) CheckRpcSendOk(stub, DEBUG_LOCATION);
}
// Check LB policy name for the channel.
EXPECT_EQ("pick_first", channel->GetLoadBalancingPolicyName());
}
INSTANTIATE_TEST_CASE_P(SubchannelForceCreation, ClientLbEnd2endWithParamTest,
::testing::Bool());
TEST_F(ClientLbEnd2endTest, PickFirstReresolutionNoSelected) {
// Prepare the ports for up servers and down servers.
const int kNumServers = 3;
@ -984,8 +1003,6 @@ TEST_F(ClientLbEnd2endTest, RoundRobinSingleReconnect) {
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
grpc_test_init(argc, argv);
grpc_init();
const auto result = RUN_ALL_TESTS();
grpc_shutdown();
return result;
}

@ -27,6 +27,7 @@
#include "src/core/ext/transport/chttp2/transport/hpack_encoder.h"
#include "src/core/ext/transport/chttp2/transport/hpack_parser.h"
#include "src/core/ext/transport/chttp2/transport/incoming_metadata.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/transport/static_metadata.h"
@ -456,8 +457,9 @@ static void BM_HpackParserParseHeader(benchmark::State& state) {
std::vector<grpc_slice> benchmark_slices = Fixture::GetBenchmarkSlices();
grpc_chttp2_hpack_parser p;
grpc_chttp2_hpack_parser_init(&p);
const int kArenaSize = 4096 * 4096;
p.on_header_user_data = gpr_arena_create(kArenaSize);
p.on_header = OnHeader;
p.on_header_user_data = nullptr;
for (auto slice : init_slices) {
GPR_ASSERT(GRPC_ERROR_NONE == grpc_chttp2_hpack_parser_parse(&p, slice));
}
@ -466,7 +468,14 @@ static void BM_HpackParserParseHeader(benchmark::State& state) {
GPR_ASSERT(GRPC_ERROR_NONE == grpc_chttp2_hpack_parser_parse(&p, slice));
}
grpc_core::ExecCtx::Get()->Flush();
// Recreate arena every 4k iterations to avoid oom
if (0 == (state.iterations() & 0xfff)) {
gpr_arena_destroy((gpr_arena*)p.on_header_user_data);
p.on_header_user_data = gpr_arena_create(kArenaSize);
}
}
// Clean up
gpr_arena_destroy((gpr_arena*)p.on_header_user_data);
for (auto slice : init_slices) grpc_slice_unref(slice);
for (auto slice : benchmark_slices) grpc_slice_unref(slice);
grpc_chttp2_hpack_parser_destroy(&p);
@ -766,8 +775,58 @@ class RepresentativeServerTrailingMetadata {
static void free_timeout(void* p) { gpr_free(p); }
// New implementation.
static void OnHeaderNew(void* user_data, grpc_mdelem md) {
// Benchmark the current on_initial_header implementation
static void OnInitialHeader(void* user_data, grpc_mdelem md) {
// Setup for benchmark. This will bloat the absolute values of this benchmark
grpc_chttp2_incoming_metadata_buffer buffer;
grpc_chttp2_incoming_metadata_buffer_init(&buffer, (gpr_arena*)user_data);
bool seen_error = false;
// Below here is the code we actually care about benchmarking
if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) &&
!grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) {
seen_error = true;
}
if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) {
grpc_millis* cached_timeout =
static_cast<grpc_millis*>(grpc_mdelem_get_user_data(md, free_timeout));
grpc_millis timeout;
if (cached_timeout != nullptr) {
timeout = *cached_timeout;
} else {
if (GPR_UNLIKELY(
!grpc_http2_decode_timeout(GRPC_MDVALUE(md), &timeout))) {
char* val = grpc_slice_to_c_string(GRPC_MDVALUE(md));
gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val);
gpr_free(val);
timeout = GRPC_MILLIS_INF_FUTURE;
}
if (GRPC_MDELEM_IS_INTERNED(md)) {
/* not already parsed: parse it now, and store the
* result away */
cached_timeout =
static_cast<grpc_millis*>(gpr_malloc(sizeof(grpc_millis)));
*cached_timeout = timeout;
grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
}
}
benchmark::DoNotOptimize(timeout);
GRPC_MDELEM_UNREF(md);
} else {
const size_t new_size = buffer.size + GRPC_MDELEM_LENGTH(md);
if (!seen_error) {
buffer.size = new_size;
}
grpc_error* error = grpc_chttp2_incoming_metadata_buffer_add(&buffer, md);
if (error != GRPC_ERROR_NONE) {
GPR_ASSERT(0);
}
}
grpc_chttp2_incoming_metadata_buffer_destroy(&buffer);
}
// Benchmark timeout handling
static void OnHeaderTimeout(void* user_data, grpc_mdelem md) {
if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) {
grpc_millis* cached_timeout =
static_cast<grpc_millis*>(grpc_mdelem_get_user_data(md, free_timeout));
@ -853,8 +912,13 @@ BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
RepresentativeServerInitialMetadata, UnrefHeader);
BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
RepresentativeServerTrailingMetadata, UnrefHeader);
BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, SameDeadline, OnHeaderNew);
BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
RepresentativeClientInitialMetadata, OnInitialHeader);
BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
MoreRepresentativeClientInitialMetadata, OnInitialHeader);
BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
RepresentativeServerInitialMetadata, OnInitialHeader);
BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, SameDeadline, OnHeaderTimeout);
} // namespace hpack_parser_fixtures

@ -48,6 +48,7 @@ namespace testing {
class FixtureConfiguration {
public:
virtual ~FixtureConfiguration() {}
virtual void ApplyCommonChannelArguments(ChannelArguments* c) const {
c->SetInt(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH, INT_MAX);
c->SetInt(GRPC_ARG_MAX_SEND_MESSAGE_LENGTH, INT_MAX);

@ -63,6 +63,7 @@ extern gpr_atm gpr_now_call_count;
class TrackCounters {
public:
TrackCounters() { grpc_stats_collect(&stats_begin_); }
virtual ~TrackCounters() {}
virtual void Finish(benchmark::State& state);
virtual void AddLabel(const grpc::string& label);
virtual void AddToLabel(std::ostream& out, benchmark::State& state);

@ -23,10 +23,14 @@ import subprocess
import re
import perfection
# configuration: a list of either strings or 2-tuples of strings
# a single string represents a static grpc_mdstr
# a 2-tuple represents a static grpc_mdelem (and appropriate grpc_mdstrs will
# also be created)
# Configuration: a list of either strings or 2-tuples of strings or 3-tuples of
# strings.
# A single string represents a static grpc_mdstr.
# A 2-tuple represents a static grpc_mdelem (and appropriate grpc_mdstrs will
# also be created).
# A 3-tuple represents a static grpc_mdelem (and appropriate grpc_mdstrs will
# also be created), with the last value equivalent to the mdelem's static hpack
# table index as defined by RFC 7541
CONFIG = [
# metadata strings
@ -72,105 +76,104 @@ CONFIG = [
('grpc-encoding', 'deflate'),
('te', 'trailers'),
('content-type', 'application/grpc'),
(':method', 'POST'),
(':status', '200'),
(':status', '404'),
(':scheme', 'http'),
(':scheme', 'https'),
(':scheme', 'grpc'),
(':authority', ''),
(':method', 'GET'),
(':method', 'POST', 3),
(':status', '200', 8),
(':status', '404', 13),
(':scheme', 'http', 6),
(':scheme', 'https', 7),
(':scheme', 'grpc', 0),
(':authority', '', 1),
(':method', 'GET', 2),
(':method', 'PUT'),
(':path', '/'),
(':path', '/index.html'),
(':status', '204'),
(':status', '206'),
(':status', '304'),
(':status', '400'),
(':status', '500'),
('accept-charset', ''),
(':path', '/', 4),
(':path', '/index.html', 5),
(':status', '204', 9),
(':status', '206', 10),
(':status', '304', 11),
(':status', '400', 12),
(':status', '500', 14),
('accept-charset', '', 15),
('accept-encoding', ''),
('accept-encoding', 'gzip, deflate'),
('accept-language', ''),
('accept-ranges', ''),
('accept', ''),
('access-control-allow-origin', ''),
('age', ''),
('allow', ''),
('authorization', ''),
('cache-control', ''),
('content-disposition', ''),
('accept-encoding', 'gzip, deflate', 16),
('accept-language', '', 17),
('accept-ranges', '', 18),
('accept', '', 19),
('access-control-allow-origin', '', 20),
('age', '', 21),
('allow', '', 22),
('authorization', '', 23),
('cache-control', '', 24),
('content-disposition', '', 25),
('content-encoding', 'identity'),
('content-encoding', 'gzip'),
('content-encoding', ''),
('content-language', ''),
('content-length', ''),
('content-location', ''),
('content-range', ''),
('content-type', ''),
('cookie', ''),
('date', ''),
('etag', ''),
('expect', ''),
('expires', ''),
('from', ''),
('host', ''),
('if-match', ''),
('if-modified-since', ''),
('if-none-match', ''),
('if-range', ''),
('if-unmodified-since', ''),
('last-modified', ''),
('content-encoding', '', 26),
('content-language', '', 27),
('content-length', '', 28),
('content-location', '', 29),
('content-range', '', 30),
('content-type', '', 31),
('cookie', '', 32),
('date', '', 33),
('etag', '', 34),
('expect', '', 35),
('expires', '', 36),
('from', '', 37),
('host', '', 38),
('if-match', '', 39),
('if-modified-since', '', 40),
('if-none-match', '', 41),
('if-range', '', 42),
('if-unmodified-since', '', 43),
('last-modified', '', 44),
('lb-token', ''),
('lb-cost-bin', ''),
('link', ''),
('location', ''),
('max-forwards', ''),
('proxy-authenticate', ''),
('proxy-authorization', ''),
('range', ''),
('referer', ''),
('refresh', ''),
('retry-after', ''),
('server', ''),
('set-cookie', ''),
('strict-transport-security', ''),
('transfer-encoding', ''),
('user-agent', ''),
('vary', ''),
('via', ''),
('www-authenticate', ''),
('link', '', 45),
('location', '', 46),
('max-forwards', '', 47),
('proxy-authenticate', '', 48),
('proxy-authorization', '', 49),
('range', '', 50),
('referer', '', 51),
('refresh', '', 52),
('retry-after', '', 53),
('server', '', 54),
('set-cookie', '', 55),
('strict-transport-security', '', 56),
('transfer-encoding', '', 57),
('user-agent', '', 58),
('vary', '', 59),
('via', '', 60),
('www-authenticate', '', 61),
]
# Entries marked with is_default=True are ignored when counting
# non-default initial metadata that prevents the chttp2 server from
# sending a Trailers-Only response.
# All entries here are ignored when counting non-default initial metadata that
# prevents the chttp2 server from sending a Trailers-Only response.
METADATA_BATCH_CALLOUTS = [
# (name, is_default)
(':path', True),
(':method', True),
(':status', True),
(':authority', True),
(':scheme', True),
('te', True),
('grpc-message', True),
('grpc-status', True),
('grpc-payload-bin', True),
('grpc-encoding', True),
('grpc-accept-encoding', True),
('grpc-server-stats-bin', True),
('grpc-tags-bin', True),
('grpc-trace-bin', True),
('content-type', True),
('content-encoding', True),
('accept-encoding', True),
('grpc-internal-encoding-request', True),
('grpc-internal-stream-encoding-request', True),
('user-agent', True),
('host', True),
('lb-token', True),
('grpc-previous-rpc-attempts', True),
('grpc-retry-pushback-ms', True),
# (name)
(':path'),
(':method'),
(':status'),
(':authority'),
(':scheme'),
('te'),
('grpc-message'),
('grpc-status'),
('grpc-payload-bin'),
('grpc-encoding'),
('grpc-accept-encoding'),
('grpc-server-stats-bin'),
('grpc-tags-bin'),
('grpc-trace-bin'),
('content-type'),
('content-encoding'),
('accept-encoding'),
('grpc-internal-encoding-request'),
('grpc-internal-stream-encoding-request'),
('user-agent'),
('host'),
('lb-token'),
('grpc-previous-rpc-attempts'),
('grpc-retry-pushback-ms'),
]
COMPRESSION_ALGORITHMS = [
@ -252,7 +255,7 @@ all_elems = list()
static_userdata = {}
# put metadata batch callouts first, to make the check of if a static metadata
# string is a callout trivial
for elem, _ in METADATA_BATCH_CALLOUTS:
for elem in METADATA_BATCH_CALLOUTS:
if elem not in all_strs:
all_strs.append(elem)
for elem in CONFIG:
@ -323,6 +326,17 @@ else:
os.path.dirname(sys.argv[0]),
'../../../test/core/end2end/fuzzers/hpack.dictionary'), 'w')
HPACK_H = open(
os.path.join(
os.path.dirname(sys.argv[0]),
'../../../src/core/ext/transport/chttp2/transport/hpack_mapping.h'),
'w')
HPACK_C = open(
os.path.join(
os.path.dirname(sys.argv[0]),
'../../../src/core/ext/transport/chttp2/transport/hpack_mapping.cc'),
'w')
# copy-paste copyright notice from this file
with open(sys.argv[0]) as my_source:
copyright = []
@ -337,7 +351,8 @@ with open(sys.argv[0]) as my_source:
if line[0] != '#':
break
copyright.append(line)
put_banner([H, C], [line[2:].rstrip() for line in copyright])
put_banner([H, C, HPACK_H, HPACK_C],
[line[2:].rstrip() for line in copyright])
hex_bytes = [ord(c) for c in 'abcdefABCDEF0123456789']
@ -364,16 +379,44 @@ See metadata.h for an explanation of the interface here, and metadata.cc for
an explanation of what's going on.
""".splitlines())
put_banner([HPACK_H, HPACK_C], """WARNING: Auto-generated code.
To make changes to this file, change
tools/codegen/core/gen_static_metadata.py, and then re-run it.
This file contains the mapping from the index of each metadata element in the
grpc static metadata table to the index of that element in the hpack static
metadata table. If the element is not contained in the static hpack table, then
the returned index is 0.
""".splitlines())
print >> H, '#ifndef GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H'
print >> H, '#define GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H'
print >> H
print >> H, '#include <grpc/support/port_platform.h>'
print >> H
print >> H, '#include "src/core/lib/transport/metadata.h"'
print >> H
print >> C, '#include <grpc/support/port_platform.h>'
print >> C
print >> C, '#include "src/core/lib/transport/static_metadata.h"'
print >> C
print >> C, '#include "src/core/lib/slice/slice_internal.h"'
print >> C
print >> HPACK_H, ('#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_'
'MAPPING_H')
print >> HPACK_H, ('#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_'
'MAPPING_H')
print >> HPACK_H
print >> HPACK_H, '#include <grpc/support/port_platform.h>'
print >> HPACK_H
print >> HPACK_H, '#include "src/core/lib/transport/static_metadata.h"'
print >> HPACK_H
print >> HPACK_C, '#include <grpc/support/port_platform.h>'
print >> HPACK_C
print >> HPACK_C, ('#include '
'"src/core/ext/transport/chttp2/transport/hpack_mapping.h"')
print >> HPACK_C
str_ofs = 0
id2strofs = {}
@ -388,7 +431,7 @@ def slice_def(i):
# validate configuration
for elem, _ in METADATA_BATCH_CALLOUTS:
for elem in METADATA_BATCH_CALLOUTS:
assert elem in all_strs
print >> H, '#define GRPC_STATIC_MDSTR_COUNT %d' % len(all_strs)
@ -450,10 +493,28 @@ print >> H, ('extern grpc_mdelem_data '
print >> H, ('extern uintptr_t '
'grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT];')
for i, elem in enumerate(all_elems):
print >> H, '/* "%s": "%s" */' % elem
print >> H, '/* "%s": "%s" */' % (elem[0], elem[1])
print >> H, ('#define %s (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[%d], '
'GRPC_MDELEM_STORAGE_STATIC))') % (mangle(elem).upper(), i)
print >> H
# Print out the chttp2 mapping between static mdelem index and the hpack static
# table index
print >> HPACK_H, ('extern const uint8_t grpc_hpack_static_mdelem_indices['
'GRPC_STATIC_MDELEM_COUNT];')
print >> HPACK_H
print >> HPACK_C, ('const uint8_t grpc_hpack_static_mdelem_indices['
'GRPC_STATIC_MDELEM_COUNT] = {')
indices = ''
for elem in all_elems:
index = 0
if len(elem) == 3:
index = elem[2]
indices += '%d,' % index
print >> HPACK_C, ' %s' % indices
print >> HPACK_C, '};'
print >> HPACK_C
print >> C, ('uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] '
'= {')
print >> C, ' %s' % ','.join(
@ -546,12 +607,13 @@ print >> C, '}'
print >> C
print >> C, 'grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT] = {'
for a, b in all_elems:
print >> C, '{%s,%s},' % (slice_def(str_idx(a)), slice_def(str_idx(b)))
for elem in all_elems:
print >> C, '{%s,%s},' % (slice_def(str_idx(elem[0])),
slice_def(str_idx(elem[1])))
print >> C, '};'
print >> H, 'typedef enum {'
for elem, _ in METADATA_BATCH_CALLOUTS:
for elem in METADATA_BATCH_CALLOUTS:
print >> H, ' %s,' % mangle(elem, 'batch').upper()
print >> H, ' GRPC_BATCH_CALLOUTS_COUNT'
print >> H, '} grpc_metadata_batch_callouts_index;'
@ -559,7 +621,7 @@ print >> H
print >> H, 'typedef union {'
print >> H, ' struct grpc_linked_mdelem *array[GRPC_BATCH_CALLOUTS_COUNT];'
print >> H, ' struct {'
for elem, _ in METADATA_BATCH_CALLOUTS:
for elem in METADATA_BATCH_CALLOUTS:
print >> H, ' struct grpc_linked_mdelem *%s;' % mangle(elem, '').lower()
print >> H, ' } named;'
print >> H, '} grpc_metadata_batch_callouts;'
@ -567,14 +629,6 @@ print >> H
print >> H, '#define GRPC_BATCH_INDEX_OF(slice) \\'
print >> H, ' (GRPC_IS_STATIC_METADATA_STRING((slice)) ? (grpc_metadata_batch_callouts_index)GPR_CLAMP(GRPC_STATIC_METADATA_INDEX((slice)), 0, GRPC_BATCH_CALLOUTS_COUNT) : GRPC_BATCH_CALLOUTS_COUNT)'
print >> H
print >> H, ('extern bool grpc_static_callout_is_default['
'GRPC_BATCH_CALLOUTS_COUNT];')
print >> H
print >> C, 'bool grpc_static_callout_is_default[GRPC_BATCH_CALLOUTS_COUNT] = {'
for elem, is_default in METADATA_BATCH_CALLOUTS:
print >> C, ' %s, // %s' % (str(is_default).lower(), elem)
print >> C, '};'
print >> C
print >> H, 'extern const uint8_t grpc_static_accept_encoding_metadata[%d];' % (
1 << len(COMPRESSION_ALGORITHMS))
@ -599,5 +653,8 @@ print >> H, '#define GRPC_MDELEM_ACCEPT_STREAM_ENCODING_FOR_ALGORITHMS(algs) (GR
print >> H, '#endif /* GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H */'
print >> HPACK_H, ('#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_'
'MAPPING_H */')
H.close()
C.close()

@ -1190,7 +1190,6 @@ src/cpp/client/secure_credentials.h \
src/cpp/codegen/codegen_init.cc \
src/cpp/common/alarm.cc \
src/cpp/common/auth_property_iterator.cc \
src/cpp/common/callback_common.cc \
src/cpp/common/channel_arguments.cc \
src/cpp/common/channel_filter.cc \
src/cpp/common/channel_filter.h \

@ -1013,6 +1013,8 @@ src/core/ext/transport/chttp2/transport/frame_window_update.cc \
src/core/ext/transport/chttp2/transport/frame_window_update.h \
src/core/ext/transport/chttp2/transport/hpack_encoder.cc \
src/core/ext/transport/chttp2/transport/hpack_encoder.h \
src/core/ext/transport/chttp2/transport/hpack_mapping.cc \
src/core/ext/transport/chttp2/transport/hpack_mapping.h \
src/core/ext/transport/chttp2/transport/hpack_parser.cc \
src/core/ext/transport/chttp2/transport/hpack_parser.h \
src/core/ext/transport/chttp2/transport/hpack_table.cc \

@ -10697,6 +10697,7 @@
"src/core/ext/transport/chttp2/transport/frame_settings.h",
"src/core/ext/transport/chttp2/transport/frame_window_update.h",
"src/core/ext/transport/chttp2/transport/hpack_encoder.h",
"src/core/ext/transport/chttp2/transport/hpack_mapping.h",
"src/core/ext/transport/chttp2/transport/hpack_parser.h",
"src/core/ext/transport/chttp2/transport/hpack_table.h",
"src/core/ext/transport/chttp2/transport/http2_settings.h",
@ -10734,6 +10735,8 @@
"src/core/ext/transport/chttp2/transport/frame_window_update.h",
"src/core/ext/transport/chttp2/transport/hpack_encoder.cc",
"src/core/ext/transport/chttp2/transport/hpack_encoder.h",
"src/core/ext/transport/chttp2/transport/hpack_mapping.cc",
"src/core/ext/transport/chttp2/transport/hpack_mapping.h",
"src/core/ext/transport/chttp2/transport/hpack_parser.cc",
"src/core/ext/transport/chttp2/transport/hpack_parser.h",
"src/core/ext/transport/chttp2/transport/hpack_table.cc",
@ -11470,7 +11473,6 @@
"src/cpp/client/credentials_cc.cc",
"src/cpp/client/generic_stub.cc",
"src/cpp/common/alarm.cc",
"src/cpp/common/callback_common.cc",
"src/cpp/common/channel_arguments.cc",
"src/cpp/common/channel_filter.cc",
"src/cpp/common/channel_filter.h",

Loading…
Cancel
Save