Merge branch 'master' into java-1.21.0

pull/19116/head
Eric Anderson 6 years ago
commit e592228f0b
  1. 4
      BUILD
  2. 4
      BUILD.gn
  3. 14
      CMakeLists.txt
  4. 14
      Makefile
  5. 8
      bazel/grpc_deps.bzl
  6. 4
      build.yaml
  7. 4
      gRPC-C++.podspec
  8. 2
      grpc.gyp
  9. 85
      include/grpcpp/channel.h
  10. 125
      include/grpcpp/channel_impl.h
  11. 1
      include/grpcpp/create_channel_impl.h
  12. 2
      include/grpcpp/generic/generic_stub_impl.h
  13. 2
      include/grpcpp/impl/codegen/async_stream.h
  14. 1
      include/grpcpp/impl/codegen/async_unary_call.h
  15. 14
      include/grpcpp/impl/codegen/call.h
  16. 1
      include/grpcpp/impl/codegen/call_op_set.h
  17. 16
      include/grpcpp/impl/codegen/channel_interface.h
  18. 6
      include/grpcpp/impl/codegen/client_callback.h
  19. 11
      include/grpcpp/impl/codegen/client_context.h
  20. 6
      include/grpcpp/impl/codegen/client_interceptor.h
  21. 2
      include/grpcpp/impl/codegen/client_unary_call.h
  22. 392
      include/grpcpp/impl/codegen/completion_queue.h
  23. 422
      include/grpcpp/impl/codegen/completion_queue_impl.h
  24. 1
      include/grpcpp/impl/codegen/core_codegen_interface.h
  25. 13
      include/grpcpp/impl/codegen/intercepted_channel.h
  26. 5
      include/grpcpp/impl/codegen/server_context.h
  27. 73
      include/grpcpp/impl/codegen/server_interface.h
  28. 3
      include/grpcpp/impl/codegen/service_type.h
  29. 1
      include/grpcpp/security/credentials_impl.h
  30. 7
      include/grpcpp/server_builder.h
  31. 9
      include/grpcpp/server_builder_impl.h
  32. 5
      include/grpcpp/server_impl.h
  33. 4
      include/grpcpp/support/channel_arguments_impl.h
  34. 36
      include/grpcpp/support/validate_service_config.h
  35. 6
      src/compiler/cpp_generator.cc
  36. 164
      src/core/ext/filters/client_channel/client_channel.cc
  37. 18
      src/core/ext/filters/client_channel/lb_policy.cc
  38. 154
      src/core/ext/filters/client_channel/lb_policy.h
  39. 43
      src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
  40. 14
      src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
  41. 17
      src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
  42. 56
      src/core/ext/filters/client_channel/lb_policy/xds/xds.cc
  43. 2
      src/core/ext/filters/client_channel/lb_policy_factory.h
  44. 2
      src/core/ext/filters/client_channel/lb_policy_registry.cc
  45. 2
      src/core/ext/filters/client_channel/lb_policy_registry.h
  46. 2
      src/core/ext/filters/client_channel/resolver_result_parsing.cc
  47. 6
      src/core/ext/filters/client_channel/resolver_result_parsing.h
  48. 6
      src/core/ext/filters/client_channel/resolving_lb_policy.cc
  49. 8
      src/core/ext/filters/client_channel/resolving_lb_policy.h
  50. 123
      src/core/ext/transport/chttp2/transport/hpack_encoder.cc
  51. 21
      src/core/ext/transport/chttp2/transport/hpack_parser.cc
  52. 17
      src/core/ext/transport/chttp2/transport/hpack_table.cc
  53. 11
      src/core/ext/transport/chttp2/transport/hpack_table.h
  54. 5
      src/core/ext/transport/cronet/transport/cronet_transport.cc
  55. 6
      src/core/lib/iomgr/error.cc
  56. 12
      src/core/lib/iomgr/error.h
  57. 2
      src/core/lib/iomgr/iomgr.cc
  58. 3
      src/core/lib/iomgr/timer.h
  59. 2
      src/core/lib/security/credentials/plugin/plugin_credentials.cc
  60. 3
      src/core/lib/slice/slice.cc
  61. 4
      src/core/lib/slice/slice_hash_table.h
  62. 21
      src/core/lib/slice/slice_intern.cc
  63. 31
      src/core/lib/slice/slice_internal.h
  64. 2
      src/core/lib/slice/slice_string_helpers.cc
  65. 2
      src/core/lib/slice/slice_string_helpers.h
  66. 4
      src/core/lib/slice/slice_weak_hash_table.h
  67. 2
      src/core/lib/surface/call.cc
  68. 57
      src/core/lib/surface/channel.cc
  69. 66
      src/core/lib/surface/channel.h
  70. 85
      src/core/lib/surface/completion_queue.cc
  71. 3
      src/core/lib/surface/completion_queue.h
  72. 12
      src/core/lib/surface/server.cc
  73. 16
      src/core/lib/surface/validate_metadata.cc
  74. 15
      src/core/lib/surface/validate_metadata.h
  75. 82
      src/core/lib/transport/metadata.cc
  76. 163
      src/core/lib/transport/metadata.h
  77. 434
      src/core/lib/transport/static_metadata.cc
  78. 435
      src/core/lib/transport/static_metadata.h
  79. 61
      src/cpp/client/channel_cc.cc
  80. 9
      src/cpp/client/client_context.cc
  81. 2
      src/cpp/client/create_channel.cc
  82. 4
      src/cpp/client/create_channel_internal.cc
  83. 4
      src/cpp/client/create_channel_internal.h
  84. 6
      src/cpp/client/create_channel_posix.cc
  85. 2
      src/cpp/client/secure_credentials.h
  86. 12
      src/cpp/common/completion_queue_cc.cc
  87. 40
      src/cpp/common/validate_service_config.cc
  88. 22
      src/objective-c/tests/APIv2Tests/Info.plist
  89. 22
      src/objective-c/tests/ChannelTests/Info.plist
  90. 21
      src/objective-c/tests/ConfigureCronet.h
  91. 39
      src/objective-c/tests/ConfigureCronet.m
  92. 24
      src/objective-c/tests/CoreCronetEnd2EndTests/Info.plist
  93. 10
      src/objective-c/tests/CronetTests/CoreCronetEnd2EndTests.mm
  94. 14
      src/objective-c/tests/CronetTests/CronetUnitTests.mm
  95. 4
      src/objective-c/tests/CronetTests/InteropTestsRemoteWithCronet.m
  96. 24
      src/objective-c/tests/CronetUnitTests/Info.plist
  97. 5
      src/objective-c/tests/InteropTests/InteropTests.h
  98. 90
      src/objective-c/tests/InteropTests/InteropTests.m
  99. 33
      src/objective-c/tests/InteropTests/InteropTestsBlockCallbacks.h
  100. 80
      src/objective-c/tests/InteropTests/InteropTestsBlockCallbacks.m
  101. Some files were not shown because too many files have changed in this diff Show More

@ -137,6 +137,7 @@ GRPCXX_SRCS = [
"src/cpp/common/resource_quota_cc.cc",
"src/cpp/common/rpc_method.cc",
"src/cpp/common/version_cc.cc",
"src/cpp/common/validate_service_config.cc",
"src/cpp/server/async_generic_service.cc",
"src/cpp/server/channel_argument_option.cc",
"src/cpp/server/create_default_thread_pool.cc",
@ -218,6 +219,7 @@ GRPCXX_PUBLIC_HDRS = [
"include/grpcpp/alarm.h",
"include/grpcpp/alarm_impl.h",
"include/grpcpp/channel.h",
"include/grpcpp/channel_impl.h",
"include/grpcpp/client_context.h",
"include/grpcpp/completion_queue.h",
"include/grpcpp/create_channel.h",
@ -285,6 +287,7 @@ GRPCXX_PUBLIC_HDRS = [
"include/grpcpp/support/stub_options.h",
"include/grpcpp/support/sync_stream.h",
"include/grpcpp/support/time.h",
"include/grpcpp/support/validate_service_config.h",
]
grpc_cc_library(
@ -2163,6 +2166,7 @@ grpc_cc_library(
"include/grpcpp/impl/codegen/client_interceptor.h",
"include/grpcpp/impl/codegen/client_unary_call.h",
"include/grpcpp/impl/codegen/completion_queue.h",
"include/grpcpp/impl/codegen/completion_queue_impl.h",
"include/grpcpp/impl/codegen/completion_queue_tag.h",
"include/grpcpp/impl/codegen/config.h",
"include/grpcpp/impl/codegen/core_codegen_interface.h",

@ -1024,6 +1024,7 @@ config("grpc_config") {
"include/grpcpp/alarm.h",
"include/grpcpp/alarm_impl.h",
"include/grpcpp/channel.h",
"include/grpcpp/channel_impl.h",
"include/grpcpp/client_context.h",
"include/grpcpp/completion_queue.h",
"include/grpcpp/create_channel.h",
@ -1055,6 +1056,7 @@ config("grpc_config") {
"include/grpcpp/impl/codegen/client_interceptor.h",
"include/grpcpp/impl/codegen/client_unary_call.h",
"include/grpcpp/impl/codegen/completion_queue.h",
"include/grpcpp/impl/codegen/completion_queue_impl.h",
"include/grpcpp/impl/codegen/completion_queue_tag.h",
"include/grpcpp/impl/codegen/config.h",
"include/grpcpp/impl/codegen/config_protobuf.h",
@ -1137,6 +1139,7 @@ config("grpc_config") {
"include/grpcpp/support/stub_options.h",
"include/grpcpp/support/sync_stream.h",
"include/grpcpp/support/time.h",
"include/grpcpp/support/validate_service_config.h",
"src/core/ext/transport/inproc/inproc_transport.h",
"src/core/lib/avl/avl.h",
"src/core/lib/backoff/backoff.h",
@ -1336,6 +1339,7 @@ config("grpc_config") {
"src/cpp/common/secure_auth_context.h",
"src/cpp/common/secure_channel_arguments.cc",
"src/cpp/common/secure_create_auth_context.cc",
"src/cpp/common/validate_service_config.cc",
"src/cpp/common/version_cc.cc",
"src/cpp/server/async_generic_service.cc",
"src/cpp/server/channel_argument_option.cc",

@ -3043,6 +3043,7 @@ add_library(grpc++
src/cpp/common/core_codegen.cc
src/cpp/common/resource_quota_cc.cc
src/cpp/common/rpc_method.cc
src/cpp/common/validate_service_config.cc
src/cpp/common/version_cc.cc
src/cpp/server/async_generic_service.cc
src/cpp/server/channel_argument_option.cc
@ -3152,6 +3153,7 @@ foreach(_hdr
include/grpcpp/alarm.h
include/grpcpp/alarm_impl.h
include/grpcpp/channel.h
include/grpcpp/channel_impl.h
include/grpcpp/client_context.h
include/grpcpp/completion_queue.h
include/grpcpp/create_channel.h
@ -3217,6 +3219,7 @@ foreach(_hdr
include/grpcpp/support/stub_options.h
include/grpcpp/support/sync_stream.h
include/grpcpp/support/time.h
include/grpcpp/support/validate_service_config.h
include/grpc/support/alloc.h
include/grpc/support/atm.h
include/grpc/support/atm_gcc_atomic.h
@ -3313,6 +3316,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/client_interceptor.h
include/grpcpp/impl/codegen/client_unary_call.h
include/grpcpp/impl/codegen/completion_queue.h
include/grpcpp/impl/codegen/completion_queue_impl.h
include/grpcpp/impl/codegen/completion_queue_tag.h
include/grpcpp/impl/codegen/config.h
include/grpcpp/impl/codegen/core_codegen_interface.h
@ -3438,6 +3442,7 @@ add_library(grpc++_cronet
src/cpp/common/core_codegen.cc
src/cpp/common/resource_quota_cc.cc
src/cpp/common/rpc_method.cc
src/cpp/common/validate_service_config.cc
src/cpp/common/version_cc.cc
src/cpp/server/async_generic_service.cc
src/cpp/server/channel_argument_option.cc
@ -3767,6 +3772,7 @@ foreach(_hdr
include/grpcpp/alarm.h
include/grpcpp/alarm_impl.h
include/grpcpp/channel.h
include/grpcpp/channel_impl.h
include/grpcpp/client_context.h
include/grpcpp/completion_queue.h
include/grpcpp/create_channel.h
@ -3832,6 +3838,7 @@ foreach(_hdr
include/grpcpp/support/stub_options.h
include/grpcpp/support/sync_stream.h
include/grpcpp/support/time.h
include/grpcpp/support/validate_service_config.h
include/grpc/support/alloc.h
include/grpc/support/atm.h
include/grpc/support/atm_gcc_atomic.h
@ -3928,6 +3935,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/client_interceptor.h
include/grpcpp/impl/codegen/client_unary_call.h
include/grpcpp/impl/codegen/completion_queue.h
include/grpcpp/impl/codegen/completion_queue_impl.h
include/grpcpp/impl/codegen/completion_queue_tag.h
include/grpcpp/impl/codegen/config.h
include/grpcpp/impl/codegen/core_codegen_interface.h
@ -4362,6 +4370,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/client_interceptor.h
include/grpcpp/impl/codegen/client_unary_call.h
include/grpcpp/impl/codegen/completion_queue.h
include/grpcpp/impl/codegen/completion_queue_impl.h
include/grpcpp/impl/codegen/completion_queue_tag.h
include/grpcpp/impl/codegen/config.h
include/grpcpp/impl/codegen/core_codegen_interface.h
@ -4560,6 +4569,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/client_interceptor.h
include/grpcpp/impl/codegen/client_unary_call.h
include/grpcpp/impl/codegen/completion_queue.h
include/grpcpp/impl/codegen/completion_queue_impl.h
include/grpcpp/impl/codegen/completion_queue_tag.h
include/grpcpp/impl/codegen/config.h
include/grpcpp/impl/codegen/core_codegen_interface.h
@ -4646,6 +4656,7 @@ add_library(grpc++_unsecure
src/cpp/common/core_codegen.cc
src/cpp/common/resource_quota_cc.cc
src/cpp/common/rpc_method.cc
src/cpp/common/validate_service_config.cc
src/cpp/common/version_cc.cc
src/cpp/server/async_generic_service.cc
src/cpp/server/channel_argument_option.cc
@ -4754,6 +4765,7 @@ foreach(_hdr
include/grpcpp/alarm.h
include/grpcpp/alarm_impl.h
include/grpcpp/channel.h
include/grpcpp/channel_impl.h
include/grpcpp/client_context.h
include/grpcpp/completion_queue.h
include/grpcpp/create_channel.h
@ -4819,6 +4831,7 @@ foreach(_hdr
include/grpcpp/support/stub_options.h
include/grpcpp/support/sync_stream.h
include/grpcpp/support/time.h
include/grpcpp/support/validate_service_config.h
include/grpc/support/alloc.h
include/grpc/support/atm.h
include/grpc/support/atm_gcc_atomic.h
@ -4915,6 +4928,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/client_interceptor.h
include/grpcpp/impl/codegen/client_unary_call.h
include/grpcpp/impl/codegen/completion_queue.h
include/grpcpp/impl/codegen/completion_queue_impl.h
include/grpcpp/impl/codegen/completion_queue_tag.h
include/grpcpp/impl/codegen/config.h
include/grpcpp/impl/codegen/core_codegen_interface.h

@ -5435,6 +5435,7 @@ LIBGRPC++_SRC = \
src/cpp/common/core_codegen.cc \
src/cpp/common/resource_quota_cc.cc \
src/cpp/common/rpc_method.cc \
src/cpp/common/validate_service_config.cc \
src/cpp/common/version_cc.cc \
src/cpp/server/async_generic_service.cc \
src/cpp/server/channel_argument_option.cc \
@ -5509,6 +5510,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/alarm.h \
include/grpcpp/alarm_impl.h \
include/grpcpp/channel.h \
include/grpcpp/channel_impl.h \
include/grpcpp/client_context.h \
include/grpcpp/completion_queue.h \
include/grpcpp/create_channel.h \
@ -5574,6 +5576,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/support/stub_options.h \
include/grpcpp/support/sync_stream.h \
include/grpcpp/support/time.h \
include/grpcpp/support/validate_service_config.h \
include/grpc/support/alloc.h \
include/grpc/support/atm.h \
include/grpc/support/atm_gcc_atomic.h \
@ -5670,6 +5673,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/client_interceptor.h \
include/grpcpp/impl/codegen/client_unary_call.h \
include/grpcpp/impl/codegen/completion_queue.h \
include/grpcpp/impl/codegen/completion_queue_impl.h \
include/grpcpp/impl/codegen/completion_queue_tag.h \
include/grpcpp/impl/codegen/config.h \
include/grpcpp/impl/codegen/core_codegen_interface.h \
@ -5839,6 +5843,7 @@ LIBGRPC++_CRONET_SRC = \
src/cpp/common/core_codegen.cc \
src/cpp/common/resource_quota_cc.cc \
src/cpp/common/rpc_method.cc \
src/cpp/common/validate_service_config.cc \
src/cpp/common/version_cc.cc \
src/cpp/server/async_generic_service.cc \
src/cpp/server/channel_argument_option.cc \
@ -6132,6 +6137,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/alarm.h \
include/grpcpp/alarm_impl.h \
include/grpcpp/channel.h \
include/grpcpp/channel_impl.h \
include/grpcpp/client_context.h \
include/grpcpp/completion_queue.h \
include/grpcpp/create_channel.h \
@ -6197,6 +6203,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/support/stub_options.h \
include/grpcpp/support/sync_stream.h \
include/grpcpp/support/time.h \
include/grpcpp/support/validate_service_config.h \
include/grpc/support/alloc.h \
include/grpc/support/atm.h \
include/grpc/support/atm_gcc_atomic.h \
@ -6293,6 +6300,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/client_interceptor.h \
include/grpcpp/impl/codegen/client_unary_call.h \
include/grpcpp/impl/codegen/completion_queue.h \
include/grpcpp/impl/codegen/completion_queue_impl.h \
include/grpcpp/impl/codegen/completion_queue_tag.h \
include/grpcpp/impl/codegen/config.h \
include/grpcpp/impl/codegen/core_codegen_interface.h \
@ -6699,6 +6707,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/client_interceptor.h \
include/grpcpp/impl/codegen/client_unary_call.h \
include/grpcpp/impl/codegen/completion_queue.h \
include/grpcpp/impl/codegen/completion_queue_impl.h \
include/grpcpp/impl/codegen/completion_queue_tag.h \
include/grpcpp/impl/codegen/config.h \
include/grpcpp/impl/codegen/core_codegen_interface.h \
@ -6868,6 +6877,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/client_interceptor.h \
include/grpcpp/impl/codegen/client_unary_call.h \
include/grpcpp/impl/codegen/completion_queue.h \
include/grpcpp/impl/codegen/completion_queue_impl.h \
include/grpcpp/impl/codegen/completion_queue_tag.h \
include/grpcpp/impl/codegen/config.h \
include/grpcpp/impl/codegen/core_codegen_interface.h \
@ -6994,6 +7004,7 @@ LIBGRPC++_UNSECURE_SRC = \
src/cpp/common/core_codegen.cc \
src/cpp/common/resource_quota_cc.cc \
src/cpp/common/rpc_method.cc \
src/cpp/common/validate_service_config.cc \
src/cpp/common/version_cc.cc \
src/cpp/server/async_generic_service.cc \
src/cpp/server/channel_argument_option.cc \
@ -7068,6 +7079,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/alarm.h \
include/grpcpp/alarm_impl.h \
include/grpcpp/channel.h \
include/grpcpp/channel_impl.h \
include/grpcpp/client_context.h \
include/grpcpp/completion_queue.h \
include/grpcpp/create_channel.h \
@ -7133,6 +7145,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/support/stub_options.h \
include/grpcpp/support/sync_stream.h \
include/grpcpp/support/time.h \
include/grpcpp/support/validate_service_config.h \
include/grpc/support/alloc.h \
include/grpc/support/atm.h \
include/grpc/support/atm_gcc_atomic.h \
@ -7229,6 +7242,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/client_interceptor.h \
include/grpcpp/impl/codegen/client_unary_call.h \
include/grpcpp/impl/codegen/completion_queue.h \
include/grpcpp/impl/codegen/completion_queue_impl.h \
include/grpcpp/impl/codegen/completion_queue_tag.h \
include/grpcpp/impl/codegen/config.h \
include/grpcpp/impl/codegen/core_codegen_interface.h \

@ -186,11 +186,11 @@ def grpc_deps():
if "bazel_toolchains" not in native.existing_rules():
http_archive(
name = "bazel_toolchains",
sha256 = "67335b3563d9b67dc2550b8f27cc689b64fadac491e69ce78763d9ba894cc5cc",
strip_prefix = "bazel-toolchains-cddc376d428ada2927ad359211c3e356bd9c9fbb",
sha256 = "88e818f9f03628eef609c8429c210ecf265ffe46c2af095f36c7ef8b1855fef5",
strip_prefix = "bazel-toolchains-92dd8a7a518a2fb7ba992d47c8b38299fe0be825",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/cddc376d428ada2927ad359211c3e356bd9c9fbb.tar.gz",
"https://github.com/bazelbuild/bazel-toolchains/archive/cddc376d428ada2927ad359211c3e356bd9c9fbb.tar.gz",
"https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/92dd8a7a518a2fb7ba992d47c8b38299fe0be825.tar.gz",
"https://github.com/bazelbuild/bazel-toolchains/archive/92dd8a7a518a2fb7ba992d47c8b38299fe0be825.tar.gz",
],
)

@ -1262,6 +1262,7 @@ filegroups:
- include/grpcpp/impl/codegen/client_interceptor.h
- include/grpcpp/impl/codegen/client_unary_call.h
- include/grpcpp/impl/codegen/completion_queue.h
- include/grpcpp/impl/codegen/completion_queue_impl.h
- include/grpcpp/impl/codegen/completion_queue_tag.h
- include/grpcpp/impl/codegen/config.h
- include/grpcpp/impl/codegen/core_codegen_interface.h
@ -1359,6 +1360,7 @@ filegroups:
- include/grpcpp/alarm.h
- include/grpcpp/alarm_impl.h
- include/grpcpp/channel.h
- include/grpcpp/channel_impl.h
- include/grpcpp/client_context.h
- include/grpcpp/completion_queue.h
- include/grpcpp/create_channel.h
@ -1424,6 +1426,7 @@ filegroups:
- include/grpcpp/support/stub_options.h
- include/grpcpp/support/sync_stream.h
- include/grpcpp/support/time.h
- include/grpcpp/support/validate_service_config.h
headers:
- src/cpp/client/create_channel_internal.h
- src/cpp/common/channel_filter.h
@ -1448,6 +1451,7 @@ filegroups:
- src/cpp/common/core_codegen.cc
- src/cpp/common/resource_quota_cc.cc
- src/cpp/common/rpc_method.cc
- src/cpp/common/validate_service_config.cc
- src/cpp/common/version_cc.cc
- src/cpp/server/async_generic_service.cc
- src/cpp/server/channel_argument_option.cc

@ -82,6 +82,7 @@ Pod::Spec.new do |s|
ss.source_files = 'include/grpcpp/alarm.h',
'include/grpcpp/alarm_impl.h',
'include/grpcpp/channel.h',
'include/grpcpp/channel_impl.h',
'include/grpcpp/client_context.h',
'include/grpcpp/completion_queue.h',
'include/grpcpp/create_channel.h',
@ -147,6 +148,7 @@ Pod::Spec.new do |s|
'include/grpcpp/support/stub_options.h',
'include/grpcpp/support/sync_stream.h',
'include/grpcpp/support/time.h',
'include/grpcpp/support/validate_service_config.h',
'include/grpcpp/impl/codegen/async_generic_service.h',
'include/grpcpp/impl/codegen/async_stream.h',
'include/grpcpp/impl/codegen/async_unary_call.h',
@ -162,6 +164,7 @@ Pod::Spec.new do |s|
'include/grpcpp/impl/codegen/client_interceptor.h',
'include/grpcpp/impl/codegen/client_unary_call.h',
'include/grpcpp/impl/codegen/completion_queue.h',
'include/grpcpp/impl/codegen/completion_queue_impl.h',
'include/grpcpp/impl/codegen/completion_queue_tag.h',
'include/grpcpp/impl/codegen/config.h',
'include/grpcpp/impl/codegen/core_codegen_interface.h',
@ -232,6 +235,7 @@ Pod::Spec.new do |s|
'src/cpp/common/core_codegen.cc',
'src/cpp/common/resource_quota_cc.cc',
'src/cpp/common/rpc_method.cc',
'src/cpp/common/validate_service_config.cc',
'src/cpp/common/version_cc.cc',
'src/cpp/server/async_generic_service.cc',
'src/cpp/server/channel_argument_option.cc',

@ -1463,6 +1463,7 @@
'src/cpp/common/core_codegen.cc',
'src/cpp/common/resource_quota_cc.cc',
'src/cpp/common/rpc_method.cc',
'src/cpp/common/validate_service_config.cc',
'src/cpp/common/version_cc.cc',
'src/cpp/server/async_generic_service.cc',
'src/cpp/server/channel_argument_option.cc',
@ -1619,6 +1620,7 @@
'src/cpp/common/core_codegen.cc',
'src/cpp/common/resource_quota_cc.cc',
'src/cpp/common/rpc_method.cc',
'src/cpp/common/validate_service_config.cc',
'src/cpp/common/version_cc.cc',
'src/cpp/server/async_generic_service.cc',
'src/cpp/server/channel_argument_option.cc',

@ -19,22 +19,12 @@
#ifndef GRPCPP_CHANNEL_H
#define GRPCPP_CHANNEL_H
#include <memory>
#include <mutex>
#include <grpc/grpc.h>
#include <grpcpp/impl/call.h>
#include <grpcpp/impl/codegen/channel_interface.h>
#include <grpcpp/impl/codegen/client_interceptor.h>
#include <grpcpp/impl/codegen/completion_queue.h>
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/grpc_library.h>
#include <grpcpp/impl/codegen/sync.h>
struct grpc_channel;
#include <grpcpp/channel_impl.h>
namespace grpc {
typedef ::grpc_impl::Channel Channel;
namespace experimental {
/// Resets the channel's connection backoff.
/// TODO(roth): Once we see whether this proves useful, either create a gRFC
@ -42,75 +32,6 @@ namespace experimental {
void ChannelResetConnectionBackoff(Channel* channel);
} // namespace experimental
/// Channels represent a connection to an endpoint. Created by \a CreateChannel.
class Channel final : public ChannelInterface,
public internal::CallHook,
public std::enable_shared_from_this<Channel>,
private GrpcLibraryCodegen {
public:
~Channel();
/// Get the current channel state. If the channel is in IDLE and
/// \a try_to_connect is set to true, try to connect.
grpc_connectivity_state GetState(bool try_to_connect) override;
/// Returns the LB policy name, or the empty string if not yet available.
grpc::string GetLoadBalancingPolicyName() const;
/// Returns the service config in JSON form, or the empty string if
/// not available.
grpc::string GetServiceConfigJSON() const;
private:
template <class InputMessage, class OutputMessage>
friend class internal::BlockingUnaryCallImpl;
friend void experimental::ChannelResetConnectionBackoff(Channel* channel);
friend std::shared_ptr<Channel> CreateChannelInternal(
const grpc::string& host, grpc_channel* c_channel,
std::vector<std::unique_ptr<
::grpc::experimental::ClientInterceptorFactoryInterface>>
interceptor_creators);
friend class internal::InterceptedChannel;
Channel(const grpc::string& host, grpc_channel* c_channel,
std::vector<
std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators);
internal::Call CreateCall(const internal::RpcMethod& method,
ClientContext* context,
CompletionQueue* cq) override;
void PerformOpsOnCall(internal::CallOpSetInterface* ops,
internal::Call* call) override;
void* RegisterMethod(const char* method) override;
void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed,
gpr_timespec deadline, CompletionQueue* cq,
void* tag) override;
bool WaitForStateChangeImpl(grpc_connectivity_state last_observed,
gpr_timespec deadline) override;
CompletionQueue* CallbackCQ() override;
internal::Call CreateCallInternal(const internal::RpcMethod& method,
ClientContext* context, CompletionQueue* cq,
size_t interceptor_pos) override;
const grpc::string host_;
grpc_channel* const c_channel_; // owned
// mu_ protects callback_cq_ (the per-channel callbackable completion queue)
grpc::internal::Mutex mu_;
// callback_cq_ references the callbackable completion queue associated
// with this channel (if any). It is set on the first call to CallbackCQ().
// It is _not owned_ by the channel; ownership belongs with its internal
// shutdown callback tag (invoked when the CQ is fully shutdown).
CompletionQueue* callback_cq_ = nullptr;
std::vector<std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators_;
};
} // namespace grpc
#endif // GRPCPP_CHANNEL_H

@ -0,0 +1,125 @@
/*
*
* Copyright 2015 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPCPP_CHANNEL_IMPL_H
#define GRPCPP_CHANNEL_IMPL_H
#include <memory>
#include <mutex>
#include <grpc/grpc.h>
#include <grpcpp/impl/call.h>
#include <grpcpp/impl/codegen/channel_interface.h>
#include <grpcpp/impl/codegen/client_interceptor.h>
#include <grpcpp/impl/codegen/completion_queue.h>
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/grpc_library.h>
#include <grpcpp/impl/codegen/sync.h>
struct grpc_channel;
namespace grpc {
std::shared_ptr<::grpc_impl::Channel> CreateChannelInternal(
const grpc::string& host, grpc_channel* c_channel,
std::vector<
std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators);
} // namespace grpc
namespace grpc_impl {
namespace experimental {
/// Resets the channel's connection backoff.
/// TODO(roth): Once we see whether this proves useful, either create a gRFC
/// and change this to be a method of the Channel class, or remove it.
void ChannelResetConnectionBackoff(Channel* channel);
} // namespace experimental
/// Channels represent a connection to an endpoint. Created by \a CreateChannel.
class Channel final : public ::grpc::ChannelInterface,
public ::grpc::internal::CallHook,
public std::enable_shared_from_this<Channel>,
private ::grpc::GrpcLibraryCodegen {
public:
~Channel();
/// Get the current channel state. If the channel is in IDLE and
/// \a try_to_connect is set to true, try to connect.
grpc_connectivity_state GetState(bool try_to_connect) override;
/// Returns the LB policy name, or the empty string if not yet available.
grpc::string GetLoadBalancingPolicyName() const;
/// Returns the service config in JSON form, or the empty string if
/// not available.
grpc::string GetServiceConfigJSON() const;
private:
template <class InputMessage, class OutputMessage>
friend class ::grpc::internal::BlockingUnaryCallImpl;
friend void experimental::ChannelResetConnectionBackoff(Channel* channel);
friend std::shared_ptr<Channel> grpc::CreateChannelInternal(
const grpc::string& host, grpc_channel* c_channel,
std::vector<std::unique_ptr<
::grpc::experimental::ClientInterceptorFactoryInterface>>
interceptor_creators);
friend class ::grpc::internal::InterceptedChannel;
Channel(const grpc::string& host, grpc_channel* c_channel,
std::vector<std::unique_ptr<
::grpc::experimental::ClientInterceptorFactoryInterface>>
interceptor_creators);
::grpc::internal::Call CreateCall(const ::grpc::internal::RpcMethod& method,
::grpc::ClientContext* context,
::grpc::CompletionQueue* cq) override;
void PerformOpsOnCall(::grpc::internal::CallOpSetInterface* ops,
::grpc::internal::Call* call) override;
void* RegisterMethod(const char* method) override;
void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed,
gpr_timespec deadline,
::grpc::CompletionQueue* cq, void* tag) override;
bool WaitForStateChangeImpl(grpc_connectivity_state last_observed,
gpr_timespec deadline) override;
::grpc::CompletionQueue* CallbackCQ() override;
::grpc::internal::Call CreateCallInternal(
const ::grpc::internal::RpcMethod& method, ::grpc::ClientContext* context,
::grpc::CompletionQueue* cq, size_t interceptor_pos) override;
const grpc::string host_;
grpc_channel* const c_channel_; // owned
// mu_ protects callback_cq_ (the per-channel callbackable completion queue)
grpc::internal::Mutex mu_;
// callback_cq_ references the callbackable completion queue associated
// with this channel (if any). It is set on the first call to CallbackCQ().
// It is _not owned_ by the channel; ownership belongs with its internal
// shutdown callback tag (invoked when the CQ is fully shutdown).
::grpc::CompletionQueue* callback_cq_ = nullptr;
std::vector<
std::unique_ptr<::grpc::experimental::ClientInterceptorFactoryInterface>>
interceptor_creators_;
};
} // namespace grpc_impl
#endif // GRPCPP_CHANNEL_IMPL_H

@ -28,7 +28,6 @@
#include <grpcpp/support/config.h>
namespace grpc_impl {
/// Create a new \a Channel pointing to \a target.
///
/// \param target The URI of the endpoint to connect to.

@ -29,12 +29,12 @@
namespace grpc {
class CompletionQueue;
typedef ClientAsyncReaderWriter<ByteBuffer, ByteBuffer>
GenericClientAsyncReaderWriter;
typedef ClientAsyncResponseReader<ByteBuffer> GenericClientAsyncResponseReader;
} // namespace grpc
namespace grpc_impl {
class CompletionQueue;
/// Generic stubs provide a type-unsafe interface to call gRPC methods
/// by name.

@ -28,8 +28,6 @@
namespace grpc {
class CompletionQueue;
namespace internal {
/// Common interface for all client side asynchronous streaming.
class ClientAsyncStreamingInterface {

@ -29,7 +29,6 @@
namespace grpc {
class CompletionQueue;
extern CoreCodegenInterface* g_core_codegen_interface;
/// An interface relevant for async client side unary RPCs (which send

@ -21,9 +21,11 @@
#include <grpc/impl/codegen/grpc_types.h>
#include <grpcpp/impl/codegen/call_hook.h>
namespace grpc {
namespace grpc_impl {
class CompletionQueue;
}
namespace grpc {
namespace experimental {
class ClientRpcInfo;
class ServerRpcInfo;
@ -41,13 +43,13 @@ class Call final {
call_(nullptr),
max_receive_message_size_(-1) {}
/** call is owned by the caller */
Call(grpc_call* call, CallHook* call_hook, CompletionQueue* cq)
Call(grpc_call* call, CallHook* call_hook, ::grpc_impl::CompletionQueue* cq)
: call_hook_(call_hook),
cq_(cq),
call_(call),
max_receive_message_size_(-1) {}
Call(grpc_call* call, CallHook* call_hook, CompletionQueue* cq,
Call(grpc_call* call, CallHook* call_hook, ::grpc_impl::CompletionQueue* cq,
experimental::ClientRpcInfo* rpc_info)
: call_hook_(call_hook),
cq_(cq),
@ -55,7 +57,7 @@ class Call final {
max_receive_message_size_(-1),
client_rpc_info_(rpc_info) {}
Call(grpc_call* call, CallHook* call_hook, CompletionQueue* cq,
Call(grpc_call* call, CallHook* call_hook, ::grpc_impl::CompletionQueue* cq,
int max_receive_message_size, experimental::ServerRpcInfo* rpc_info)
: call_hook_(call_hook),
cq_(cq),
@ -68,7 +70,7 @@ class Call final {
}
grpc_call* call() const { return call_; }
CompletionQueue* cq() const { return cq_; }
::grpc_impl::CompletionQueue* cq() const { return cq_; }
int max_receive_message_size() const { return max_receive_message_size_; }
@ -82,7 +84,7 @@ class Call final {
private:
CallHook* call_hook_;
CompletionQueue* cq_;
::grpc_impl::CompletionQueue* cq_;
grpc_call* call_;
int max_receive_message_size_;
experimental::ClientRpcInfo* client_rpc_info_ = nullptr;

@ -48,7 +48,6 @@
namespace grpc {
class CompletionQueue;
extern CoreCodegenInterface* g_core_codegen_interface;
namespace internal {

@ -24,10 +24,13 @@
#include <grpcpp/impl/codegen/status.h>
#include <grpcpp/impl/codegen/time.h>
namespace grpc_impl {
class CompletionQueue;
}
namespace grpc {
class ChannelInterface;
class ClientContext;
class CompletionQueue;
template <class R>
class ClientReader;
@ -74,7 +77,7 @@ class ChannelInterface {
/// deadline expires. \a GetState needs to called to get the current state.
template <typename T>
void NotifyOnStateChange(grpc_connectivity_state last_observed, T deadline,
CompletionQueue* cq, void* tag) {
::grpc_impl::CompletionQueue* cq, void* tag) {
TimePoint<T> deadline_tp(deadline);
NotifyOnStateChangeImpl(last_observed, deadline_tp.raw_time(), cq, tag);
}
@ -127,13 +130,14 @@ class ChannelInterface {
friend class ::grpc::internal::InterceptedChannel;
virtual internal::Call CreateCall(const internal::RpcMethod& method,
ClientContext* context,
CompletionQueue* cq) = 0;
::grpc_impl::CompletionQueue* cq) = 0;
virtual void PerformOpsOnCall(internal::CallOpSetInterface* ops,
internal::Call* call) = 0;
virtual void* RegisterMethod(const char* method) = 0;
virtual void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed,
gpr_timespec deadline,
CompletionQueue* cq, void* tag) = 0;
::grpc_impl::CompletionQueue* cq,
void* tag) = 0;
virtual bool WaitForStateChangeImpl(grpc_connectivity_state last_observed,
gpr_timespec deadline) = 0;
@ -146,7 +150,7 @@ class ChannelInterface {
// change (even though this is private and non-API)
virtual internal::Call CreateCallInternal(const internal::RpcMethod& method,
ClientContext* context,
CompletionQueue* cq,
::grpc_impl::CompletionQueue* cq,
size_t interceptor_pos) {
return internal::Call();
}
@ -159,7 +163,7 @@ class ChannelInterface {
// Returns nullptr (rather than being pure) since this is a post-1.0 method
// and adding a new pure method to an interface would be a breaking change
// (even though this is private and non-API)
virtual CompletionQueue* CallbackCQ() { return nullptr; }
virtual ::grpc_impl::CompletionQueue* CallbackCQ() { return nullptr; }
};
} // namespace grpc

@ -29,11 +29,13 @@
#include <grpcpp/impl/codegen/core_codegen_interface.h>
#include <grpcpp/impl/codegen/status.h>
namespace grpc_impl {
class Channel;
}
namespace grpc {
class Channel;
class ClientContext;
class CompletionQueue;
namespace internal {
class RpcMethod;

@ -60,12 +60,12 @@ struct grpc_call;
namespace grpc_impl {
class CallCredentials;
class Channel;
class CompletionQueue;
} // namespace grpc_impl
namespace grpc {
class Channel;
class ChannelInterface;
class CompletionQueue;
class ClientContext;
namespace internal {
@ -397,7 +397,7 @@ class ClientContext {
friend class ::grpc::testing::InteropClientContextInspector;
friend class ::grpc::internal::CallOpClientRecvStatus;
friend class ::grpc::internal::CallOpRecvInitialMetadata;
friend class Channel;
friend class ::grpc_impl::Channel;
template <class R>
friend class ::grpc::ClientReader;
template <class W>
@ -430,7 +430,8 @@ class ClientContext {
}
grpc_call* call() const { return call_; }
void set_call(grpc_call* call, const std::shared_ptr<Channel>& channel);
void set_call(grpc_call* call,
const std::shared_ptr<::grpc_impl::Channel>& channel);
experimental::ClientRpcInfo* set_client_rpc_info(
const char* method, internal::RpcMethod::RpcType type,
@ -463,7 +464,7 @@ class ClientContext {
bool wait_for_ready_explicitly_set_;
bool idempotent_;
bool cacheable_;
std::shared_ptr<Channel> channel_;
std::shared_ptr<::grpc_impl::Channel> channel_;
grpc::internal::Mutex mu_;
grpc_call* call_;
bool call_canceled_;

@ -26,10 +26,14 @@
#include <grpcpp/impl/codegen/rpc_method.h>
#include <grpcpp/impl/codegen/string_ref.h>
namespace grpc_impl {
class Channel;
}
namespace grpc {
class ClientContext;
class Channel;
namespace internal {
class InterceptorBatchMethodsImpl;

@ -27,9 +27,7 @@
namespace grpc {
class Channel;
class ClientContext;
class CompletionQueue;
namespace internal {
class RpcMethod;

@ -16,401 +16,15 @@
*
*/
/// A completion queue implements a concurrent producer-consumer queue, with
/// two main API-exposed methods: \a Next and \a AsyncNext. These
/// methods are the essential component of the gRPC C++ asynchronous API.
/// There is also a \a Shutdown method to indicate that a given completion queue
/// will no longer have regular events. This must be called before the
/// completion queue is destroyed.
/// All completion queue APIs are thread-safe and may be used concurrently with
/// any other completion queue API invocation; it is acceptable to have
/// multiple threads calling \a Next or \a AsyncNext on the same or different
/// completion queues, or to call these methods concurrently with a \a Shutdown
/// elsewhere.
/// \remark{All other API calls on completion queue should be completed before
/// a completion queue destructor is called.}
#ifndef GRPCPP_IMPL_CODEGEN_COMPLETION_QUEUE_H
#define GRPCPP_IMPL_CODEGEN_COMPLETION_QUEUE_H
#include <grpc/impl/codegen/atm.h>
#include <grpcpp/impl/codegen/completion_queue_tag.h>
#include <grpcpp/impl/codegen/core_codegen_interface.h>
#include <grpcpp/impl/codegen/grpc_library.h>
#include <grpcpp/impl/codegen/status.h>
#include <grpcpp/impl/codegen/time.h>
#include <grpcpp/impl/codegen/completion_queue_impl.h>
struct grpc_completion_queue;
namespace grpc_impl {
class Server;
class ServerBuilder;
} // namespace grpc_impl
namespace grpc {
template <class R>
class ClientReader;
template <class W>
class ClientWriter;
template <class W, class R>
class ClientReaderWriter;
template <class R>
class ServerReader;
template <class W>
class ServerWriter;
namespace internal {
template <class W, class R>
class ServerReaderWriterBody;
} // namespace internal
class Channel;
class ChannelInterface;
class ClientContext;
class CompletionQueue;
class ServerContext;
class ServerInterface;
namespace internal {
class CompletionQueueTag;
class RpcMethod;
template <class ServiceType, class RequestType, class ResponseType>
class RpcMethodHandler;
template <class ServiceType, class RequestType, class ResponseType>
class ClientStreamingHandler;
template <class ServiceType, class RequestType, class ResponseType>
class ServerStreamingHandler;
template <class ServiceType, class RequestType, class ResponseType>
class BidiStreamingHandler;
template <class Streamer, bool WriteNeeded>
class TemplatedBidiStreamingHandler;
template <StatusCode code>
class ErrorMethodHandler;
template <class InputMessage, class OutputMessage>
class BlockingUnaryCallImpl;
template <class Op1, class Op2, class Op3, class Op4, class Op5, class Op6>
class CallOpSet;
} // namespace internal
extern CoreCodegenInterface* g_core_codegen_interface;
/// A thin wrapper around \ref grpc_completion_queue (see \ref
/// src/core/lib/surface/completion_queue.h).
/// See \ref doc/cpp/perf_notes.md for notes on best practices for high
/// performance servers.
class CompletionQueue : private GrpcLibraryCodegen {
public:
/// Default constructor. Implicitly creates a \a grpc_completion_queue
/// instance.
CompletionQueue()
: CompletionQueue(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_NEXT, GRPC_CQ_DEFAULT_POLLING,
nullptr}) {}
/// Wrap \a take, taking ownership of the instance.
///
/// \param take The completion queue instance to wrap. Ownership is taken.
explicit CompletionQueue(grpc_completion_queue* take);
/// Destructor. Destroys the owned wrapped completion queue / instance.
~CompletionQueue() {
g_core_codegen_interface->grpc_completion_queue_destroy(cq_);
}
/// Tri-state return for AsyncNext: SHUTDOWN, GOT_EVENT, TIMEOUT.
enum NextStatus {
SHUTDOWN, ///< The completion queue has been shutdown and fully-drained
GOT_EVENT, ///< Got a new event; \a tag will be filled in with its
///< associated value; \a ok indicating its success.
TIMEOUT ///< deadline was reached.
};
/// Read from the queue, blocking until an event is available or the queue is
/// shutting down.
///
/// \param tag [out] Updated to point to the read event's tag.
/// \param ok [out] true if read a successful event, false otherwise.
///
/// Note that each tag sent to the completion queue (through RPC operations
/// or alarms) will be delivered out of the completion queue by a call to
/// Next (or a related method), regardless of whether the operation succeeded
/// or not. Success here means that this operation completed in the normal
/// valid manner.
///
/// Server-side RPC request: \a ok indicates that the RPC has indeed
/// been started. If it is false, the server has been Shutdown
/// before this particular call got matched to an incoming RPC.
///
/// Client-side StartCall/RPC invocation: \a ok indicates that the RPC is
/// going to go to the wire. If it is false, it not going to the wire. This
/// would happen if the channel is either permanently broken or
/// transiently broken but with the fail-fast option. (Note that async unary
/// RPCs don't post a CQ tag at this point, nor do client-streaming
/// or bidi-streaming RPCs that have the initial metadata corked option set.)
///
/// Client-side Write, Client-side WritesDone, Server-side Write,
/// Server-side Finish, Server-side SendInitialMetadata (which is
/// typically included in Write or Finish when not done explicitly):
/// \a ok means that the data/metadata/status/etc is going to go to the
/// wire. If it is false, it not going to the wire because the call
/// is already dead (i.e., canceled, deadline expired, other side
/// dropped the channel, etc).
///
/// Client-side Read, Server-side Read, Client-side
/// RecvInitialMetadata (which is typically included in Read if not
/// done explicitly): \a ok indicates whether there is a valid message
/// that got read. If not, you know that there are certainly no more
/// messages that can ever be read from this stream. For the client-side
/// operations, this only happens because the call is dead. For the
/// server-sider operation, though, this could happen because the client
/// has done a WritesDone already.
///
/// Client-side Finish: \a ok should always be true
///
/// Server-side AsyncNotifyWhenDone: \a ok should always be true
///
/// Alarm: \a ok is true if it expired, false if it was canceled
///
/// \return true if got an event, false if the queue is fully drained and
/// shut down.
bool Next(void** tag, bool* ok) {
return (AsyncNextInternal(tag, ok,
g_core_codegen_interface->gpr_inf_future(
GPR_CLOCK_REALTIME)) != SHUTDOWN);
}
/// Read from the queue, blocking up to \a deadline (or the queue's shutdown).
/// Both \a tag and \a ok are updated upon success (if an event is available
/// within the \a deadline). A \a tag points to an arbitrary location usually
/// employed to uniquely identify an event.
///
/// \param tag [out] Upon success, updated to point to the event's tag.
/// \param ok [out] Upon success, true if a successful event, false otherwise
/// See documentation for CompletionQueue::Next for explanation of ok
/// \param deadline [in] How long to block in wait for an event.
///
/// \return The type of event read.
template <typename T>
NextStatus AsyncNext(void** tag, bool* ok, const T& deadline) {
TimePoint<T> deadline_tp(deadline);
return AsyncNextInternal(tag, ok, deadline_tp.raw_time());
}
/// EXPERIMENTAL
/// First executes \a F, then reads from the queue, blocking up to
/// \a deadline (or the queue's shutdown).
/// Both \a tag and \a ok are updated upon success (if an event is available
/// within the \a deadline). A \a tag points to an arbitrary location usually
/// employed to uniquely identify an event.
///
/// \param f [in] Function to execute before calling AsyncNext on this queue.
/// \param tag [out] Upon success, updated to point to the event's tag.
/// \param ok [out] Upon success, true if read a regular event, false
/// otherwise.
/// \param deadline [in] How long to block in wait for an event.
///
/// \return The type of event read.
template <typename T, typename F>
NextStatus DoThenAsyncNext(F&& f, void** tag, bool* ok, const T& deadline) {
CompletionQueueTLSCache cache = CompletionQueueTLSCache(this);
f();
if (cache.Flush(tag, ok)) {
return GOT_EVENT;
} else {
return AsyncNext(tag, ok, deadline);
}
}
/// Request the shutdown of the queue.
///
/// \warning This method must be called at some point if this completion queue
/// is accessed with Next or AsyncNext. \a Next will not return false
/// until this method has been called and all pending tags have been drained.
/// (Likewise for \a AsyncNext returning \a NextStatus::SHUTDOWN .)
/// Only once either one of these methods does that (that is, once the queue
/// has been \em drained) can an instance of this class be destroyed.
/// Also note that applications must ensure that no work is enqueued on this
/// completion queue after this method is called.
void Shutdown();
/// Returns a \em raw pointer to the underlying \a grpc_completion_queue
/// instance.
///
/// \warning Remember that the returned instance is owned. No transfer of
/// owership is performed.
grpc_completion_queue* cq() { return cq_; }
protected:
/// Private constructor of CompletionQueue only visible to friend classes
CompletionQueue(const grpc_completion_queue_attributes& attributes) {
cq_ = g_core_codegen_interface->grpc_completion_queue_create(
g_core_codegen_interface->grpc_completion_queue_factory_lookup(
&attributes),
&attributes, NULL);
InitialAvalanching(); // reserve this for the future shutdown
}
private:
// Friend synchronous wrappers so that they can access Pluck(), which is
// a semi-private API geared towards the synchronous implementation.
template <class R>
friend class ::grpc::ClientReader;
template <class W>
friend class ::grpc::ClientWriter;
template <class W, class R>
friend class ::grpc::ClientReaderWriter;
template <class R>
friend class ::grpc::ServerReader;
template <class W>
friend class ::grpc::ServerWriter;
template <class W, class R>
friend class ::grpc::internal::ServerReaderWriterBody;
template <class ServiceType, class RequestType, class ResponseType>
friend class ::grpc::internal::RpcMethodHandler;
template <class ServiceType, class RequestType, class ResponseType>
friend class ::grpc::internal::ClientStreamingHandler;
template <class ServiceType, class RequestType, class ResponseType>
friend class ::grpc::internal::ServerStreamingHandler;
template <class Streamer, bool WriteNeeded>
friend class ::grpc::internal::TemplatedBidiStreamingHandler;
template <StatusCode code>
friend class ::grpc::internal::ErrorMethodHandler;
friend class ::grpc_impl::Server;
friend class ::grpc::ServerContext;
friend class ::grpc::ServerInterface;
template <class InputMessage, class OutputMessage>
friend class ::grpc::internal::BlockingUnaryCallImpl;
// Friends that need access to constructor for callback CQ
friend class ::grpc::Channel;
// For access to Register/CompleteAvalanching
template <class Op1, class Op2, class Op3, class Op4, class Op5, class Op6>
friend class ::grpc::internal::CallOpSet;
/// EXPERIMENTAL
/// Creates a Thread Local cache to store the first event
/// On this completion queue queued from this thread. Once
/// initialized, it must be flushed on the same thread.
class CompletionQueueTLSCache {
public:
CompletionQueueTLSCache(CompletionQueue* cq);
~CompletionQueueTLSCache();
bool Flush(void** tag, bool* ok);
private:
CompletionQueue* cq_;
bool flushed_;
};
NextStatus AsyncNextInternal(void** tag, bool* ok, gpr_timespec deadline);
/// Wraps \a grpc_completion_queue_pluck.
/// \warning Must not be mixed with calls to \a Next.
bool Pluck(internal::CompletionQueueTag* tag) {
auto deadline =
g_core_codegen_interface->gpr_inf_future(GPR_CLOCK_REALTIME);
while (true) {
auto ev = g_core_codegen_interface->grpc_completion_queue_pluck(
cq_, tag, deadline, nullptr);
bool ok = ev.success != 0;
void* ignored = tag;
if (tag->FinalizeResult(&ignored, &ok)) {
GPR_CODEGEN_ASSERT(ignored == tag);
return ok;
}
}
}
/// Performs a single polling pluck on \a tag.
/// \warning Must not be mixed with calls to \a Next.
///
/// TODO: sreek - This calls tag->FinalizeResult() even if the cq_ is already
/// shutdown. This is most likely a bug and if it is a bug, then change this
/// implementation to simple call the other TryPluck function with a zero
/// timeout. i.e:
/// TryPluck(tag, gpr_time_0(GPR_CLOCK_REALTIME))
void TryPluck(internal::CompletionQueueTag* tag) {
auto deadline = g_core_codegen_interface->gpr_time_0(GPR_CLOCK_REALTIME);
auto ev = g_core_codegen_interface->grpc_completion_queue_pluck(
cq_, tag, deadline, nullptr);
if (ev.type == GRPC_QUEUE_TIMEOUT) return;
bool ok = ev.success != 0;
void* ignored = tag;
// the tag must be swallowed if using TryPluck
GPR_CODEGEN_ASSERT(!tag->FinalizeResult(&ignored, &ok));
}
/// Performs a single polling pluck on \a tag. Calls tag->FinalizeResult if
/// the pluck() was successful and returned the tag.
///
/// This exects tag->FinalizeResult (if called) to return 'false' i.e expects
/// that the tag is internal not something that is returned to the user.
void TryPluck(internal::CompletionQueueTag* tag, gpr_timespec deadline) {
auto ev = g_core_codegen_interface->grpc_completion_queue_pluck(
cq_, tag, deadline, nullptr);
if (ev.type == GRPC_QUEUE_TIMEOUT || ev.type == GRPC_QUEUE_SHUTDOWN) {
return;
}
bool ok = ev.success != 0;
void* ignored = tag;
GPR_CODEGEN_ASSERT(!tag->FinalizeResult(&ignored, &ok));
}
/// Manage state of avalanching operations : completion queue tags that
/// trigger other completion queue operations. The underlying core completion
/// queue should not really shutdown until all avalanching operations have
/// been finalized. Note that we maintain the requirement that an avalanche
/// registration must take place before CQ shutdown (which must be maintained
/// elsewhere)
void InitialAvalanching() {
gpr_atm_rel_store(&avalanches_in_flight_, static_cast<gpr_atm>(1));
}
void RegisterAvalanching() {
gpr_atm_no_barrier_fetch_add(&avalanches_in_flight_,
static_cast<gpr_atm>(1));
}
void CompleteAvalanching() {
if (gpr_atm_no_barrier_fetch_add(&avalanches_in_flight_,
static_cast<gpr_atm>(-1)) == 1) {
g_core_codegen_interface->grpc_completion_queue_shutdown(cq_);
}
}
grpc_completion_queue* cq_; // owned
gpr_atm avalanches_in_flight_;
};
/// A specific type of completion queue used by the processing of notifications
/// by servers. Instantiated by \a ServerBuilder.
class ServerCompletionQueue : public CompletionQueue {
public:
bool IsFrequentlyPolled() { return polling_type_ != GRPC_CQ_NON_LISTENING; }
protected:
/// Default constructor
ServerCompletionQueue() : polling_type_(GRPC_CQ_DEFAULT_POLLING) {}
private:
/// \param completion_type indicates whether this is a NEXT or CALLBACK
/// completion queue.
/// \param polling_type Informs the GRPC library about the type of polling
/// allowed on this completion queue. See grpc_cq_polling_type's description
/// in grpc_types.h for more details.
/// \param shutdown_cb is the shutdown callback used for CALLBACK api queues
ServerCompletionQueue(grpc_cq_completion_type completion_type,
grpc_cq_polling_type polling_type,
grpc_experimental_completion_queue_functor* shutdown_cb)
: CompletionQueue(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, completion_type, polling_type,
shutdown_cb}),
polling_type_(polling_type) {}
grpc_cq_polling_type polling_type_;
friend class grpc_impl::ServerBuilder;
friend class grpc_impl::Server;
};
typedef ::grpc_impl::CompletionQueue CompletionQueue;
typedef ::grpc_impl::ServerCompletionQueue ServerCompletionQueue;
} // namespace grpc

@ -0,0 +1,422 @@
/*
*
* Copyright 2015-2016 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/// A completion queue implements a concurrent producer-consumer queue, with
/// two main API-exposed methods: \a Next and \a AsyncNext. These
/// methods are the essential component of the gRPC C++ asynchronous API.
/// There is also a \a Shutdown method to indicate that a given completion queue
/// will no longer have regular events. This must be called before the
/// completion queue is destroyed.
/// All completion queue APIs are thread-safe and may be used concurrently with
/// any other completion queue API invocation; it is acceptable to have
/// multiple threads calling \a Next or \a AsyncNext on the same or different
/// completion queues, or to call these methods concurrently with a \a Shutdown
/// elsewhere.
/// \remark{All other API calls on completion queue should be completed before
/// a completion queue destructor is called.}
#ifndef GRPCPP_IMPL_CODEGEN_COMPLETION_QUEUE_IMPL_H
#define GRPCPP_IMPL_CODEGEN_COMPLETION_QUEUE_IMPL_H
#include <grpc/impl/codegen/atm.h>
#include <grpcpp/impl/codegen/completion_queue_tag.h>
#include <grpcpp/impl/codegen/core_codegen_interface.h>
#include <grpcpp/impl/codegen/grpc_library.h>
#include <grpcpp/impl/codegen/status.h>
#include <grpcpp/impl/codegen/time.h>
struct grpc_completion_queue;
namespace grpc_impl {
class Channel;
class Server;
class ServerBuilder;
} // namespace grpc_impl
namespace grpc {
template <class R>
class ClientReader;
template <class W>
class ClientWriter;
template <class W, class R>
class ClientReaderWriter;
template <class R>
class ServerReader;
template <class W>
class ServerWriter;
namespace internal {
template <class W, class R>
class ServerReaderWriterBody;
} // namespace internal
class ChannelInterface;
class ClientContext;
class ServerContext;
class ServerInterface;
namespace internal {
class CompletionQueueTag;
class RpcMethod;
template <class ServiceType, class RequestType, class ResponseType>
class RpcMethodHandler;
template <class ServiceType, class RequestType, class ResponseType>
class ClientStreamingHandler;
template <class ServiceType, class RequestType, class ResponseType>
class ServerStreamingHandler;
template <class ServiceType, class RequestType, class ResponseType>
class BidiStreamingHandler;
template <class Streamer, bool WriteNeeded>
class TemplatedBidiStreamingHandler;
template <StatusCode code>
class ErrorMethodHandler;
template <class InputMessage, class OutputMessage>
class BlockingUnaryCallImpl;
template <class Op1, class Op2, class Op3, class Op4, class Op5, class Op6>
class CallOpSet;
} // namespace internal
extern CoreCodegenInterface* g_core_codegen_interface;
} // namespace grpc
namespace grpc_impl {
/// A thin wrapper around \ref grpc_completion_queue (see \ref
/// src/core/lib/surface/completion_queue.h).
/// See \ref doc/cpp/perf_notes.md for notes on best practices for high
/// performance servers.
class CompletionQueue : private ::grpc::GrpcLibraryCodegen {
public:
/// Default constructor. Implicitly creates a \a grpc_completion_queue
/// instance.
CompletionQueue()
: CompletionQueue(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_NEXT, GRPC_CQ_DEFAULT_POLLING,
nullptr}) {}
/// Wrap \a take, taking ownership of the instance.
///
/// \param take The completion queue instance to wrap. Ownership is taken.
explicit CompletionQueue(grpc_completion_queue* take);
/// Destructor. Destroys the owned wrapped completion queue / instance.
~CompletionQueue() {
::grpc::g_core_codegen_interface->grpc_completion_queue_destroy(cq_);
}
/// Tri-state return for AsyncNext: SHUTDOWN, GOT_EVENT, TIMEOUT.
enum NextStatus {
SHUTDOWN, ///< The completion queue has been shutdown and fully-drained
GOT_EVENT, ///< Got a new event; \a tag will be filled in with its
///< associated value; \a ok indicating its success.
TIMEOUT ///< deadline was reached.
};
/// Read from the queue, blocking until an event is available or the queue is
/// shutting down.
///
/// \param tag [out] Updated to point to the read event's tag.
/// \param ok [out] true if read a successful event, false otherwise.
///
/// Note that each tag sent to the completion queue (through RPC operations
/// or alarms) will be delivered out of the completion queue by a call to
/// Next (or a related method), regardless of whether the operation succeeded
/// or not. Success here means that this operation completed in the normal
/// valid manner.
///
/// Server-side RPC request: \a ok indicates that the RPC has indeed
/// been started. If it is false, the server has been Shutdown
/// before this particular call got matched to an incoming RPC.
///
/// Client-side StartCall/RPC invocation: \a ok indicates that the RPC is
/// going to go to the wire. If it is false, it not going to the wire. This
/// would happen if the channel is either permanently broken or
/// transiently broken but with the fail-fast option. (Note that async unary
/// RPCs don't post a CQ tag at this point, nor do client-streaming
/// or bidi-streaming RPCs that have the initial metadata corked option set.)
///
/// Client-side Write, Client-side WritesDone, Server-side Write,
/// Server-side Finish, Server-side SendInitialMetadata (which is
/// typically included in Write or Finish when not done explicitly):
/// \a ok means that the data/metadata/status/etc is going to go to the
/// wire. If it is false, it not going to the wire because the call
/// is already dead (i.e., canceled, deadline expired, other side
/// dropped the channel, etc).
///
/// Client-side Read, Server-side Read, Client-side
/// RecvInitialMetadata (which is typically included in Read if not
/// done explicitly): \a ok indicates whether there is a valid message
/// that got read. If not, you know that there are certainly no more
/// messages that can ever be read from this stream. For the client-side
/// operations, this only happens because the call is dead. For the
/// server-sider operation, though, this could happen because the client
/// has done a WritesDone already.
///
/// Client-side Finish: \a ok should always be true
///
/// Server-side AsyncNotifyWhenDone: \a ok should always be true
///
/// Alarm: \a ok is true if it expired, false if it was canceled
///
/// \return true if got an event, false if the queue is fully drained and
/// shut down.
bool Next(void** tag, bool* ok) {
return (AsyncNextInternal(tag, ok,
::grpc::g_core_codegen_interface->gpr_inf_future(
GPR_CLOCK_REALTIME)) != SHUTDOWN);
}
/// Read from the queue, blocking up to \a deadline (or the queue's shutdown).
/// Both \a tag and \a ok are updated upon success (if an event is available
/// within the \a deadline). A \a tag points to an arbitrary location usually
/// employed to uniquely identify an event.
///
/// \param tag [out] Upon success, updated to point to the event's tag.
/// \param ok [out] Upon success, true if a successful event, false otherwise
/// See documentation for CompletionQueue::Next for explanation of ok
/// \param deadline [in] How long to block in wait for an event.
///
/// \return The type of event read.
template <typename T>
NextStatus AsyncNext(void** tag, bool* ok, const T& deadline) {
::grpc::TimePoint<T> deadline_tp(deadline);
return AsyncNextInternal(tag, ok, deadline_tp.raw_time());
}
/// EXPERIMENTAL
/// First executes \a F, then reads from the queue, blocking up to
/// \a deadline (or the queue's shutdown).
/// Both \a tag and \a ok are updated upon success (if an event is available
/// within the \a deadline). A \a tag points to an arbitrary location usually
/// employed to uniquely identify an event.
///
/// \param f [in] Function to execute before calling AsyncNext on this queue.
/// \param tag [out] Upon success, updated to point to the event's tag.
/// \param ok [out] Upon success, true if read a regular event, false
/// otherwise.
/// \param deadline [in] How long to block in wait for an event.
///
/// \return The type of event read.
template <typename T, typename F>
NextStatus DoThenAsyncNext(F&& f, void** tag, bool* ok, const T& deadline) {
CompletionQueueTLSCache cache = CompletionQueueTLSCache(this);
f();
if (cache.Flush(tag, ok)) {
return GOT_EVENT;
} else {
return AsyncNext(tag, ok, deadline);
}
}
/// Request the shutdown of the queue.
///
/// \warning This method must be called at some point if this completion queue
/// is accessed with Next or AsyncNext. \a Next will not return false
/// until this method has been called and all pending tags have been drained.
/// (Likewise for \a AsyncNext returning \a NextStatus::SHUTDOWN .)
/// Only once either one of these methods does that (that is, once the queue
/// has been \em drained) can an instance of this class be destroyed.
/// Also note that applications must ensure that no work is enqueued on this
/// completion queue after this method is called.
void Shutdown();
/// Returns a \em raw pointer to the underlying \a grpc_completion_queue
/// instance.
///
/// \warning Remember that the returned instance is owned. No transfer of
/// owership is performed.
grpc_completion_queue* cq() { return cq_; }
protected:
/// Private constructor of CompletionQueue only visible to friend classes
CompletionQueue(const grpc_completion_queue_attributes& attributes) {
cq_ = ::grpc::g_core_codegen_interface->grpc_completion_queue_create(
::grpc::g_core_codegen_interface->grpc_completion_queue_factory_lookup(
&attributes),
&attributes, NULL);
InitialAvalanching(); // reserve this for the future shutdown
}
private:
// Friend synchronous wrappers so that they can access Pluck(), which is
// a semi-private API geared towards the synchronous implementation.
template <class R>
friend class ::grpc::ClientReader;
template <class W>
friend class ::grpc::ClientWriter;
template <class W, class R>
friend class ::grpc::ClientReaderWriter;
template <class R>
friend class ::grpc::ServerReader;
template <class W>
friend class ::grpc::ServerWriter;
template <class W, class R>
friend class ::grpc::internal::ServerReaderWriterBody;
template <class ServiceType, class RequestType, class ResponseType>
friend class ::grpc::internal::RpcMethodHandler;
template <class ServiceType, class RequestType, class ResponseType>
friend class ::grpc::internal::ClientStreamingHandler;
template <class ServiceType, class RequestType, class ResponseType>
friend class ::grpc::internal::ServerStreamingHandler;
template <class Streamer, bool WriteNeeded>
friend class ::grpc::internal::TemplatedBidiStreamingHandler;
template <::grpc::StatusCode code>
friend class ::grpc::internal::ErrorMethodHandler;
friend class ::grpc_impl::Server;
friend class ::grpc::ServerContext;
friend class ::grpc::ServerInterface;
template <class InputMessage, class OutputMessage>
friend class ::grpc::internal::BlockingUnaryCallImpl;
// Friends that need access to constructor for callback CQ
friend class ::grpc_impl::Channel;
// For access to Register/CompleteAvalanching
template <class Op1, class Op2, class Op3, class Op4, class Op5, class Op6>
friend class ::grpc::internal::CallOpSet;
/// EXPERIMENTAL
/// Creates a Thread Local cache to store the first event
/// On this completion queue queued from this thread. Once
/// initialized, it must be flushed on the same thread.
class CompletionQueueTLSCache {
public:
CompletionQueueTLSCache(CompletionQueue* cq);
~CompletionQueueTLSCache();
bool Flush(void** tag, bool* ok);
private:
CompletionQueue* cq_;
bool flushed_;
};
NextStatus AsyncNextInternal(void** tag, bool* ok, gpr_timespec deadline);
/// Wraps \a grpc_completion_queue_pluck.
/// \warning Must not be mixed with calls to \a Next.
bool Pluck(::grpc::internal::CompletionQueueTag* tag) {
auto deadline =
::grpc::g_core_codegen_interface->gpr_inf_future(GPR_CLOCK_REALTIME);
while (true) {
auto ev = ::grpc::g_core_codegen_interface->grpc_completion_queue_pluck(
cq_, tag, deadline, nullptr);
bool ok = ev.success != 0;
void* ignored = tag;
if (tag->FinalizeResult(&ignored, &ok)) {
GPR_CODEGEN_ASSERT(ignored == tag);
return ok;
}
}
}
/// Performs a single polling pluck on \a tag.
/// \warning Must not be mixed with calls to \a Next.
///
/// TODO: sreek - This calls tag->FinalizeResult() even if the cq_ is already
/// shutdown. This is most likely a bug and if it is a bug, then change this
/// implementation to simple call the other TryPluck function with a zero
/// timeout. i.e:
/// TryPluck(tag, gpr_time_0(GPR_CLOCK_REALTIME))
void TryPluck(::grpc::internal::CompletionQueueTag* tag) {
auto deadline =
::grpc::g_core_codegen_interface->gpr_time_0(GPR_CLOCK_REALTIME);
auto ev = ::grpc::g_core_codegen_interface->grpc_completion_queue_pluck(
cq_, tag, deadline, nullptr);
if (ev.type == GRPC_QUEUE_TIMEOUT) return;
bool ok = ev.success != 0;
void* ignored = tag;
// the tag must be swallowed if using TryPluck
GPR_CODEGEN_ASSERT(!tag->FinalizeResult(&ignored, &ok));
}
/// Performs a single polling pluck on \a tag. Calls tag->FinalizeResult if
/// the pluck() was successful and returned the tag.
///
/// This exects tag->FinalizeResult (if called) to return 'false' i.e expects
/// that the tag is internal not something that is returned to the user.
void TryPluck(::grpc::internal::CompletionQueueTag* tag,
gpr_timespec deadline) {
auto ev = ::grpc::g_core_codegen_interface->grpc_completion_queue_pluck(
cq_, tag, deadline, nullptr);
if (ev.type == GRPC_QUEUE_TIMEOUT || ev.type == GRPC_QUEUE_SHUTDOWN) {
return;
}
bool ok = ev.success != 0;
void* ignored = tag;
GPR_CODEGEN_ASSERT(!tag->FinalizeResult(&ignored, &ok));
}
/// Manage state of avalanching operations : completion queue tags that
/// trigger other completion queue operations. The underlying core completion
/// queue should not really shutdown until all avalanching operations have
/// been finalized. Note that we maintain the requirement that an avalanche
/// registration must take place before CQ shutdown (which must be maintained
/// elsehwere)
void InitialAvalanching() {
gpr_atm_rel_store(&avalanches_in_flight_, static_cast<gpr_atm>(1));
}
void RegisterAvalanching() {
gpr_atm_no_barrier_fetch_add(&avalanches_in_flight_,
static_cast<gpr_atm>(1));
}
void CompleteAvalanching() {
if (gpr_atm_no_barrier_fetch_add(&avalanches_in_flight_,
static_cast<gpr_atm>(-1)) == 1) {
::grpc::g_core_codegen_interface->grpc_completion_queue_shutdown(cq_);
}
}
grpc_completion_queue* cq_; // owned
gpr_atm avalanches_in_flight_;
};
/// A specific type of completion queue used by the processing of notifications
/// by servers. Instantiated by \a ServerBuilder.
class ServerCompletionQueue : public CompletionQueue {
public:
bool IsFrequentlyPolled() { return polling_type_ != GRPC_CQ_NON_LISTENING; }
protected:
/// Default constructor
ServerCompletionQueue() : polling_type_(GRPC_CQ_DEFAULT_POLLING) {}
private:
/// \param completion_type indicates whether this is a NEXT or CALLBACK
/// completion queue.
/// \param polling_type Informs the GRPC library about the type of polling
/// allowed on this completion queue. See grpc_cq_polling_type's description
/// in grpc_types.h for more details.
/// \param shutdown_cb is the shutdown callback used for CALLBACK api queues
ServerCompletionQueue(grpc_cq_completion_type completion_type,
grpc_cq_polling_type polling_type,
grpc_experimental_completion_queue_functor* shutdown_cb)
: CompletionQueue(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, completion_type, polling_type,
shutdown_cb}),
polling_type_(polling_type) {}
grpc_cq_polling_type polling_type_;
friend class ::grpc_impl::ServerBuilder;
friend class ::grpc_impl::Server;
};
} // namespace grpc_impl
#endif // GRPCPP_IMPL_CODEGEN_COMPLETION_QUEUE_IMPL_H

@ -19,6 +19,7 @@
#ifndef GRPCPP_IMPL_CODEGEN_CORE_CODEGEN_INTERFACE_H
#define GRPCPP_IMPL_CODEGEN_CORE_CODEGEN_INTERFACE_H
#include <grpc/impl/codegen/byte_buffer.h>
#include <grpc/impl/codegen/byte_buffer_reader.h>
#include <grpc/impl/codegen/grpc_types.h>
#include <grpc/impl/codegen/sync.h>

@ -21,6 +21,10 @@
#include <grpcpp/impl/codegen/channel_interface.h>
namespace grpc_impl {
class CompletionQueue;
}
namespace grpc {
namespace internal {
@ -46,7 +50,7 @@ class InterceptedChannel : public ChannelInterface {
: channel_(channel), interceptor_pos_(pos) {}
Call CreateCall(const RpcMethod& method, ClientContext* context,
CompletionQueue* cq) override {
::grpc_impl::CompletionQueue* cq) override {
return channel_->CreateCallInternal(method, context, cq, interceptor_pos_);
}
@ -58,7 +62,8 @@ class InterceptedChannel : public ChannelInterface {
}
void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed,
gpr_timespec deadline, CompletionQueue* cq,
gpr_timespec deadline,
::grpc_impl::CompletionQueue* cq,
void* tag) override {
return channel_->NotifyOnStateChangeImpl(last_observed, deadline, cq, tag);
}
@ -67,7 +72,9 @@ class InterceptedChannel : public ChannelInterface {
return channel_->WaitForStateChangeImpl(last_observed, deadline);
}
CompletionQueue* CallbackCQ() override { return channel_->CallbackCQ(); }
::grpc_impl::CompletionQueue* CallbackCQ() override {
return channel_->CallbackCQ();
}
ChannelInterface* channel_;
size_t interceptor_pos_;

@ -43,12 +43,12 @@ struct census_context;
namespace grpc_impl {
class CompletionQueue;
class Server;
} // namespace grpc_impl
namespace grpc {
class ClientContext;
class GenericServerContext;
class CompletionQueue;
class ServerInterface;
template <class W, class R>
class ServerAsyncReader;
@ -90,6 +90,7 @@ class Call;
class ServerReactor;
} // namespace internal
class ServerInterface;
namespace testing {
class InteropServerContextInspector;
class ServerContextTestSpouse;
@ -354,7 +355,7 @@ class ServerContext {
gpr_timespec deadline_;
grpc_call* call_;
CompletionQueue* cq_;
::grpc_impl::CompletionQueue* cq_;
bool sent_initial_metadata_;
mutable std::shared_ptr<const AuthContext> auth_context_;
mutable internal::MetadataMap client_metadata_;

@ -30,14 +30,15 @@
namespace grpc_impl {
class Channel;
class CompletionQueue;
class ServerCompletionQueue;
class ServerCredentials;
} // namespace grpc_impl
namespace grpc {
class AsyncGenericService;
class Channel;
class GenericServerContext;
class ServerCompletionQueue;
class ServerContext;
class Service;
@ -161,7 +162,8 @@ class ServerInterface : public internal::CallHook {
/// caller is required to keep all completion queues live until the server is
/// destroyed.
/// \param num_cqs How many completion queues does \a cqs hold.
virtual void Start(ServerCompletionQueue** cqs, size_t num_cqs) = 0;
virtual void Start(::grpc_impl::ServerCompletionQueue** cqs,
size_t num_cqs) = 0;
virtual void ShutdownInternal(gpr_timespec deadline) = 0;
@ -176,9 +178,9 @@ class ServerInterface : public internal::CallHook {
public:
BaseAsyncRequest(ServerInterface* server, ServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
CompletionQueue* call_cq,
ServerCompletionQueue* notification_cq, void* tag,
bool delete_on_finalize);
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq,
void* tag, bool delete_on_finalize);
virtual ~BaseAsyncRequest();
bool FinalizeResult(void** tag, bool* status) override;
@ -190,8 +192,8 @@ class ServerInterface : public internal::CallHook {
ServerInterface* const server_;
ServerContext* const context_;
internal::ServerAsyncStreamingInterface* const stream_;
CompletionQueue* const call_cq_;
ServerCompletionQueue* const notification_cq_;
::grpc_impl::CompletionQueue* const call_cq_;
::grpc_impl::ServerCompletionQueue* const notification_cq_;
void* const tag_;
const bool delete_on_finalize_;
grpc_call* call_;
@ -205,16 +207,17 @@ class ServerInterface : public internal::CallHook {
public:
RegisteredAsyncRequest(ServerInterface* server, ServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
CompletionQueue* call_cq,
ServerCompletionQueue* notification_cq, void* tag,
const char* name, internal::RpcMethod::RpcType type);
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq,
void* tag, const char* name,
internal::RpcMethod::RpcType type);
virtual bool FinalizeResult(void** tag, bool* status) override {
/* If we are done intercepting, then there is nothing more for us to do */
if (done_intercepting_) {
return BaseAsyncRequest::FinalizeResult(tag, status);
}
call_wrapper_ = internal::Call(
call_wrapper_ = ::grpc::internal::Call(
call_, server_, call_cq_, server_->max_receive_message_size(),
context_->set_server_rpc_info(name_, type_,
*server_->interceptor_creators()));
@ -223,7 +226,7 @@ class ServerInterface : public internal::CallHook {
protected:
void IssueRequest(void* registered_method, grpc_byte_buffer** payload,
ServerCompletionQueue* notification_cq);
::grpc_impl::ServerCompletionQueue* notification_cq);
const char* name_;
const internal::RpcMethod::RpcType type_;
};
@ -233,8 +236,9 @@ class ServerInterface : public internal::CallHook {
NoPayloadAsyncRequest(internal::RpcServiceMethod* registered_method,
ServerInterface* server, ServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
CompletionQueue* call_cq,
ServerCompletionQueue* notification_cq, void* tag)
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq,
void* tag)
: RegisteredAsyncRequest(
server, context, stream, call_cq, notification_cq, tag,
registered_method->name(), registered_method->method_type()) {
@ -250,9 +254,9 @@ class ServerInterface : public internal::CallHook {
PayloadAsyncRequest(internal::RpcServiceMethod* registered_method,
ServerInterface* server, ServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
CompletionQueue* call_cq,
ServerCompletionQueue* notification_cq, void* tag,
Message* request)
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq,
void* tag, Message* request)
: RegisteredAsyncRequest(
server, context, stream, call_cq, notification_cq, tag,
registered_method->name(), registered_method->method_type()),
@ -307,9 +311,9 @@ class ServerInterface : public internal::CallHook {
ServerInterface* const server_;
ServerContext* const context_;
internal::ServerAsyncStreamingInterface* const stream_;
CompletionQueue* const call_cq_;
::grpc_impl::CompletionQueue* const call_cq_;
ServerCompletionQueue* const notification_cq_;
::grpc_impl::ServerCompletionQueue* const notification_cq_;
void* const tag_;
Message* const request_;
ByteBuffer payload_;
@ -319,9 +323,9 @@ class ServerInterface : public internal::CallHook {
public:
GenericAsyncRequest(ServerInterface* server, GenericServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
CompletionQueue* call_cq,
ServerCompletionQueue* notification_cq, void* tag,
bool delete_on_finalize);
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq,
void* tag, bool delete_on_finalize);
bool FinalizeResult(void** tag, bool* status) override;
@ -333,9 +337,9 @@ class ServerInterface : public internal::CallHook {
void RequestAsyncCall(internal::RpcServiceMethod* method,
ServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
CompletionQueue* call_cq,
ServerCompletionQueue* notification_cq, void* tag,
Message* message) {
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq,
void* tag, Message* message) {
GPR_CODEGEN_ASSERT(method);
new PayloadAsyncRequest<Message>(method, this, context, stream, call_cq,
notification_cq, tag, message);
@ -344,18 +348,19 @@ class ServerInterface : public internal::CallHook {
void RequestAsyncCall(internal::RpcServiceMethod* method,
ServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
CompletionQueue* call_cq,
ServerCompletionQueue* notification_cq, void* tag) {
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq,
void* tag) {
GPR_CODEGEN_ASSERT(method);
new NoPayloadAsyncRequest(method, this, context, stream, call_cq,
notification_cq, tag);
}
void RequestAsyncGenericCall(GenericServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
CompletionQueue* call_cq,
ServerCompletionQueue* notification_cq,
void* tag) {
void RequestAsyncGenericCall(
GenericServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq, void* tag) {
new GenericAsyncRequest(this, context, stream, call_cq, notification_cq,
tag, true);
}
@ -380,7 +385,7 @@ class ServerInterface : public internal::CallHook {
// Returns nullptr (rather than being pure) since this is a post-1.0 method
// and adding a new pure method to an interface would be a breaking change
// (even though this is private and non-API)
virtual CompletionQueue* CallbackCQ() { return nullptr; }
virtual ::grpc_impl::CompletionQueue* CallbackCQ() { return nullptr; }
};
} // namespace grpc

@ -29,12 +29,11 @@
namespace grpc_impl {
class Server;
class CompletionQueue;
} // namespace grpc_impl
namespace grpc {
class CompletionQueue;
class ServerInterface;
class ServerCompletionQueue;
class ServerContext;
namespace internal {

@ -24,6 +24,7 @@
#include <vector>
#include <grpc/grpc_security_constants.h>
#include <grpcpp/channel.h>
#include <grpcpp/impl/codegen/client_interceptor.h>
#include <grpcpp/impl/codegen/grpc_library.h>
#include <grpcpp/security/auth_context.h>

@ -21,13 +21,6 @@
#include <grpcpp/server_builder_impl.h>
namespace grpc_impl {
class Server;
class ServerCredentials;
class ResourceQuota;
} // namespace grpc_impl
namespace grpc {
typedef ::grpc_impl::ServerBuilder ServerBuilder;

@ -38,15 +38,16 @@ struct grpc_resource_quota;
namespace grpc_impl {
class CompletionQueue;
class ResourceQuota;
class Server;
class ServerCompletionQueue;
class ServerCredentials;
} // namespace grpc_impl
namespace grpc {
class AsyncGenericService;
class CompletionQueue;
class ServerCompletionQueue;
class Service;
namespace testing {
class ServerBuilderPluginTest;
@ -155,7 +156,7 @@ class ServerBuilder {
/// not polling the completion queue frequently) will have a significantly
/// negative performance impact and hence should not be used in production
/// use cases.
std::unique_ptr<grpc::ServerCompletionQueue> AddCompletionQueue(
std::unique_ptr<grpc_impl::ServerCompletionQueue> AddCompletionQueue(
bool is_frequently_polled = true);
//////////////////////////////////////////////////////////////////////////////
@ -361,7 +362,7 @@ class ServerBuilder {
SyncServerSettings sync_server_settings_;
/// List of completion queues added via \a AddCompletionQueue method.
std::vector<grpc::ServerCompletionQueue*> cqs_;
std::vector<grpc_impl::ServerCompletionQueue*> cqs_;
std::shared_ptr<grpc_impl::ServerCredentials> creds_;
std::vector<std::unique_ptr<grpc::ServerBuilderPlugin>> plugins_;

@ -27,6 +27,7 @@
#include <grpc/compression.h>
#include <grpc/support/atm.h>
#include <grpcpp/channel.h>
#include <grpcpp/completion_queue.h>
#include <grpcpp/health_check_service_interface.h>
#include <grpcpp/impl/call.h>
@ -107,7 +108,7 @@ class Server : public grpc::ServerInterface, private grpc::GrpcLibraryCodegen {
}
/// Establish a channel for in-process communication
std::shared_ptr<grpc::Channel> InProcessChannel(
std::shared_ptr<::grpc::Channel> InProcessChannel(
const grpc::ChannelArguments& args);
/// NOTE: class experimental_type is not part of the public API of this class.
@ -119,7 +120,7 @@ class Server : public grpc::ServerInterface, private grpc::GrpcLibraryCodegen {
/// Establish a channel for in-process communication with client
/// interceptors
std::shared_ptr<grpc::Channel> InProcessChannelWithInterceptors(
std::shared_ptr<::grpc::Channel> InProcessChannelWithInterceptors(
const grpc::ChannelArguments& args,
std::vector<std::unique_ptr<
grpc::experimental::ClientInterceptorFactoryInterface>>

@ -61,8 +61,8 @@ class ChannelArguments {
void SetChannelArgs(grpc_channel_args* channel_args) const;
// gRPC specific channel argument setters
/// Set target name override for SSL host name checking. This option is for
/// testing only and should never be used in production.
/// Set target name override for SSL host name checking. This option should
/// be used with caution in production.
void SetSslTargetNameOverride(const grpc::string& name);
// TODO(yangg) add flow control options
/// Set the compression algorithm for the channel.

@ -0,0 +1,36 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPCPP_SUPPORT_VALIDATE_SERVICE_CONFIG_H
#define GRPCPP_SUPPORT_VALIDATE_SERVICE_CONFIG_H
#include <grpcpp/support/config.h>
namespace grpc {
namespace experimental {
/// Validates \a service_config_json. If valid, returns an empty string.
/// Otherwise, returns the validation error.
/// TODO(yashykt): Promote it to out of experimental once it is proved useful
/// and gRFC is accepted.
grpc::string ValidateServiceConfigJSON(const grpc::string& service_config_json);
} // namespace experimental
} // namespace grpc
#endif // GRPCPP_SUPPORT_VALIDATE_SERVICE_CONFIG_H

@ -154,13 +154,15 @@ grpc::string GetHeaderIncludes(grpc_generator::File* file,
PrintIncludes(printer.get(), headers, params.use_system_headers,
params.grpc_search_path);
printer->Print(vars, "\n");
printer->Print(vars, "namespace grpc_impl {\n");
printer->Print(vars, "class CompletionQueue;\n");
printer->Print(vars, "class ServerCompletionQueue;\n");
printer->Print(vars, "} // namespace grpc_impl\n\n");
printer->Print(vars, "namespace grpc {\n");
printer->Print(vars, "namespace experimental {\n");
printer->Print(vars, "template <typename RequestT, typename ResponseT>\n");
printer->Print(vars, "class MessageAllocator;\n");
printer->Print(vars, "} // namespace experimental\n");
printer->Print(vars, "class CompletionQueue;\n");
printer->Print(vars, "class ServerCompletionQueue;\n");
printer->Print(vars, "class ServerContext;\n");
printer->Print(vars, "} // namespace grpc\n\n");

@ -105,7 +105,6 @@ namespace {
class ChannelData {
public:
struct QueuedPick {
LoadBalancingPolicy::PickArgs pick;
grpc_call_element* elem;
QueuedPick* next = nullptr;
};
@ -223,7 +222,7 @@ class ChannelData {
static bool ProcessResolverResultLocked(
void* arg, Resolver::Result* result, const char** lb_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig>* lb_policy_config,
RefCountedPtr<LoadBalancingPolicy::Config>* lb_policy_config,
grpc_error** service_config_error);
grpc_error* DoPingLocked(grpc_transport_op* op);
@ -236,7 +235,7 @@ class ChannelData {
const Resolver::Result& resolver_result,
const internal::ClientChannelGlobalParsedConfig* parsed_service_config,
UniquePtr<char>* lb_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig>* lb_policy_config);
RefCountedPtr<LoadBalancingPolicy::Config>* lb_policy_config);
//
// Fields set at construction and never modified.
@ -314,6 +313,16 @@ class CallData {
private:
class QueuedPickCanceller;
class LbCallState : public LoadBalancingPolicy::CallState {
public:
explicit LbCallState(CallData* calld) : calld_(calld) {}
void* Alloc(size_t size) override { return calld_->arena_->Alloc(size); }
private:
CallData* calld_;
};
// State used for starting a retryable batch on a subchannel call.
// This provides its own grpc_transport_stream_op_batch and other data
// structures needed to populate the ops in the batch.
@ -449,8 +458,9 @@ class CallData {
grpc_call_element* elem, SubchannelCallBatchData* batch_data,
SubchannelCallRetryState* retry_state);
static void MaybeInjectRecvTrailingMetadataReadyForLoadBalancingPolicy(
const LoadBalancingPolicy::PickArgs& pick,
static void RecvTrailingMetadataReadyForLoadBalancingPolicy(
void* arg, grpc_error* error);
void MaybeInjectRecvTrailingMetadataReadyForLoadBalancingPolicy(
grpc_transport_stream_op_batch* batch);
// Returns the index into pending_batches_ to be used for batch.
@ -640,8 +650,19 @@ class CallData {
bool pick_queued_ = false;
bool service_config_applied_ = false;
QueuedPickCanceller* pick_canceller_ = nullptr;
LbCallState lb_call_state_;
RefCountedPtr<ConnectedSubchannel> connected_subchannel_;
void (*lb_recv_trailing_metadata_ready_)(
void* user_data, grpc_metadata_batch* recv_trailing_metadata,
LoadBalancingPolicy::CallState* call_state) = nullptr;
void* lb_recv_trailing_metadata_ready_user_data_ = nullptr;
grpc_closure pick_closure_;
// For intercepting recv_trailing_metadata_ready for the LB policy.
grpc_metadata_batch* recv_trailing_metadata_ = nullptr;
grpc_closure recv_trailing_metadata_ready_;
grpc_closure* original_recv_trailing_metadata_ready_ = nullptr;
grpc_polling_entity* pollent_ = nullptr;
// Batches are added to this list when received from above.
@ -1143,7 +1164,7 @@ void ChannelData::ProcessLbPolicy(
const Resolver::Result& resolver_result,
const internal::ClientChannelGlobalParsedConfig* parsed_service_config,
UniquePtr<char>* lb_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig>* lb_policy_config) {
RefCountedPtr<LoadBalancingPolicy::Config>* lb_policy_config) {
// Prefer the LB policy name found in the service config.
if (parsed_service_config != nullptr &&
parsed_service_config->parsed_lb_config() != nullptr) {
@ -1191,7 +1212,7 @@ void ChannelData::ProcessLbPolicy(
// resolver result update.
bool ChannelData::ProcessResolverResultLocked(
void* arg, Resolver::Result* result, const char** lb_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig>* lb_policy_config,
RefCountedPtr<LoadBalancingPolicy::Config>* lb_policy_config,
grpc_error** service_config_error) {
ChannelData* chand = static_cast<ChannelData*>(arg);
RefCountedPtr<ServiceConfig> service_config;
@ -1312,19 +1333,18 @@ grpc_error* ChannelData::DoPingLocked(grpc_transport_op* op) {
if (grpc_connectivity_state_check(&state_tracker_) != GRPC_CHANNEL_READY) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("channel not connected");
}
LoadBalancingPolicy::PickArgs pick;
grpc_error* error = GRPC_ERROR_NONE;
picker_->Pick(&pick, &error);
if (pick.connected_subchannel != nullptr) {
pick.connected_subchannel->Ping(op->send_ping.on_initiate,
op->send_ping.on_ack);
LoadBalancingPolicy::PickResult result =
picker_->Pick(LoadBalancingPolicy::PickArgs());
if (result.connected_subchannel != nullptr) {
result.connected_subchannel->Ping(op->send_ping.on_initiate,
op->send_ping.on_ack);
} else {
if (error == GRPC_ERROR_NONE) {
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
if (result.error == GRPC_ERROR_NONE) {
result.error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"LB policy dropped call on ping");
}
}
return error;
return result.error;
}
void ChannelData::StartTransportOpLocked(void* arg, grpc_error* ignored) {
@ -1505,6 +1525,7 @@ CallData::CallData(grpc_call_element* elem, const ChannelData& chand,
owning_call_(args.call_stack),
call_combiner_(args.call_combiner),
call_context_(args.context),
lb_call_state_(this),
pending_send_initial_metadata_(false),
pending_send_message_(false),
pending_send_trailing_metadata_(false),
@ -1737,18 +1758,30 @@ void CallData::FreeCachedSendOpDataForCompletedBatch(
// LB recv_trailing_metadata_ready handling
//
void CallData::RecvTrailingMetadataReadyForLoadBalancingPolicy(
void* arg, grpc_error* error) {
CallData* calld = static_cast<CallData*>(arg);
// Invoke callback to LB policy.
calld->lb_recv_trailing_metadata_ready_(
calld->lb_recv_trailing_metadata_ready_user_data_,
calld->recv_trailing_metadata_, &calld->lb_call_state_);
// Chain to original callback.
GRPC_CLOSURE_RUN(calld->original_recv_trailing_metadata_ready_,
GRPC_ERROR_REF(error));
}
void CallData::MaybeInjectRecvTrailingMetadataReadyForLoadBalancingPolicy(
const LoadBalancingPolicy::PickArgs& pick,
grpc_transport_stream_op_batch* batch) {
if (pick.recv_trailing_metadata_ready != nullptr) {
*pick.original_recv_trailing_metadata_ready =
if (lb_recv_trailing_metadata_ready_ != nullptr) {
recv_trailing_metadata_ =
batch->payload->recv_trailing_metadata.recv_trailing_metadata;
original_recv_trailing_metadata_ready_ =
batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready;
GRPC_CLOSURE_INIT(&recv_trailing_metadata_ready_,
RecvTrailingMetadataReadyForLoadBalancingPolicy, this,
grpc_schedule_on_exec_ctx);
batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready =
pick.recv_trailing_metadata_ready;
if (pick.recv_trailing_metadata != nullptr) {
*pick.recv_trailing_metadata =
batch->payload->recv_trailing_metadata.recv_trailing_metadata;
}
&recv_trailing_metadata_ready_;
}
}
@ -1894,8 +1927,7 @@ void CallData::PendingBatchesFail(
grpc_transport_stream_op_batch* batch = pending->batch;
if (batch != nullptr) {
if (batch->recv_trailing_metadata) {
MaybeInjectRecvTrailingMetadataReadyForLoadBalancingPolicy(pick_.pick,
batch);
MaybeInjectRecvTrailingMetadataReadyForLoadBalancingPolicy(batch);
}
batch->handler_private.extra_arg = this;
GRPC_CLOSURE_INIT(&batch->handler_private.closure,
@ -1949,8 +1981,7 @@ void CallData::PendingBatchesResume(grpc_call_element* elem) {
grpc_transport_stream_op_batch* batch = pending->batch;
if (batch != nullptr) {
if (batch->recv_trailing_metadata) {
MaybeInjectRecvTrailingMetadataReadyForLoadBalancingPolicy(pick_.pick,
batch);
MaybeInjectRecvTrailingMetadataReadyForLoadBalancingPolicy(batch);
}
batch->handler_private.extra_arg = subchannel_call_.get();
GRPC_CLOSURE_INIT(&batch->handler_private.closure,
@ -2011,7 +2042,7 @@ void CallData::DoRetry(grpc_call_element* elem,
GPR_ASSERT(retry_policy != nullptr);
// Reset subchannel call and connected subchannel.
subchannel_call_.reset();
pick_.pick.connected_subchannel.reset();
connected_subchannel_.reset();
// Compute backoff delay.
grpc_millis next_attempt_time;
if (server_pushback_ms >= 0) {
@ -2868,7 +2899,7 @@ void CallData::AddRetriableRecvTrailingMetadataOp(
.recv_trailing_metadata_ready =
&retry_state->recv_trailing_metadata_ready;
MaybeInjectRecvTrailingMetadataReadyForLoadBalancingPolicy(
pick_.pick, &batch_data->batch);
&batch_data->batch);
}
void CallData::StartInternalRecvTrailingMetadata(grpc_call_element* elem) {
@ -3135,8 +3166,7 @@ void CallData::CreateSubchannelCall(grpc_call_element* elem) {
// need to use a separate call context for each subchannel call.
call_context_, call_combiner_, parent_data_size};
grpc_error* error = GRPC_ERROR_NONE;
subchannel_call_ =
pick_.pick.connected_subchannel->CreateCall(call_args, &error);
subchannel_call_ = connected_subchannel_->CreateCall(call_args, &error);
if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
gpr_log(GPR_INFO, "chand=%p calld=%p: create subchannel_call=%p: error=%s",
chand, this, subchannel_call_.get(), grpc_error_string(error));
@ -3297,13 +3327,14 @@ void CallData::MaybeApplyServiceConfigToCallLocked(grpc_call_element* elem) {
}
}
const char* PickResultName(LoadBalancingPolicy::PickResult result) {
switch (result) {
case LoadBalancingPolicy::PICK_COMPLETE:
const char* PickResultTypeName(
LoadBalancingPolicy::PickResult::ResultType type) {
switch (type) {
case LoadBalancingPolicy::PickResult::PICK_COMPLETE:
return "COMPLETE";
case LoadBalancingPolicy::PICK_QUEUE:
case LoadBalancingPolicy::PickResult::PICK_QUEUE:
return "QUEUE";
case LoadBalancingPolicy::PICK_TRANSIENT_FAILURE:
case LoadBalancingPolicy::PickResult::PICK_TRANSIENT_FAILURE:
return "TRANSIENT_FAILURE";
}
GPR_UNREACHABLE_CODE(return "UNKNOWN");
@ -3313,8 +3344,10 @@ void CallData::StartPickLocked(void* arg, grpc_error* error) {
grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
CallData* calld = static_cast<CallData*>(elem->call_data);
ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
GPR_ASSERT(calld->pick_.pick.connected_subchannel == nullptr);
GPR_ASSERT(calld->connected_subchannel_ == nullptr);
GPR_ASSERT(calld->subchannel_call_ == nullptr);
// Apply service config to call if needed.
calld->MaybeApplyServiceConfigToCallLocked(elem);
// If this is a retry, use the send_initial_metadata payload that
// we've cached; otherwise, use the pending batch. The
// send_initial_metadata batch will be the first pending batch in the
@ -3325,58 +3358,58 @@ void CallData::StartPickLocked(void* arg, grpc_error* error) {
// allocate the subchannel batch earlier so that we can give the
// subchannel's copy of the metadata batch (which is copied for each
// attempt) to the LB policy instead the one from the parent channel.
calld->pick_.pick.initial_metadata =
LoadBalancingPolicy::PickArgs pick_args;
pick_args.call_state = &calld->lb_call_state_;
pick_args.initial_metadata =
calld->seen_send_initial_metadata_
? &calld->send_initial_metadata_
: calld->pending_batches_[0]
.batch->payload->send_initial_metadata.send_initial_metadata;
uint32_t* send_initial_metadata_flags =
// Grab initial metadata flags so that we can check later if the call has
// wait_for_ready enabled.
const uint32_t send_initial_metadata_flags =
calld->seen_send_initial_metadata_
? &calld->send_initial_metadata_flags_
: &calld->pending_batches_[0]
.batch->payload->send_initial_metadata
.send_initial_metadata_flags;
// Apply service config to call if needed.
calld->MaybeApplyServiceConfigToCallLocked(elem);
? calld->send_initial_metadata_flags_
: calld->pending_batches_[0]
.batch->payload->send_initial_metadata
.send_initial_metadata_flags;
// When done, we schedule this closure to leave the data plane combiner.
GRPC_CLOSURE_INIT(&calld->pick_closure_, PickDone, elem,
grpc_schedule_on_exec_ctx);
// Attempt pick.
error = GRPC_ERROR_NONE;
auto pick_result = chand->picker()->Pick(&calld->pick_.pick, &error);
auto result = chand->picker()->Pick(pick_args);
if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
gpr_log(GPR_INFO,
"chand=%p calld=%p: LB pick returned %s (connected_subchannel=%p, "
"error=%s)",
chand, calld, PickResultName(pick_result),
calld->pick_.pick.connected_subchannel.get(),
grpc_error_string(error));
chand, calld, PickResultTypeName(result.type),
result.connected_subchannel.get(), grpc_error_string(result.error));
}
switch (pick_result) {
case LoadBalancingPolicy::PICK_TRANSIENT_FAILURE: {
switch (result.type) {
case LoadBalancingPolicy::PickResult::PICK_TRANSIENT_FAILURE: {
// If we're shutting down, fail all RPCs.
grpc_error* disconnect_error = chand->disconnect_error();
if (disconnect_error != GRPC_ERROR_NONE) {
GRPC_ERROR_UNREF(error);
GRPC_ERROR_UNREF(result.error);
GRPC_CLOSURE_SCHED(&calld->pick_closure_,
GRPC_ERROR_REF(disconnect_error));
break;
}
// If wait_for_ready is false, then the error indicates the RPC
// attempt's final status.
if ((*send_initial_metadata_flags &
if ((send_initial_metadata_flags &
GRPC_INITIAL_METADATA_WAIT_FOR_READY) == 0) {
// Retry if appropriate; otherwise, fail.
grpc_status_code status = GRPC_STATUS_OK;
grpc_error_get_status(error, calld->deadline_, &status, nullptr,
grpc_error_get_status(result.error, calld->deadline_, &status, nullptr,
nullptr, nullptr);
if (!calld->enable_retries_ ||
!calld->MaybeRetry(elem, nullptr /* batch_data */, status,
nullptr /* server_pushback_md */)) {
grpc_error* new_error =
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Failed to pick subchannel", &error, 1);
GRPC_ERROR_UNREF(error);
"Failed to pick subchannel", &result.error, 1);
GRPC_ERROR_UNREF(result.error);
GRPC_CLOSURE_SCHED(&calld->pick_closure_, new_error);
}
if (calld->pick_queued_) calld->RemoveCallFromQueuedPicksLocked(elem);
@ -3384,19 +3417,24 @@ void CallData::StartPickLocked(void* arg, grpc_error* error) {
}
// If wait_for_ready is true, then queue to retry when we get a new
// picker.
GRPC_ERROR_UNREF(error);
GRPC_ERROR_UNREF(result.error);
}
// Fallthrough
case LoadBalancingPolicy::PICK_QUEUE:
case LoadBalancingPolicy::PickResult::PICK_QUEUE:
if (!calld->pick_queued_) calld->AddCallToQueuedPicksLocked(elem);
break;
default: // PICK_COMPLETE
// Handle drops.
if (GPR_UNLIKELY(calld->pick_.pick.connected_subchannel == nullptr)) {
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
if (GPR_UNLIKELY(result.connected_subchannel == nullptr)) {
result.error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Call dropped by load balancing policy");
}
GRPC_CLOSURE_SCHED(&calld->pick_closure_, error);
calld->connected_subchannel_ = std::move(result.connected_subchannel);
calld->lb_recv_trailing_metadata_ready_ =
result.recv_trailing_metadata_ready;
calld->lb_recv_trailing_metadata_ready_user_data_ =
result.recv_trailing_metadata_ready_user_data;
GRPC_CLOSURE_SCHED(&calld->pick_closure_, result.error);
if (calld->pick_queued_) calld->RemoveCallFromQueuedPicksLocked(elem);
}
}

@ -105,7 +105,7 @@ LoadBalancingPolicy::UpdateArgs& LoadBalancingPolicy::UpdateArgs::operator=(
//
LoadBalancingPolicy::PickResult LoadBalancingPolicy::QueuePicker::Pick(
PickArgs* pick, grpc_error** error) {
PickArgs args) {
// We invoke the parent's ExitIdleLocked() via a closure instead
// of doing it directly here, for two reasons:
// 1. ExitIdleLocked() may cause the policy's state to change and
@ -125,7 +125,9 @@ LoadBalancingPolicy::PickResult LoadBalancingPolicy::QueuePicker::Pick(
grpc_combiner_scheduler(parent_->combiner())),
GRPC_ERROR_NONE);
}
return PICK_QUEUE;
PickResult result;
result.type = PickResult::PICK_QUEUE;
return result;
}
void LoadBalancingPolicy::QueuePicker::CallExitIdle(void* arg,
@ -135,4 +137,16 @@ void LoadBalancingPolicy::QueuePicker::CallExitIdle(void* arg,
parent->Unref();
}
//
// LoadBalancingPolicy::TransientFailurePicker
//
LoadBalancingPolicy::PickResult
LoadBalancingPolicy::TransientFailurePicker::Pick(PickArgs args) {
PickResult result;
result.type = PickResult::PICK_TRANSIENT_FAILURE;
result.error = GRPC_ERROR_REF(error_);
return result;
}
} // namespace grpc_core

@ -32,21 +32,9 @@
#include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/transport/connectivity_state.h"
extern grpc_core::DebugOnlyTraceFlag grpc_trace_lb_policy_refcount;
namespace grpc_core {
/// Interface for parsed forms of load balancing configs found in a service
/// config.
class ParsedLoadBalancingConfig : public RefCounted<ParsedLoadBalancingConfig> {
public:
virtual ~ParsedLoadBalancingConfig() = default;
// Returns the load balancing policy name
virtual const char* name() const GRPC_ABSTRACT;
GRPC_ABSTRACT_BASE_CLASS;
};
extern DebugOnlyTraceFlag grpc_trace_lb_policy_refcount;
/// Interface for load balancing policies.
///
@ -89,66 +77,77 @@ class ParsedLoadBalancingConfig : public RefCounted<ParsedLoadBalancingConfig> {
// interested_parties() hooks from the API.
class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
public:
/// Interface for accessing per-call state.
class CallState {
public:
CallState() = default;
virtual ~CallState() = default;
/// Allocates memory associated with the call, which will be
/// automatically freed when the call is complete.
/// It is more efficient to use this than to allocate memory directly
/// for allocations that need to be made on a per-call basis.
virtual void* Alloc(size_t size) GRPC_ABSTRACT;
GRPC_ABSTRACT_BASE_CLASS
};
/// Arguments used when picking a subchannel for an RPC.
struct PickArgs {
///
/// Input parameters.
///
/// Initial metadata associated with the picking call.
/// The LB policy may use the existing metadata to influence its routing
/// decision, and it may add new metadata elements to be sent with the
/// call to the chosen backend.
// TODO(roth): Provide a more generic metadata API here.
grpc_metadata_batch* initial_metadata = nullptr;
/// Storage for LB token in \a initial_metadata, or nullptr if not used.
// TODO(roth): Remove this from the API. Maybe have the LB policy
// allocate this on the arena instead?
grpc_linked_mdelem lb_token_mdelem_storage;
///
/// Output parameters.
///
/// Will be set to the selected subchannel, or nullptr on failure or when
/// the LB policy decides to drop the call.
RefCountedPtr<ConnectedSubchannel> connected_subchannel;
/// Callback set by lb policy to be notified of trailing metadata.
/// The callback must be scheduled on grpc_schedule_on_exec_ctx.
// TODO(roth): Provide a cleaner callback API.
grpc_closure* recv_trailing_metadata_ready = nullptr;
/// The address that will be set to point to the original
/// recv_trailing_metadata_ready callback, to be invoked by the LB
/// policy's recv_trailing_metadata_ready callback when complete.
/// Must be non-null if recv_trailing_metadata_ready is non-null.
// TODO(roth): Consider making the recv_trailing_metadata closure a
// synchronous callback, in which case it is not responsible for
// chaining to the next callback, so this can be removed from the API.
grpc_closure** original_recv_trailing_metadata_ready = nullptr;
/// If this is not nullptr, then the client channel will point it to the
/// call's trailing metadata before invoking recv_trailing_metadata_ready.
/// If this is nullptr, then the callback will still be called.
/// The lb does not have ownership of the metadata.
// TODO(roth): If we make this a synchronous callback, then this can
// be passed to the callback as a parameter and can be removed from
// the API here.
grpc_metadata_batch** recv_trailing_metadata = nullptr;
/// An interface for accessing call state. Can be used to allocate
/// data associated with the call in an efficient way.
CallState* call_state;
};
/// The result of picking a subchannel for an RPC.
enum PickResult {
// Pick complete. If connected_subchannel is non-null, client channel
// can immediately proceed with the call on connected_subchannel;
// otherwise, call should be dropped.
PICK_COMPLETE,
// Pick cannot be completed until something changes on the control
// plane. Client channel will queue the pick and try again the
// next time the picker is updated.
PICK_QUEUE,
// LB policy is in transient failure. If the pick is wait_for_ready,
// client channel will wait for the next picker and try again;
// otherwise, the call will be failed immediately (although it may
// be retried if the client channel is configured to do so).
// The Pick() method will set its error parameter if this value is
// returned.
PICK_TRANSIENT_FAILURE,
struct PickResult {
enum ResultType {
/// Pick complete. If connected_subchannel is non-null, client channel
/// can immediately proceed with the call on connected_subchannel;
/// otherwise, call should be dropped.
PICK_COMPLETE,
/// Pick cannot be completed until something changes on the control
/// plane. Client channel will queue the pick and try again the
/// next time the picker is updated.
PICK_QUEUE,
/// LB policy is in transient failure. If the pick is wait_for_ready,
/// client channel will wait for the next picker and try again;
/// otherwise, the call will be failed immediately (although it may
/// be retried if the client channel is configured to do so).
/// The Pick() method will set its error parameter if this value is
/// returned.
PICK_TRANSIENT_FAILURE,
};
ResultType type;
/// Used only if type is PICK_COMPLETE. Will be set to the selected
/// subchannel, or nullptr if the LB policy decides to drop the call.
RefCountedPtr<ConnectedSubchannel> connected_subchannel;
/// Used only if type is PICK_TRANSIENT_FAILURE.
/// Error to be set when returning a transient failure.
// TODO(roth): Replace this with something similar to grpc::Status,
// so that we don't expose grpc_error to this API.
grpc_error* error = GRPC_ERROR_NONE;
/// Used only if type is PICK_COMPLETE.
/// Callback set by lb policy to be notified of trailing metadata.
/// The user_data argument will be set to the
/// recv_trailing_metadata_ready_user_data field.
/// recv_trailing_metadata will be set to the metadata, which may be
/// modified by the callback. The callback does not take ownership,
/// however, so any data that needs to be used after returning must
/// be copied.
void (*recv_trailing_metadata_ready)(
void* user_data, grpc_metadata_batch* recv_trailing_metadata,
CallState* call_state) = nullptr;
void* recv_trailing_metadata_ready_user_data = nullptr;
};
/// A subchannel picker is the object used to pick the subchannel to
@ -162,17 +161,14 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
/// live in the LB policy object itself.
///
/// Currently, pickers are always accessed from within the
/// client_channel combiner, so they do not have to be thread-safe.
// TODO(roth): In a subsequent PR, split the data plane work (i.e.,
// the interaction with the picker) and the control plane work (i.e.,
// the interaction with the LB policy) into two different
// synchronization mechanisms, to avoid lock contention between the two.
/// client_channel data plane combiner, so they do not have to be
/// thread-safe.
class SubchannelPicker {
public:
SubchannelPicker() = default;
virtual ~SubchannelPicker() = default;
virtual PickResult Pick(PickArgs* pick, grpc_error** error) GRPC_ABSTRACT;
virtual PickResult Pick(PickArgs args) GRPC_ABSTRACT;
GRPC_ABSTRACT_BASE_CLASS
};
@ -208,11 +204,24 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
GRPC_ABSTRACT_BASE_CLASS
};
/// Interface for configuration data used by an LB policy implementation.
/// Individual implementations will create a subclass that adds methods to
/// return the parameters they need.
class Config : public RefCounted<Config> {
public:
virtual ~Config() = default;
// Returns the load balancing policy name
virtual const char* name() const GRPC_ABSTRACT;
GRPC_ABSTRACT_BASE_CLASS
};
/// Data passed to the UpdateLocked() method when new addresses and
/// config are available.
struct UpdateArgs {
ServerAddressList addresses;
RefCountedPtr<ParsedLoadBalancingConfig> config;
RefCountedPtr<Config> config;
const grpc_channel_args* args = nullptr;
// TODO(roth): Remove everything below once channel args is
@ -291,7 +300,7 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
explicit QueuePicker(RefCountedPtr<LoadBalancingPolicy> parent)
: parent_(std::move(parent)) {}
PickResult Pick(PickArgs* pick, grpc_error** error) override;
PickResult Pick(PickArgs args) override;
private:
static void CallExitIdle(void* arg, grpc_error* error);
@ -306,10 +315,7 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
explicit TransientFailurePicker(grpc_error* error) : error_(error) {}
~TransientFailurePicker() override { GRPC_ERROR_UNREF(error_); }
PickResult Pick(PickArgs* pick, grpc_error** error) override {
*error = GRPC_ERROR_REF(error_);
return PICK_TRANSIENT_FAILURE;
}
PickResult Pick(PickArgs args) override;
private:
grpc_error* error_;

@ -118,19 +118,19 @@ namespace {
constexpr char kGrpclb[] = "grpclb";
class ParsedGrpcLbConfig : public ParsedLoadBalancingConfig {
class ParsedGrpcLbConfig : public LoadBalancingPolicy::Config {
public:
explicit ParsedGrpcLbConfig(
RefCountedPtr<ParsedLoadBalancingConfig> child_policy)
RefCountedPtr<LoadBalancingPolicy::Config> child_policy)
: child_policy_(std::move(child_policy)) {}
const char* name() const override { return kGrpclb; }
RefCountedPtr<ParsedLoadBalancingConfig> child_policy() const {
RefCountedPtr<LoadBalancingPolicy::Config> child_policy() const {
return child_policy_;
}
private:
RefCountedPtr<ParsedLoadBalancingConfig> child_policy_;
RefCountedPtr<LoadBalancingPolicy::Config> child_policy_;
};
class GrpcLb : public LoadBalancingPolicy {
@ -274,7 +274,7 @@ class GrpcLb : public LoadBalancingPolicy {
child_picker_(std::move(child_picker)),
client_stats_(std::move(client_stats)) {}
PickResult Pick(PickArgs* pick, grpc_error** error) override;
PickResult Pick(PickArgs args) override;
private:
// Storing the address for logging, but not holding a ref.
@ -394,7 +394,7 @@ class GrpcLb : public LoadBalancingPolicy {
// until it reports READY, at which point it will be moved to child_policy_.
OrphanablePtr<LoadBalancingPolicy> pending_child_policy_;
// The child policy config.
RefCountedPtr<ParsedLoadBalancingConfig> child_policy_config_;
RefCountedPtr<LoadBalancingPolicy::Config> child_policy_config_;
// Child policy in state READY.
bool child_policy_ready_ = false;
};
@ -561,7 +561,8 @@ const char* GrpcLb::Serverlist::ShouldDrop() {
// GrpcLb::Picker
//
GrpcLb::PickResult GrpcLb::Picker::Pick(PickArgs* pick, grpc_error** error) {
GrpcLb::PickResult GrpcLb::Picker::Pick(PickArgs args) {
PickResult result;
// Check if we should drop the call.
const char* drop_token = serverlist_->ShouldDrop();
if (drop_token != nullptr) {
@ -573,26 +574,28 @@ GrpcLb::PickResult GrpcLb::Picker::Pick(PickArgs* pick, grpc_error** error) {
if (client_stats_ != nullptr) {
client_stats_->AddCallDropped(drop_token);
}
return PICK_COMPLETE;
result.type = PickResult::PICK_COMPLETE;
return result;
}
// Forward pick to child policy.
PickResult result = child_picker_->Pick(pick, error);
result = child_picker_->Pick(args);
// If pick succeeded, add LB token to initial metadata.
if (result == PickResult::PICK_COMPLETE &&
pick->connected_subchannel != nullptr) {
if (result.type == PickResult::PICK_COMPLETE &&
result.connected_subchannel != nullptr) {
const grpc_arg* arg = grpc_channel_args_find(
pick->connected_subchannel->args(), GRPC_ARG_GRPCLB_ADDRESS_LB_TOKEN);
result.connected_subchannel->args(), GRPC_ARG_GRPCLB_ADDRESS_LB_TOKEN);
if (arg == nullptr) {
gpr_log(GPR_ERROR,
"[grpclb %p picker %p] No LB token for connected subchannel "
"pick %p",
parent_, this, pick);
"[grpclb %p picker %p] No LB token for connected subchannel %p",
parent_, this, result.connected_subchannel.get());
abort();
}
grpc_mdelem lb_token = {reinterpret_cast<uintptr_t>(arg->value.pointer.p)};
GPR_ASSERT(!GRPC_MDISNULL(lb_token));
grpc_linked_mdelem* mdelem_storage = static_cast<grpc_linked_mdelem*>(
args.call_state->Alloc(sizeof(grpc_linked_mdelem)));
GPR_ASSERT(grpc_metadata_batch_add_tail(
pick->initial_metadata, &pick->lb_token_mdelem_storage,
args.initial_metadata, mdelem_storage,
GRPC_MDELEM_REF(lb_token)) == GRPC_ERROR_NONE);
GrpcLbClientStats* client_stats = static_cast<GrpcLbClientStats*>(
grpc_mdelem_get_user_data(lb_token, GrpcLbClientStats::Destroy));
@ -1800,15 +1803,15 @@ class GrpcLbFactory : public LoadBalancingPolicyFactory {
const char* name() const override { return kGrpclb; }
RefCountedPtr<ParsedLoadBalancingConfig> ParseLoadBalancingConfig(
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
const grpc_json* json, grpc_error** error) const override {
GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
if (json == nullptr) {
return RefCountedPtr<ParsedLoadBalancingConfig>(
return RefCountedPtr<LoadBalancingPolicy::Config>(
New<ParsedGrpcLbConfig>(nullptr));
}
InlinedVector<grpc_error*, 2> error_list;
RefCountedPtr<ParsedLoadBalancingConfig> child_policy;
RefCountedPtr<LoadBalancingPolicy::Config> child_policy;
for (const grpc_json* field = json->child; field != nullptr;
field = field->next) {
if (field->key == nullptr) continue;
@ -1826,7 +1829,7 @@ class GrpcLbFactory : public LoadBalancingPolicyFactory {
}
}
if (error_list.empty()) {
return RefCountedPtr<ParsedLoadBalancingConfig>(
return RefCountedPtr<LoadBalancingPolicy::Config>(
New<ParsedGrpcLbConfig>(std::move(child_policy)));
} else {
*error = GRPC_ERROR_CREATE_FROM_VECTOR("GrpcLb Parser", &error_list);

@ -115,9 +115,11 @@ class PickFirst : public LoadBalancingPolicy {
explicit Picker(RefCountedPtr<ConnectedSubchannel> connected_subchannel)
: connected_subchannel_(std::move(connected_subchannel)) {}
PickResult Pick(PickArgs* pick, grpc_error** error) override {
pick->connected_subchannel = connected_subchannel_;
return PICK_COMPLETE;
PickResult Pick(PickArgs args) override {
PickResult result;
result.type = PickResult::PICK_COMPLETE;
result.connected_subchannel = connected_subchannel_;
return result;
}
private:
@ -527,7 +529,7 @@ void PickFirst::PickFirstSubchannelData::
}
}
class ParsedPickFirstConfig : public ParsedLoadBalancingConfig {
class ParsedPickFirstConfig : public LoadBalancingPolicy::Config {
public:
const char* name() const override { return kPickFirst; }
};
@ -545,12 +547,12 @@ class PickFirstFactory : public LoadBalancingPolicyFactory {
const char* name() const override { return kPickFirst; }
RefCountedPtr<ParsedLoadBalancingConfig> ParseLoadBalancingConfig(
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
const grpc_json* json, grpc_error** error) const override {
if (json != nullptr) {
GPR_DEBUG_ASSERT(strcmp(json->key, name()) == 0);
}
return RefCountedPtr<ParsedLoadBalancingConfig>(
return RefCountedPtr<LoadBalancingPolicy::Config>(
New<ParsedPickFirstConfig>());
}
};

@ -149,7 +149,7 @@ class RoundRobin : public LoadBalancingPolicy {
public:
Picker(RoundRobin* parent, RoundRobinSubchannelList* subchannel_list);
PickResult Pick(PickArgs* pick, grpc_error** error) override;
PickResult Pick(PickArgs args) override;
private:
// Using pointer value only, no ref held -- do not dereference!
@ -220,8 +220,7 @@ RoundRobin::Picker::Picker(RoundRobin* parent,
}
}
RoundRobin::PickResult RoundRobin::Picker::Pick(PickArgs* pick,
grpc_error** error) {
RoundRobin::PickResult RoundRobin::Picker::Pick(PickArgs args) {
last_picked_index_ = (last_picked_index_ + 1) % subchannels_.size();
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_round_robin_trace)) {
gpr_log(GPR_INFO,
@ -230,8 +229,10 @@ RoundRobin::PickResult RoundRobin::Picker::Pick(PickArgs* pick,
parent_, this, last_picked_index_,
subchannels_[last_picked_index_].get());
}
pick->connected_subchannel = subchannels_[last_picked_index_];
return PICK_COMPLETE;
PickResult result;
result.type = PickResult::PICK_COMPLETE;
result.connected_subchannel = subchannels_[last_picked_index_];
return result;
}
//
@ -503,7 +504,7 @@ void RoundRobin::UpdateLocked(UpdateArgs args) {
}
}
class ParsedRoundRobinConfig : public ParsedLoadBalancingConfig {
class ParsedRoundRobinConfig : public LoadBalancingPolicy::Config {
public:
const char* name() const override { return kRoundRobin; }
};
@ -521,12 +522,12 @@ class RoundRobinFactory : public LoadBalancingPolicyFactory {
const char* name() const override { return kRoundRobin; }
RefCountedPtr<ParsedLoadBalancingConfig> ParseLoadBalancingConfig(
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
const grpc_json* json, grpc_error** error) const override {
if (json != nullptr) {
GPR_DEBUG_ASSERT(strcmp(json->key, name()) == 0);
}
return RefCountedPtr<ParsedLoadBalancingConfig>(
return RefCountedPtr<LoadBalancingPolicy::Config>(
New<ParsedRoundRobinConfig>());
}
};

@ -120,11 +120,11 @@ constexpr char kXds[] = "xds_experimental";
constexpr char kDefaultLocalityName[] = "xds_default_locality";
constexpr uint32_t kDefaultLocalityWeight = 3;
class ParsedXdsConfig : public ParsedLoadBalancingConfig {
class ParsedXdsConfig : public LoadBalancingPolicy::Config {
public:
ParsedXdsConfig(const char* balancer_name,
RefCountedPtr<ParsedLoadBalancingConfig> child_policy,
RefCountedPtr<ParsedLoadBalancingConfig> fallback_policy)
RefCountedPtr<LoadBalancingPolicy::Config> child_policy,
RefCountedPtr<LoadBalancingPolicy::Config> fallback_policy)
: balancer_name_(balancer_name),
child_policy_(std::move(child_policy)),
fallback_policy_(std::move(fallback_policy)) {}
@ -133,18 +133,18 @@ class ParsedXdsConfig : public ParsedLoadBalancingConfig {
const char* balancer_name() const { return balancer_name_; };
RefCountedPtr<ParsedLoadBalancingConfig> child_policy() const {
RefCountedPtr<LoadBalancingPolicy::Config> child_policy() const {
return child_policy_;
}
RefCountedPtr<ParsedLoadBalancingConfig> fallback_policy() const {
RefCountedPtr<LoadBalancingPolicy::Config> fallback_policy() const {
return fallback_policy_;
}
private:
const char* balancer_name_ = nullptr;
RefCountedPtr<ParsedLoadBalancingConfig> child_policy_;
RefCountedPtr<ParsedLoadBalancingConfig> fallback_policy_;
RefCountedPtr<LoadBalancingPolicy::Config> child_policy_;
RefCountedPtr<LoadBalancingPolicy::Config> fallback_policy_;
};
class XdsLb : public LoadBalancingPolicy {
@ -300,9 +300,7 @@ class XdsLb : public LoadBalancingPolicy {
public:
explicit PickerRef(UniquePtr<SubchannelPicker> picker)
: picker_(std::move(picker)) {}
PickResult Pick(PickArgs* pick, grpc_error** error) {
return picker_->Pick(pick, error);
}
PickResult Pick(PickArgs args) { return picker_->Pick(args); }
private:
UniquePtr<SubchannelPicker> picker_;
@ -322,12 +320,11 @@ class XdsLb : public LoadBalancingPolicy {
: client_stats_(std::move(client_stats)),
pickers_(std::move(pickers)) {}
PickResult Pick(PickArgs* pick, grpc_error** error) override;
PickResult Pick(PickArgs args) override;
private:
// Calls the picker of the locality that the key falls within
PickResult PickFromLocality(const uint32_t key, PickArgs* pick,
grpc_error** error);
PickResult PickFromLocality(const uint32_t key, PickArgs args);
RefCountedPtr<XdsLbClientStats> client_stats_;
PickerList pickers_;
};
@ -363,7 +360,7 @@ class XdsLb : public LoadBalancingPolicy {
~LocalityEntry() = default;
void UpdateLocked(xds_grpclb_serverlist* serverlist,
ParsedLoadBalancingConfig* child_policy_config,
LoadBalancingPolicy::Config* child_policy_config,
const grpc_channel_args* args);
void ShutdownLocked();
void ResetBackoffLocked();
@ -410,7 +407,7 @@ class XdsLb : public LoadBalancingPolicy {
};
void UpdateLocked(const LocalityList& locality_list,
ParsedLoadBalancingConfig* child_policy_config,
LoadBalancingPolicy::Config* child_policy_config,
const grpc_channel_args* args, XdsLb* parent);
void ShutdownLocked();
void ResetBackoffLocked();
@ -506,7 +503,7 @@ class XdsLb : public LoadBalancingPolicy {
grpc_closure lb_on_fallback_;
// The policy to use for the fallback backends.
RefCountedPtr<ParsedLoadBalancingConfig> fallback_policy_config_;
RefCountedPtr<LoadBalancingPolicy::Config> fallback_policy_config_;
// Lock held when modifying the value of fallback_policy_ or
// pending_fallback_policy_.
Mutex fallback_policy_mu_;
@ -515,7 +512,7 @@ class XdsLb : public LoadBalancingPolicy {
OrphanablePtr<LoadBalancingPolicy> pending_fallback_policy_;
// The policy to use for the backends.
RefCountedPtr<ParsedLoadBalancingConfig> child_policy_config_;
RefCountedPtr<LoadBalancingPolicy::Config> child_policy_config_;
// Map of policies to use in the backend
LocalityMap locality_map_;
// TODO(mhaidry) : Add support for multiple maps of localities
@ -530,25 +527,24 @@ class XdsLb : public LoadBalancingPolicy {
// XdsLb::Picker
//
XdsLb::PickResult XdsLb::Picker::Pick(PickArgs* pick, grpc_error** error) {
XdsLb::PickResult XdsLb::Picker::Pick(PickArgs args) {
// TODO(roth): Add support for drop handling.
// Generate a random number between 0 and the total weight
const uint32_t key =
(rand() * pickers_[pickers_.size() - 1].first) / RAND_MAX;
// Forward pick to whichever locality maps to the range in which the
// random number falls in.
PickResult result = PickFromLocality(key, pick, error);
PickResult result = PickFromLocality(key, args);
// If pick succeeded, add client stats.
if (result == PickResult::PICK_COMPLETE &&
pick->connected_subchannel != nullptr && client_stats_ != nullptr) {
if (result.type == PickResult::PICK_COMPLETE &&
result.connected_subchannel != nullptr && client_stats_ != nullptr) {
// TODO(roth): Add support for client stats.
}
return result;
}
XdsLb::PickResult XdsLb::Picker::PickFromLocality(const uint32_t key,
PickArgs* pick,
grpc_error** error) {
PickArgs args) {
size_t mid = 0;
size_t start_index = 0;
size_t end_index = pickers_.size() - 1;
@ -566,7 +562,7 @@ XdsLb::PickResult XdsLb::Picker::PickFromLocality(const uint32_t key,
}
if (index == 0) index = start_index;
GPR_ASSERT(pickers_[index].first > key);
return pickers_[index].second->Pick(pick, error);
return pickers_[index].second->Pick(args);
}
//
@ -1744,7 +1740,7 @@ void XdsLb::LocalityMap::PruneLocalities(const LocalityList& locality_list) {
void XdsLb::LocalityMap::UpdateLocked(
const LocalityList& locality_serverlist,
ParsedLoadBalancingConfig* child_policy_config,
LoadBalancingPolicy::Config* child_policy_config,
const grpc_channel_args* args, XdsLb* parent) {
if (parent->shutting_down_) return;
for (size_t i = 0; i < locality_serverlist.size(); i++) {
@ -1839,7 +1835,7 @@ XdsLb::LocalityMap::LocalityEntry::CreateChildPolicyLocked(
void XdsLb::LocalityMap::LocalityEntry::UpdateLocked(
xds_grpclb_serverlist* serverlist,
ParsedLoadBalancingConfig* child_policy_config,
LoadBalancingPolicy::Config* child_policy_config,
const grpc_channel_args* args_in) {
if (parent_->shutting_down_) return;
// Construct update args.
@ -2158,7 +2154,7 @@ class XdsFactory : public LoadBalancingPolicyFactory {
const char* name() const override { return kXds; }
RefCountedPtr<ParsedLoadBalancingConfig> ParseLoadBalancingConfig(
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
const grpc_json* json, grpc_error** error) const override {
GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
if (json == nullptr) {
@ -2174,8 +2170,8 @@ class XdsFactory : public LoadBalancingPolicyFactory {
InlinedVector<grpc_error*, 3> error_list;
const char* balancer_name = nullptr;
RefCountedPtr<ParsedLoadBalancingConfig> child_policy;
RefCountedPtr<ParsedLoadBalancingConfig> fallback_policy;
RefCountedPtr<LoadBalancingPolicy::Config> child_policy;
RefCountedPtr<LoadBalancingPolicy::Config> fallback_policy;
for (const grpc_json* field = json->child; field != nullptr;
field = field->next) {
if (field->key == nullptr) continue;
@ -2221,7 +2217,7 @@ class XdsFactory : public LoadBalancingPolicyFactory {
"field:balancerName error:not found"));
}
if (error_list.empty()) {
return RefCountedPtr<ParsedLoadBalancingConfig>(New<ParsedXdsConfig>(
return RefCountedPtr<LoadBalancingPolicy::Config>(New<ParsedXdsConfig>(
balancer_name, std::move(child_policy), std::move(fallback_policy)));
} else {
*error = GRPC_ERROR_CREATE_FROM_VECTOR("Xds Parser", &error_list);

@ -37,7 +37,7 @@ class LoadBalancingPolicyFactory {
/// Caller does NOT take ownership of result.
virtual const char* name() const GRPC_ABSTRACT;
virtual RefCountedPtr<ParsedLoadBalancingConfig> ParseLoadBalancingConfig(
virtual RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
const grpc_json* json, grpc_error** error) const GRPC_ABSTRACT;
virtual ~LoadBalancingPolicyFactory() {}

@ -176,7 +176,7 @@ grpc_json* ParseLoadBalancingConfigHelper(const grpc_json* lb_config_array,
}
} // namespace
RefCountedPtr<ParsedLoadBalancingConfig>
RefCountedPtr<LoadBalancingPolicy::Config>
LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(const grpc_json* json,
grpc_error** error) {
GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);

@ -56,7 +56,7 @@ class LoadBalancingPolicyRegistry {
/// Returns a parsed object of the load balancing policy to be used from a
/// LoadBalancingConfig array \a json.
static RefCountedPtr<ParsedLoadBalancingConfig> ParseLoadBalancingConfig(
static RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
const grpc_json* json, grpc_error** error);
};

@ -268,7 +268,7 @@ ClientChannelServiceConfigParser::ParseGlobalParams(const grpc_json* json,
grpc_error** error) {
GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
InlinedVector<grpc_error*, 4> error_list;
RefCountedPtr<ParsedLoadBalancingConfig> parsed_lb_config;
RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config;
UniquePtr<char> lb_policy_name;
Optional<ClientChannelGlobalParsedConfig::RetryThrottling> retry_throttling;
const char* health_check_service_name = nullptr;

@ -45,7 +45,7 @@ class ClientChannelGlobalParsedConfig : public ServiceConfig::ParsedConfig {
};
ClientChannelGlobalParsedConfig(
RefCountedPtr<ParsedLoadBalancingConfig> parsed_lb_config,
RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config,
UniquePtr<char> parsed_deprecated_lb_policy,
const Optional<RetryThrottling>& retry_throttling,
const char* health_check_service_name)
@ -58,7 +58,7 @@ class ClientChannelGlobalParsedConfig : public ServiceConfig::ParsedConfig {
return retry_throttling_;
}
RefCountedPtr<ParsedLoadBalancingConfig> parsed_lb_config() const {
RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config() const {
return parsed_lb_config_;
}
@ -71,7 +71,7 @@ class ClientChannelGlobalParsedConfig : public ServiceConfig::ParsedConfig {
}
private:
RefCountedPtr<ParsedLoadBalancingConfig> parsed_lb_config_;
RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config_;
UniquePtr<char> parsed_deprecated_lb_policy_;
Optional<RetryThrottling> retry_throttling_;
const char* health_check_service_name_;

@ -184,7 +184,7 @@ class ResolvingLoadBalancingPolicy::ResolvingControlHelper
ResolvingLoadBalancingPolicy::ResolvingLoadBalancingPolicy(
Args args, TraceFlag* tracer, UniquePtr<char> target_uri,
UniquePtr<char> child_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig> child_lb_config,
RefCountedPtr<LoadBalancingPolicy::Config> child_lb_config,
grpc_error** error)
: LoadBalancingPolicy(std::move(args)),
tracer_(tracer),
@ -333,7 +333,7 @@ void ResolvingLoadBalancingPolicy::OnResolverError(grpc_error* error) {
void ResolvingLoadBalancingPolicy::CreateOrUpdateLbPolicyLocked(
const char* lb_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig> lb_policy_config,
RefCountedPtr<LoadBalancingPolicy::Config> lb_policy_config,
Resolver::Result result, TraceStringVector* trace_strings) {
// If the child policy name changes, we need to create a new child
// policy. When this happens, we leave child_policy_ as-is and store
@ -530,7 +530,7 @@ void ResolvingLoadBalancingPolicy::OnResolverResultChangedLocked(
const bool resolution_contains_addresses = result.addresses.size() > 0;
// Process the resolver result.
const char* lb_policy_name = nullptr;
RefCountedPtr<ParsedLoadBalancingConfig> lb_policy_config;
RefCountedPtr<LoadBalancingPolicy::Config> lb_policy_config;
bool service_config_changed = false;
char* service_config_error_string = nullptr;
if (process_resolver_result_ != nullptr) {

@ -57,7 +57,7 @@ class ResolvingLoadBalancingPolicy : public LoadBalancingPolicy {
ResolvingLoadBalancingPolicy(
Args args, TraceFlag* tracer, UniquePtr<char> target_uri,
UniquePtr<char> child_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig> child_lb_config,
RefCountedPtr<LoadBalancingPolicy::Config> child_lb_config,
grpc_error** error);
// Private ctor, to be used by client_channel only!
@ -70,7 +70,7 @@ class ResolvingLoadBalancingPolicy : public LoadBalancingPolicy {
// should set the channel to be in TRANSIENT_FAILURE.
typedef bool (*ProcessResolverResultCallback)(
void* user_data, Resolver::Result* result, const char** lb_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig>* lb_policy_config,
RefCountedPtr<LoadBalancingPolicy::Config>* lb_policy_config,
grpc_error** service_config_error);
// If error is set when this returns, then construction failed, and
// the caller may not use the new object.
@ -109,7 +109,7 @@ class ResolvingLoadBalancingPolicy : public LoadBalancingPolicy {
void OnResolverError(grpc_error* error);
void CreateOrUpdateLbPolicyLocked(
const char* lb_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig> lb_policy_config,
RefCountedPtr<LoadBalancingPolicy::Config> lb_policy_config,
Resolver::Result result, TraceStringVector* trace_strings);
OrphanablePtr<LoadBalancingPolicy> CreateLbPolicyLocked(
const char* lb_policy_name, const grpc_channel_args& args,
@ -126,7 +126,7 @@ class ResolvingLoadBalancingPolicy : public LoadBalancingPolicy {
ProcessResolverResultCallback process_resolver_result_ = nullptr;
void* process_resolver_result_user_data_ = nullptr;
UniquePtr<char> child_policy_name_;
RefCountedPtr<ParsedLoadBalancingConfig> child_lb_config_;
RefCountedPtr<LoadBalancingPolicy::Config> child_lb_config_;
// Resolver and associated state.
OrphanablePtr<Resolver> resolver_;

@ -37,6 +37,7 @@
#include "src/core/lib/debug/stats.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/surface/validate_metadata.h"
#include "src/core/lib/transport/metadata.h"
#include "src/core/lib/transport/static_metadata.h"
#include "src/core/lib/transport/timeout_encoding.h"
@ -56,7 +57,10 @@
/* don't consider adding anything bigger than this to the hpack table */
#define MAX_DECODER_SPACE_USAGE 512
static grpc_slice_refcount terminal_slice_refcount;
#define DATA_FRAME_HEADER_SIZE 9
static grpc_slice_refcount terminal_slice_refcount(
grpc_slice_refcount::Type::STATIC);
static const grpc_slice terminal_slice = {
&terminal_slice_refcount, /* refcount */
{{0, nullptr}} /* data.refcounted */
@ -80,7 +84,8 @@ typedef struct {
bool use_true_binary_metadata;
} framer_state;
/* fills p (which is expected to be 9 bytes long) with a data frame header */
/* fills p (which is expected to be DATA_FRAME_HEADER_SIZE bytes long)
* with a data frame header */
static void fill_header(uint8_t* p, uint8_t type, uint32_t id, size_t len,
uint8_t flags) {
GPR_ASSERT(len < 16777316);
@ -107,15 +112,17 @@ static void finish_frame(framer_state* st, int is_header_boundary,
static_cast<uint8_t>(
(is_last_in_stream ? GRPC_CHTTP2_DATA_FLAG_END_STREAM : 0) |
(is_header_boundary ? GRPC_CHTTP2_DATA_FLAG_END_HEADERS : 0)));
st->stats->framing_bytes += 9;
st->stats->framing_bytes += DATA_FRAME_HEADER_SIZE;
st->is_first_frame = 0;
}
/* begin a new frame: reserve off header space, remember how many bytes we'd
output before beginning */
static void begin_frame(framer_state* st) {
st->header_idx =
grpc_slice_buffer_add_indexed(st->output, GRPC_SLICE_MALLOC(9));
grpc_slice reserved;
reserved.refcount = nullptr;
reserved.data.inlined.length = DATA_FRAME_HEADER_SIZE;
st->header_idx = grpc_slice_buffer_add_indexed(st->output, reserved);
st->output_length_at_start_of_frame = st->output->length;
}
@ -188,8 +195,9 @@ static void evict_entry(grpc_chttp2_hpack_compressor* c) {
static uint32_t prepare_space_for_new_elem(grpc_chttp2_hpack_compressor* c,
size_t elem_size) {
uint32_t new_index = c->tail_remote_index + c->table_elems + 1;
GPR_ASSERT(elem_size < 65536);
GPR_DEBUG_ASSERT(elem_size < 65536);
// TODO(arjunroy): Re-examine semantics
if (elem_size > c->max_table_size) {
while (c->table_size > 0) {
evict_entry(c);
@ -203,6 +211,7 @@ static uint32_t prepare_space_for_new_elem(grpc_chttp2_hpack_compressor* c,
while (c->table_size + elem_size > c->max_table_size) {
evict_entry(c);
}
// TODO(arjunroy): Are we conflating size in bytes vs. membership?
GPR_ASSERT(c->table_elems < c->max_table_size);
c->table_elem_size[new_index % c->cap_table_elems] =
static_cast<uint16_t>(elem_size);
@ -215,19 +224,19 @@ static uint32_t prepare_space_for_new_elem(grpc_chttp2_hpack_compressor* c,
// Add a key to the dynamic table. Both key and value will be added to table at
// the decoder.
static void add_key_with_index(grpc_chttp2_hpack_compressor* c,
grpc_mdelem elem, uint32_t new_index) {
grpc_mdelem elem, uint32_t new_index,
uint32_t key_hash) {
if (new_index == 0) {
return;
}
uint32_t key_hash = grpc_slice_hash(GRPC_MDKEY(elem));
/* Store the key into {entries,indices}_keys */
if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_2(key_hash)],
GRPC_MDKEY(elem))) {
if (grpc_slice_static_interned_equal(
c->entries_keys[HASH_FRAGMENT_2(key_hash)], GRPC_MDKEY(elem))) {
c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index;
} else if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_3(key_hash)],
GRPC_MDKEY(elem))) {
} else if (grpc_slice_static_interned_equal(
c->entries_keys[HASH_FRAGMENT_3(key_hash)],
GRPC_MDKEY(elem))) {
c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
} else if (c->entries_keys[HASH_FRAGMENT_2(key_hash)].refcount ==
&terminal_slice_refcount) {
@ -255,22 +264,20 @@ static void add_key_with_index(grpc_chttp2_hpack_compressor* c,
/* add an element to the decoder table */
static void add_elem_with_index(grpc_chttp2_hpack_compressor* c,
grpc_mdelem elem, uint32_t new_index) {
grpc_mdelem elem, uint32_t new_index,
uint32_t elem_hash, uint32_t key_hash) {
if (new_index == 0) {
return;
}
GPR_ASSERT(GRPC_MDELEM_IS_INTERNED(elem));
uint32_t key_hash = grpc_slice_hash(GRPC_MDKEY(elem));
uint32_t value_hash = grpc_slice_hash(GRPC_MDVALUE(elem));
uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, value_hash);
GPR_DEBUG_ASSERT(GRPC_MDELEM_IS_INTERNED(elem));
/* Store this element into {entries,indices}_elem */
if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_2(elem_hash)], elem)) {
if (grpc_mdelem_both_interned_eq(c->entries_elems[HASH_FRAGMENT_2(elem_hash)],
elem)) {
/* already there: update with new index */
c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
} else if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_3(elem_hash)],
elem)) {
} else if (grpc_mdelem_both_interned_eq(
c->entries_elems[HASH_FRAGMENT_3(elem_hash)], elem)) {
/* already there (cuckoo): update with new index */
c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
} else if (GRPC_MDISNULL(c->entries_elems[HASH_FRAGMENT_2(elem_hash)])) {
@ -294,19 +301,19 @@ static void add_elem_with_index(grpc_chttp2_hpack_compressor* c,
c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
}
add_key_with_index(c, elem, new_index);
add_key_with_index(c, elem, new_index, key_hash);
}
static void add_elem(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
size_t elem_size) {
size_t elem_size, uint32_t elem_hash, uint32_t key_hash) {
uint32_t new_index = prepare_space_for_new_elem(c, elem_size);
add_elem_with_index(c, elem, new_index);
add_elem_with_index(c, elem, new_index, elem_hash, key_hash);
}
static void add_key(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
size_t elem_size) {
size_t elem_size, uint32_t key_hash) {
uint32_t new_index = prepare_space_for_new_elem(c, elem_size);
add_key_with_index(c, elem, new_index);
add_key_with_index(c, elem, new_index, key_hash);
}
static void emit_indexed(grpc_chttp2_hpack_compressor* c, uint32_t elem_index,
@ -323,9 +330,14 @@ typedef struct {
bool insert_null_before_wire_value;
} wire_value;
template <bool mdkey_definitely_interned>
static wire_value get_wire_value(grpc_mdelem elem, bool true_binary_enabled) {
wire_value wire_val;
if (grpc_is_binary_header(GRPC_MDKEY(elem))) {
bool is_bin_hdr =
mdkey_definitely_interned
? grpc_is_refcounted_slice_binary_header(GRPC_MDKEY(elem))
: grpc_is_binary_header_internal(GRPC_MDKEY(elem));
if (is_bin_hdr) {
if (true_binary_enabled) {
GRPC_STATS_INC_HPACK_SEND_BINARY();
wire_val.huffman_prefix = 0x00;
@ -363,7 +375,7 @@ static void emit_lithdr_incidx(grpc_chttp2_hpack_compressor* c,
framer_state* st) {
GRPC_STATS_INC_HPACK_SEND_LITHDR_INCIDX();
uint32_t len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 2);
wire_value value = get_wire_value(elem, st->use_true_binary_metadata);
wire_value value = get_wire_value<true>(elem, st->use_true_binary_metadata);
size_t len_val = wire_value_length(value);
uint32_t len_val_len;
GPR_ASSERT(len_val <= UINT32_MAX);
@ -380,7 +392,7 @@ static void emit_lithdr_noidx(grpc_chttp2_hpack_compressor* c,
framer_state* st) {
GRPC_STATS_INC_HPACK_SEND_LITHDR_NOTIDX();
uint32_t len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 4);
wire_value value = get_wire_value(elem, st->use_true_binary_metadata);
wire_value value = get_wire_value<false>(elem, st->use_true_binary_metadata);
size_t len_val = wire_value_length(value);
uint32_t len_val_len;
GPR_ASSERT(len_val <= UINT32_MAX);
@ -399,7 +411,7 @@ static void emit_lithdr_incidx_v(grpc_chttp2_hpack_compressor* c,
GRPC_STATS_INC_HPACK_SEND_LITHDR_INCIDX_V();
GRPC_STATS_INC_HPACK_SEND_UNCOMPRESSED();
uint32_t len_key = static_cast<uint32_t> GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
wire_value value = get_wire_value(elem, st->use_true_binary_metadata);
wire_value value = get_wire_value<true>(elem, st->use_true_binary_metadata);
uint32_t len_val = static_cast<uint32_t>(wire_value_length(value));
uint32_t len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1);
uint32_t len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1);
@ -421,7 +433,7 @@ static void emit_lithdr_noidx_v(grpc_chttp2_hpack_compressor* c,
GRPC_STATS_INC_HPACK_SEND_LITHDR_NOTIDX_V();
GRPC_STATS_INC_HPACK_SEND_UNCOMPRESSED();
uint32_t len_key = static_cast<uint32_t> GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
wire_value value = get_wire_value(elem, st->use_true_binary_metadata);
wire_value value = get_wire_value<false>(elem, st->use_true_binary_metadata);
uint32_t len_val = static_cast<uint32_t>(wire_value_length(value));
uint32_t len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1);
uint32_t len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1);
@ -464,7 +476,7 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) {
char* k = grpc_slice_to_c_string(GRPC_MDKEY(elem));
char* v = nullptr;
if (grpc_is_binary_header(GRPC_MDKEY(elem))) {
if (grpc_is_binary_header_internal(GRPC_MDKEY(elem))) {
v = grpc_dump_slice(GRPC_MDVALUE(elem), GPR_DUMP_HEX);
} else {
v = grpc_slice_to_c_string(GRPC_MDVALUE(elem));
@ -488,27 +500,33 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
return;
}
uint32_t key_hash = grpc_slice_hash(GRPC_MDKEY(elem));
uint32_t elem_hash = 0;
if (elem_interned) {
uint32_t value_hash = grpc_slice_hash(GRPC_MDVALUE(elem));
elem_hash = GRPC_MDSTR_KV_HASH(key_hash, value_hash);
if (GRPC_MDELEM_STORAGE(elem) == GRPC_MDELEM_STORAGE_INTERNED) {
elem_hash =
reinterpret_cast<grpc_core::InternedMetadata*>(GRPC_MDELEM_DATA(elem))
->hash();
} else {
elem_hash =
reinterpret_cast<grpc_core::StaticMetadata*>(GRPC_MDELEM_DATA(elem))
->hash();
}
inc_filter(HASH_FRAGMENT_1(elem_hash), &c->filter_elems_sum,
c->filter_elems);
/* is this elem currently in the decoders table? */
if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_2(elem_hash)], elem) &&
if (grpc_mdelem_both_interned_eq(
c->entries_elems[HASH_FRAGMENT_2(elem_hash)], elem) &&
c->indices_elems[HASH_FRAGMENT_2(elem_hash)] > c->tail_remote_index) {
/* HIT: complete element (first cuckoo hash) */
emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_2(elem_hash)]),
st);
return;
}
if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_3(elem_hash)], elem) &&
if (grpc_mdelem_both_interned_eq(
c->entries_elems[HASH_FRAGMENT_3(elem_hash)], elem) &&
c->indices_elems[HASH_FRAGMENT_3(elem_hash)] > c->tail_remote_index) {
/* HIT: complete element (second cuckoo hash) */
emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_3(elem_hash)]),
@ -527,11 +545,12 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
c->filter_elems[HASH_FRAGMENT_1(elem_hash)] >=
c->filter_elems_sum / ONE_ON_ADD_PROBABILITY;
uint32_t key_hash = GRPC_MDKEY(elem).refcount->Hash(GRPC_MDKEY(elem));
auto emit_maybe_add = [&should_add_elem, &elem, &st, &c, &indices_key,
&decoder_space_usage] {
&decoder_space_usage, &elem_hash, &key_hash] {
if (should_add_elem) {
emit_lithdr_incidx(c, dynidx(c, indices_key), elem, st);
add_elem(c, elem, decoder_space_usage);
add_elem(c, elem, decoder_space_usage, elem_hash, key_hash);
} else {
emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st);
}
@ -539,8 +558,8 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
/* no hits for the elem... maybe there's a key? */
indices_key = c->indices_keys[HASH_FRAGMENT_2(key_hash)];
if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_2(key_hash)],
GRPC_MDKEY(elem)) &&
if (grpc_slice_static_interned_equal(
c->entries_keys[HASH_FRAGMENT_2(key_hash)], GRPC_MDKEY(elem)) &&
indices_key > c->tail_remote_index) {
/* HIT: key (first cuckoo hash) */
emit_maybe_add();
@ -548,8 +567,8 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
}
indices_key = c->indices_keys[HASH_FRAGMENT_3(key_hash)];
if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_3(key_hash)],
GRPC_MDKEY(elem)) &&
if (grpc_slice_static_interned_equal(
c->entries_keys[HASH_FRAGMENT_3(key_hash)], GRPC_MDKEY(elem)) &&
indices_key > c->tail_remote_index) {
/* HIT: key (first cuckoo hash) */
emit_maybe_add();
@ -565,9 +584,9 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
emit_lithdr_noidx_v(c, 0, elem, st);
}
if (should_add_elem) {
add_elem(c, elem, decoder_space_usage);
add_elem(c, elem, decoder_space_usage, elem_hash, key_hash);
} else if (should_add_key) {
add_key(c, elem, decoder_space_usage);
add_key(c, elem, decoder_space_usage, key_hash);
}
}
@ -692,18 +711,18 @@ void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor* c,
}
for (size_t i = 0; i < extra_headers_size; ++i) {
grpc_mdelem md = *extra_headers[i];
uint8_t static_index = grpc_chttp2_get_static_hpack_table_index(md);
uintptr_t static_index = grpc_chttp2_get_static_hpack_table_index(md);
if (static_index) {
emit_indexed(c, static_index, &st);
emit_indexed(c, static_cast<uint32_t>(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) {
uint8_t static_index = grpc_chttp2_get_static_hpack_table_index(l->md);
uintptr_t static_index = grpc_chttp2_get_static_hpack_table_index(l->md);
if (static_index) {
emit_indexed(c, static_index, &st);
emit_indexed(c, static_cast<uint32_t>(static_index), &st);
} else {
hpack_enc(c, l->md, &st);
}

@ -35,6 +35,7 @@
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/surface/validate_metadata.h"
#include "src/core/lib/transport/http2_errors.h"
typedef enum {
@ -627,7 +628,7 @@ static grpc_error* on_hdr(grpc_chttp2_hpack_parser* p, grpc_mdelem md,
if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) {
char* k = grpc_slice_to_c_string(GRPC_MDKEY(md));
char* v = nullptr;
if (grpc_is_binary_header(GRPC_MDKEY(md))) {
if (grpc_is_binary_header_internal(GRPC_MDKEY(md))) {
v = grpc_dump_slice(GRPC_MDVALUE(md), GPR_DUMP_HEX);
} else {
v = grpc_slice_to_c_string(GRPC_MDVALUE(md));
@ -1494,7 +1495,13 @@ static grpc_error* parse_key_string(grpc_chttp2_hpack_parser* p,
/* check if a key represents a binary header or not */
static bool is_binary_literal_header(grpc_chttp2_hpack_parser* p) {
return grpc_is_binary_header(
/* We know that either argument here is a reference counter slice.
* 1. If a result of grpc_slice_from_static_buffer, the refcount is set to
* NoopRefcount.
* 2. If it's p->key.data.referenced, then p->key.copied was set to false,
* which occurs in begin_parse_string() - where the refcount is set to
* p->current_slice_refcount, which is not null. */
return grpc_is_refcounted_slice_binary_header(
p->key.copied ? grpc_slice_from_static_buffer(p->key.data.copied.str,
p->key.data.copied.length)
: p->key.data.referenced);
@ -1511,7 +1518,15 @@ static grpc_error* is_binary_indexed_header(grpc_chttp2_hpack_parser* p,
static_cast<intptr_t>(p->index)),
GRPC_ERROR_INT_SIZE, static_cast<intptr_t>(p->table.num_ents));
}
*is = grpc_is_binary_header(GRPC_MDKEY(elem));
/* We know that GRPC_MDKEY(elem) points to a reference counted slice since:
* 1. elem was a result of grpc_chttp2_hptbl_lookup
* 2. An item in this table is either static (see entries with
* index < GRPC_CHTTP2_LAST_STATIC_ENTRY or added via
* grpc_chttp2_hptbl_add).
* 3. If added via grpc_chttp2_hptbl_add, the entry is either static or
* interned.
* 4. Both static and interned element slices have non-null refcounts. */
*is = grpc_is_refcounted_slice_binary_header(GRPC_MDKEY(elem));
return GRPC_ERROR_NONE;
}

@ -29,6 +29,7 @@
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gpr/murmur_hash.h"
#include "src/core/lib/surface/validate_metadata.h"
#include "src/core/lib/transport/static_metadata.h"
extern grpc_core::TraceFlag grpc_http_trace;
@ -375,9 +376,11 @@ static size_t get_base64_encoded_size(size_t raw_length) {
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));
const uint8_t* key_buf = GRPC_SLICE_START_PTR(GRPC_MDKEY(elem));
size_t key_len = GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
size_t overhead_and_key = 32 + key_len;
size_t value_len = GRPC_SLICE_LENGTH(GRPC_MDVALUE(elem));
if (grpc_is_binary_header(GRPC_MDKEY(elem))) {
if (grpc_key_is_binary_header(key_buf, key_len)) {
return overhead_and_key + (use_true_binary_metadata
? value_len + 1
: get_base64_encoded_size(value_len));
@ -385,13 +388,3 @@ size_t grpc_chttp2_get_size_in_hpack_table(grpc_mdelem elem,
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) {
uint8_t index = GRPC_MDELEM_DATA(md) - grpc_static_mdelem_table;
if (index < GRPC_CHTTP2_LAST_STATIC_ENTRY) {
return index + 1; // Hpack static metadata element indices start at 1
}
}
return 0;
}

@ -24,6 +24,7 @@
#include <grpc/slice.h>
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/transport/metadata.h"
#include "src/core/lib/transport/static_metadata.h"
/* HPACK header table */
@ -90,7 +91,15 @@ size_t grpc_chttp2_get_size_in_hpack_table(grpc_mdelem elem,
/* 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);
inline uintptr_t grpc_chttp2_get_static_hpack_table_index(grpc_mdelem md) {
uintptr_t index =
reinterpret_cast<grpc_core::StaticMetadata*>(GRPC_MDELEM_DATA(md)) -
grpc_static_mdelem_table;
if (index < GRPC_CHTTP2_LAST_STATIC_ENTRY) {
return index + 1; // Hpack static metadata element indices start at 1
}
return 0;
}
/* 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 */

@ -38,6 +38,7 @@
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/surface/validate_metadata.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/static_metadata.h"
#include "src/core/lib/transport/transport_impl.h"
@ -419,7 +420,7 @@ static void convert_cronet_array_to_metadata(
grpc_slice key = grpc_slice_intern(
grpc_slice_from_static_string(header_array->headers[i].key));
grpc_slice value;
if (grpc_is_binary_header(key)) {
if (grpc_is_refcounted_slice_binary_header(key)) {
value = grpc_slice_from_static_string(header_array->headers[i].value);
value = grpc_slice_intern(grpc_chttp2_base64_decode_with_length(
value, grpc_chttp2_base64_infer_length_after_decode(value)));
@ -746,7 +747,7 @@ static void convert_metadata_to_cronet_headers(
curr = curr->next;
char* key = grpc_slice_to_c_string(GRPC_MDKEY(mdelem));
char* value;
if (grpc_is_binary_header(GRPC_MDKEY(mdelem))) {
if (grpc_is_binary_header_internal(GRPC_MDKEY(mdelem))) {
grpc_slice wire_value = grpc_chttp2_base64_encode(GRPC_MDVALUE(mdelem));
value = grpc_slice_to_c_string(wire_value);
grpc_slice_unref_internal(wire_value);

@ -795,9 +795,9 @@ grpc_error* grpc_wsa_error(const char* file, int line, int err,
}
#endif
bool grpc_log_if_error(const char* what, grpc_error* error, const char* file,
int line) {
if (error == GRPC_ERROR_NONE) return true;
bool grpc_log_error(const char* what, grpc_error* error, const char* file,
int line) {
GPR_DEBUG_ASSERT(error != GRPC_ERROR_NONE);
const char* msg = grpc_error_string(error);
gpr_log(file, line, GPR_LOG_SEVERITY_ERROR, "%s: %s", what, msg);
GRPC_ERROR_UNREF(error);

@ -261,9 +261,15 @@ grpc_error* grpc_wsa_error(const char* file, int line, int err,
#define GRPC_WSA_ERROR(err, call_name) \
grpc_wsa_error(__FILE__, __LINE__, err, call_name)
bool grpc_log_if_error(const char* what, grpc_error* error, const char* file,
int line);
bool grpc_log_error(const char* what, grpc_error* error, const char* file,
int line);
inline bool grpc_log_if_error(const char* what, grpc_error* error,
const char* file, int line) {
return error == GRPC_ERROR_NONE ? true
: grpc_log_error(what, error, file, line);
}
#define GRPC_LOG_IF_ERROR(what, error) \
grpc_log_if_error((what), (error), __FILE__, __LINE__)
(grpc_log_if_error((what), (error), __FILE__, __LINE__))
#endif /* GRPC_CORE_LIB_IOMGR_ERROR_H */

@ -57,10 +57,10 @@ void grpc_iomgr_init() {
gpr_mu_init(&g_mu);
gpr_cv_init(&g_rcv);
grpc_core::Executor::InitAll();
grpc_timer_list_init();
g_root_object.next = g_root_object.prev = &g_root_object;
g_root_object.name = (char*)"root";
grpc_iomgr_platform_init();
grpc_timer_list_init();
grpc_core::grpc_errqueue_init();
}

@ -29,7 +29,8 @@
typedef struct grpc_timer {
grpc_millis deadline;
uint32_t heap_index; /* INVALID_HEAP_INDEX if not in heap */
// Uninitialized if not using heap, or INVALID_HEAP_INDEX if not in heap.
uint32_t heap_index;
bool pending;
struct grpc_timer* next;
struct grpc_timer* prev;

@ -85,7 +85,7 @@ static grpc_error* process_plugin_result(
grpc_validate_header_key_is_legal(md[i].key))) {
seen_illegal_header = true;
break;
} else if (!grpc_is_binary_header(md[i].key) &&
} else if (!grpc_is_binary_header_internal(md[i].key) &&
!GRPC_LOG_IF_ERROR(
"validate_metadata_from_plugin",
grpc_validate_header_nonbin_value_is_legal(md[i].value))) {

@ -68,7 +68,8 @@ void grpc_slice_unref(grpc_slice slice) {
/* grpc_slice_from_static_string support structure - a refcount that does
nothing */
static grpc_slice_refcount NoopRefcount;
static grpc_slice_refcount NoopRefcount =
grpc_slice_refcount(grpc_slice_refcount::Type::NOP);
size_t grpc_slice_memory_usage(grpc_slice s) {
if (s.refcount == nullptr || s.refcount == &NoopRefcount) {

@ -138,7 +138,7 @@ SliceHashTable<T>::~SliceHashTable() {
template <typename T>
void SliceHashTable<T>::Add(const grpc_slice& key, T& value) {
const size_t hash = grpc_slice_hash(key);
const size_t hash = grpc_slice_hash_internal(key);
for (size_t offset = 0; offset < size_; ++offset) {
const size_t idx = (hash + offset) % size_;
if (!entries_[idx].is_set) {
@ -156,7 +156,7 @@ void SliceHashTable<T>::Add(const grpc_slice& key, T& value) {
template <typename T>
const T* SliceHashTable<T>::Get(const grpc_slice& key) const {
const size_t hash = grpc_slice_hash(key);
const size_t hash = grpc_slice_hash_internal(key);
// We cap the number of probes at the max number recorded when
// populating the table.
for (size_t offset = 0; offset <= max_num_probes_; ++offset) {

@ -128,10 +128,7 @@ int grpc_static_slice_eq(grpc_slice a, grpc_slice b) {
return GRPC_STATIC_METADATA_INDEX(a) == GRPC_STATIC_METADATA_INDEX(b);
}
uint32_t grpc_slice_hash(grpc_slice s) {
return s.refcount == nullptr ? grpc_slice_default_hash_impl(s)
: s.refcount->Hash(s);
}
uint32_t grpc_slice_hash(grpc_slice s) { return grpc_slice_hash_internal(s); }
grpc_slice grpc_slice_maybe_static_intern(grpc_slice slice,
bool* returned_slice_is_different) {
@ -139,7 +136,7 @@ grpc_slice grpc_slice_maybe_static_intern(grpc_slice slice,
return slice;
}
uint32_t hash = grpc_slice_hash(slice);
uint32_t hash = grpc_slice_hash_internal(slice);
for (uint32_t i = 0; i <= max_static_metadata_hash_probe; i++) {
static_metadata_hash_ent ent =
static_metadata_hash[(hash + i) % GPR_ARRAY_SIZE(static_metadata_hash)];
@ -154,19 +151,13 @@ grpc_slice grpc_slice_maybe_static_intern(grpc_slice slice,
return slice;
}
bool grpc_slice_is_interned(const grpc_slice& slice) {
return (slice.refcount &&
(slice.refcount->GetType() == grpc_slice_refcount::Type::INTERNED ||
GRPC_IS_STATIC_METADATA_STRING(slice)));
}
grpc_slice grpc_slice_intern(grpc_slice slice) {
GPR_TIMER_SCOPE("grpc_slice_intern", 0);
if (GRPC_IS_STATIC_METADATA_STRING(slice)) {
return slice;
}
uint32_t hash = grpc_slice_hash(slice);
uint32_t hash = grpc_slice_hash_internal(slice);
for (uint32_t i = 0; i <= max_static_metadata_hash_probe; i++) {
static_metadata_hash_ent ent =
@ -238,7 +229,7 @@ void grpc_slice_intern_init(void) {
max_static_metadata_hash_probe = 0;
for (size_t i = 0; i < GRPC_STATIC_MDSTR_COUNT; i++) {
grpc_static_metadata_hash_values[i] =
grpc_slice_default_hash_impl(grpc_static_slice_table[i]);
grpc_slice_default_hash_internal(grpc_static_slice_table[i]);
for (size_t j = 0; j < GPR_ARRAY_SIZE(static_metadata_hash); j++) {
size_t slot = (grpc_static_metadata_hash_values[i] + j) %
GPR_ARRAY_SIZE(static_metadata_hash);
@ -252,6 +243,10 @@ void grpc_slice_intern_init(void) {
}
}
}
// Handle KV hash for all static mdelems.
for (size_t i = 0; i < GRPC_STATIC_MDELEM_COUNT; ++i) {
grpc_static_mdelem_table[i].HashInit();
}
}
void grpc_slice_intern_shutdown(void) {

@ -99,12 +99,15 @@ struct grpc_slice_refcount {
enum class Type {
STATIC, // Refcount for a static metadata slice.
INTERNED, // Refcount for an interned slice.
NOP, // No-Op
REGULAR // Refcount for non-static-metadata, non-interned slices.
};
typedef void (*DestroyerFn)(void*);
grpc_slice_refcount() = default;
explicit grpc_slice_refcount(Type t) : ref_type_(t) {}
explicit grpc_slice_refcount(grpc_slice_refcount* sub) : sub_refcount_(sub) {}
// Regular constructor for grpc_slice_refcount.
//
@ -200,6 +203,7 @@ inline int grpc_slice_refcount::Eq(const grpc_slice& a, const grpc_slice& b) {
return GRPC_STATIC_METADATA_INDEX(a) == GRPC_STATIC_METADATA_INDEX(b);
case Type::INTERNED:
return a.refcount == b.refcount;
case Type::NOP:
case Type::REGULAR:
break;
}
@ -217,6 +221,7 @@ inline uint32_t grpc_slice_refcount::Hash(const grpc_slice& slice) {
case Type::INTERNED:
return reinterpret_cast<grpc_core::InternedSliceRefcount*>(slice.refcount)
->hash;
case Type::NOP:
case Type::REGULAR:
break;
}
@ -258,6 +263,17 @@ void grpc_slice_buffer_sub_first(grpc_slice_buffer* sb, size_t begin,
/* Check if a slice is interned */
bool grpc_slice_is_interned(const grpc_slice& slice);
inline bool grpc_slice_is_interned(const grpc_slice& slice) {
return (slice.refcount &&
(slice.refcount->GetType() == grpc_slice_refcount::Type::INTERNED ||
slice.refcount->GetType() == grpc_slice_refcount::Type::STATIC));
}
inline bool grpc_slice_static_interned_equal(const grpc_slice& a,
const grpc_slice& b) {
GPR_DEBUG_ASSERT(grpc_slice_is_interned(a) && grpc_slice_is_interned(b));
return a.refcount == b.refcount;
}
void grpc_slice_intern_init(void);
void grpc_slice_intern_shutdown(void);
@ -271,6 +287,21 @@ grpc_slice grpc_slice_maybe_static_intern(grpc_slice slice,
uint32_t grpc_static_slice_hash(grpc_slice s);
int grpc_static_slice_eq(grpc_slice a, grpc_slice b);
inline uint32_t grpc_slice_hash_refcounted(const grpc_slice& s) {
GPR_DEBUG_ASSERT(s.refcount != nullptr);
return s.refcount->Hash(s);
}
inline uint32_t grpc_slice_default_hash_internal(const grpc_slice& s) {
return gpr_murmur_hash3(GRPC_SLICE_START_PTR(s), GRPC_SLICE_LENGTH(s),
g_hash_seed);
}
inline uint32_t grpc_slice_hash_internal(const grpc_slice& s) {
return s.refcount == nullptr ? grpc_slice_default_hash_internal(s)
: grpc_slice_hash_refcounted(s);
}
// Returns the memory used by this slice, not counting the slice structure
// itself. This means that inlined and slices from static strings will return
// 0. All other slices will return the size of the allocated chars.

@ -27,7 +27,7 @@
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/slice/slice_internal.h"
char* grpc_dump_slice(grpc_slice s, uint32_t flags) {
char* grpc_dump_slice(const grpc_slice& s, uint32_t flags) {
return gpr_dump(reinterpret_cast<const char*> GRPC_SLICE_START_PTR(s),
GRPC_SLICE_LENGTH(s), flags);
}

@ -30,7 +30,7 @@
#include "src/core/lib/gpr/string.h"
/* Calls gpr_dump on a slice. */
char* grpc_dump_slice(grpc_slice slice, uint32_t flags);
char* grpc_dump_slice(const grpc_slice& slice, uint32_t flags);
/** Split \a str by the separator \a sep. Results are stored in \a dst, which
* should be a properly initialized instance. */

@ -47,7 +47,7 @@ class SliceWeakHashTable : public RefCounted<SliceWeakHashTable<T, Size>> {
/// Add a mapping from \a key to \a value, taking ownership of \a key. This
/// operation will always succeed. It may discard older entries.
void Add(const grpc_slice& key, T value) {
const size_t idx = grpc_slice_hash(key) % Size;
const size_t idx = grpc_slice_hash_internal(key) % Size;
entries_[idx].Set(key, std::move(value));
return;
}
@ -55,7 +55,7 @@ class SliceWeakHashTable : public RefCounted<SliceWeakHashTable<T, Size>> {
/// Returns the value from the table associated with / \a key or null if not
/// found.
const T* Get(const grpc_slice& key) const {
const size_t idx = grpc_slice_hash(key) % Size;
const size_t idx = grpc_slice_hash_internal(key) % Size;
const auto& entry = entries_[idx];
return grpc_slice_eq(entry.key(), key) ? entry.value() : nullptr;
}

@ -899,7 +899,7 @@ static int prepare_application_metadata(grpc_call* call, int count,
if (!GRPC_LOG_IF_ERROR("validate_metadata",
grpc_validate_header_key_is_legal(md->key))) {
break;
} else if (!grpc_is_binary_header(md->key) &&
} else if (!grpc_is_binary_header_internal(md->key) &&
!GRPC_LOG_IF_ERROR(
"validate_metadata",
grpc_validate_header_nonbin_value_is_legal(md->value))) {

@ -59,23 +59,6 @@ typedef struct registered_call {
struct registered_call* next;
} registered_call;
struct grpc_channel {
int is_client;
grpc_compression_options compression_options;
gpr_atm call_size_estimate;
grpc_resource_user* resource_user;
gpr_mu registered_call_mu;
registered_call* registered_calls;
grpc_core::RefCountedPtr<grpc_core::channelz::ChannelNode> channelz_channel;
char* target;
};
#define CHANNEL_STACK_FROM_CHANNEL(c) ((grpc_channel_stack*)((c) + 1))
static void destroy_channel(void* arg, grpc_error* error);
grpc_channel* grpc_channel_create_with_builder(
@ -214,11 +197,6 @@ static grpc_channel_args* build_channel_args(
return grpc_channel_args_copy_and_add(input_args, new_args, num_new_args);
}
grpc_core::channelz::ChannelNode* grpc_channel_get_channelz_node(
grpc_channel* channel) {
return channel->channelz_channel.get();
}
grpc_channel* grpc_channel_create(const char* target,
const grpc_channel_args* input_args,
grpc_channel_stack_type channel_stack_type,
@ -421,21 +399,6 @@ grpc_call* grpc_channel_create_registered_call(
return call;
}
#ifndef NDEBUG
#define REF_REASON reason
#define REF_ARG , const char* reason
#else
#define REF_REASON ""
#define REF_ARG
#endif
void grpc_channel_internal_ref(grpc_channel* c REF_ARG) {
GRPC_CHANNEL_STACK_REF(CHANNEL_STACK_FROM_CHANNEL(c), REF_REASON);
}
void grpc_channel_internal_unref(grpc_channel* c REF_ARG) {
GRPC_CHANNEL_STACK_UNREF(CHANNEL_STACK_FROM_CHANNEL(c), REF_REASON);
}
static void destroy_channel(void* arg, grpc_error* error) {
grpc_channel* channel = static_cast<grpc_channel*>(arg);
if (channel->channelz_channel != nullptr) {
@ -475,25 +438,9 @@ void grpc_channel_destroy(grpc_channel* channel) {
GRPC_CHANNEL_INTERNAL_UNREF(channel, "channel");
}
grpc_channel_stack* grpc_channel_get_channel_stack(grpc_channel* channel) {
return CHANNEL_STACK_FROM_CHANNEL(channel);
}
grpc_compression_options grpc_channel_compression_options(
const grpc_channel* channel) {
return channel->compression_options;
}
grpc_mdelem grpc_channel_get_reffed_status_elem(grpc_channel* channel, int i) {
grpc_mdelem grpc_channel_get_reffed_status_elem_slowpath(grpc_channel* channel,
int i) {
char tmp[GPR_LTOA_MIN_BUFSIZE];
switch (i) {
case 0:
return GRPC_MDELEM_GRPC_STATUS_0;
case 1:
return GRPC_MDELEM_GRPC_STATUS_1;
case 2:
return GRPC_MDELEM_GRPC_STATUS_2;
}
gpr_ltoa(i, tmp);
return grpc_mdelem_from_slices(GRPC_MDSTR_GRPC_STATUS,
grpc_slice_from_copied_string(tmp));

@ -59,22 +59,76 @@ grpc_core::channelz::ChannelNode* grpc_channel_get_channelz_node(
status_code.
The returned elem is owned by the caller. */
grpc_mdelem grpc_channel_get_reffed_status_elem(grpc_channel* channel,
int status_code);
grpc_mdelem grpc_channel_get_reffed_status_elem_slowpath(grpc_channel* channel,
int status_code);
inline grpc_mdelem grpc_channel_get_reffed_status_elem(grpc_channel* channel,
int status_code) {
switch (status_code) {
case 0:
return GRPC_MDELEM_GRPC_STATUS_0;
case 1:
return GRPC_MDELEM_GRPC_STATUS_1;
case 2:
return GRPC_MDELEM_GRPC_STATUS_2;
}
return grpc_channel_get_reffed_status_elem_slowpath(channel, status_code);
}
size_t grpc_channel_get_call_size_estimate(grpc_channel* channel);
void grpc_channel_update_call_size_estimate(grpc_channel* channel, size_t size);
struct registered_call;
struct grpc_channel {
int is_client;
grpc_compression_options compression_options;
gpr_atm call_size_estimate;
grpc_resource_user* resource_user;
gpr_mu registered_call_mu;
registered_call* registered_calls;
grpc_core::RefCountedPtr<grpc_core::channelz::ChannelNode> channelz_channel;
char* target;
};
#define CHANNEL_STACK_FROM_CHANNEL(c) ((grpc_channel_stack*)((c) + 1))
inline grpc_compression_options grpc_channel_compression_options(
const grpc_channel* channel) {
return channel->compression_options;
}
inline grpc_channel_stack* grpc_channel_get_channel_stack(
grpc_channel* channel) {
return CHANNEL_STACK_FROM_CHANNEL(channel);
}
inline grpc_core::channelz::ChannelNode* grpc_channel_get_channelz_node(
grpc_channel* channel) {
return channel->channelz_channel.get();
}
#ifndef NDEBUG
void grpc_channel_internal_ref(grpc_channel* channel, const char* reason);
void grpc_channel_internal_unref(grpc_channel* channel, const char* reason);
inline void grpc_channel_internal_ref(grpc_channel* channel,
const char* reason) {
GRPC_CHANNEL_STACK_REF(CHANNEL_STACK_FROM_CHANNEL(channel), reason);
}
inline void grpc_channel_internal_unref(grpc_channel* channel,
const char* reason) {
GRPC_CHANNEL_STACK_UNREF(CHANNEL_STACK_FROM_CHANNEL(channel), reason);
}
#define GRPC_CHANNEL_INTERNAL_REF(channel, reason) \
grpc_channel_internal_ref(channel, reason)
#define GRPC_CHANNEL_INTERNAL_UNREF(channel, reason) \
grpc_channel_internal_unref(channel, reason)
#else
void grpc_channel_internal_ref(grpc_channel* channel);
void grpc_channel_internal_unref(grpc_channel* channel);
inline void grpc_channel_internal_ref(grpc_channel* channel) {
GRPC_CHANNEL_STACK_REF(CHANNEL_STACK_FROM_CHANNEL(channel), "unused");
}
inline void grpc_channel_internal_unref(grpc_channel* channel) {
GRPC_CHANNEL_STACK_UNREF(CHANNEL_STACK_FROM_CHANNEL(channel), "unused");
}
#define GRPC_CHANNEL_INTERNAL_REF(channel, reason) \
grpc_channel_internal_ref(channel)
#define GRPC_CHANNEL_INTERNAL_UNREF(channel, reason) \

@ -34,6 +34,7 @@
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/tls.h"
#include "src/core/lib/gprpp/atomic.h"
#include "src/core/lib/iomgr/executor.h"
#include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/profiling/timers.h"
@ -200,7 +201,7 @@ struct cq_vtable {
bool (*begin_op)(grpc_completion_queue* cq, void* tag);
void (*end_op)(grpc_completion_queue* cq, void* tag, grpc_error* error,
void (*done)(void* done_arg, grpc_cq_completion* storage),
void* done_arg, grpc_cq_completion* storage);
void* done_arg, grpc_cq_completion* storage, bool internal);
grpc_event (*next)(grpc_completion_queue* cq, gpr_timespec deadline,
void* reserved);
grpc_event (*pluck)(grpc_completion_queue* cq, void* tag,
@ -354,23 +355,20 @@ static bool cq_begin_op_for_callback(grpc_completion_queue* cq, void* tag);
// queue. The done argument is a callback that will be invoked when it is
// safe to free up that storage. The storage MUST NOT be freed until the
// done callback is invoked.
static void cq_end_op_for_next(grpc_completion_queue* cq, void* tag,
grpc_error* error,
void (*done)(void* done_arg,
grpc_cq_completion* storage),
void* done_arg, grpc_cq_completion* storage);
static void cq_end_op_for_pluck(grpc_completion_queue* cq, void* tag,
grpc_error* error,
void (*done)(void* done_arg,
grpc_cq_completion* storage),
void* done_arg, grpc_cq_completion* storage);
static void cq_end_op_for_callback(grpc_completion_queue* cq, void* tag,
grpc_error* error,
void (*done)(void* done_arg,
grpc_cq_completion* storage),
void* done_arg, grpc_cq_completion* storage);
static void cq_end_op_for_next(
grpc_completion_queue* cq, void* tag, grpc_error* error,
void (*done)(void* done_arg, grpc_cq_completion* storage), void* done_arg,
grpc_cq_completion* storage, bool internal);
static void cq_end_op_for_pluck(
grpc_completion_queue* cq, void* tag, grpc_error* error,
void (*done)(void* done_arg, grpc_cq_completion* storage), void* done_arg,
grpc_cq_completion* storage, bool internal);
static void cq_end_op_for_callback(
grpc_completion_queue* cq, void* tag, grpc_error* error,
void (*done)(void* done_arg, grpc_cq_completion* storage), void* done_arg,
grpc_cq_completion* storage, bool internal);
static grpc_event cq_next(grpc_completion_queue* cq, gpr_timespec deadline,
void* reserved);
@ -674,11 +672,10 @@ bool grpc_cq_begin_op(grpc_completion_queue* cq, void* tag) {
/* Queue a GRPC_OP_COMPLETED operation to a completion queue (with a
* completion
* type of GRPC_CQ_NEXT) */
static void cq_end_op_for_next(grpc_completion_queue* cq, void* tag,
grpc_error* error,
void (*done)(void* done_arg,
grpc_cq_completion* storage),
void* done_arg, grpc_cq_completion* storage) {
static void cq_end_op_for_next(
grpc_completion_queue* cq, void* tag, grpc_error* error,
void (*done)(void* done_arg, grpc_cq_completion* storage), void* done_arg,
grpc_cq_completion* storage, bool internal) {
GPR_TIMER_SCOPE("cq_end_op_for_next", 0);
if (GRPC_TRACE_FLAG_ENABLED(grpc_api_trace) ||
@ -754,11 +751,10 @@ static void cq_end_op_for_next(grpc_completion_queue* cq, void* tag,
/* Queue a GRPC_OP_COMPLETED operation to a completion queue (with a
* completion
* type of GRPC_CQ_PLUCK) */
static void cq_end_op_for_pluck(grpc_completion_queue* cq, void* tag,
grpc_error* error,
void (*done)(void* done_arg,
grpc_cq_completion* storage),
void* done_arg, grpc_cq_completion* storage) {
static void cq_end_op_for_pluck(
grpc_completion_queue* cq, void* tag, grpc_error* error,
void (*done)(void* done_arg, grpc_cq_completion* storage), void* done_arg,
grpc_cq_completion* storage, bool internal) {
GPR_TIMER_SCOPE("cq_end_op_for_pluck", 0);
cq_pluck_data* cqd = static_cast<cq_pluck_data*> DATA_FROM_CQ(cq);
@ -821,15 +817,19 @@ static void cq_end_op_for_pluck(grpc_completion_queue* cq, void* tag,
GRPC_ERROR_UNREF(error);
}
static void functor_callback(void* arg, grpc_error* error) {
auto* functor = static_cast<grpc_experimental_completion_queue_functor*>(arg);
functor->functor_run(functor, error == GRPC_ERROR_NONE);
}
/* Complete an event on a completion queue of type GRPC_CQ_CALLBACK */
static void cq_end_op_for_callback(
grpc_completion_queue* cq, void* tag, grpc_error* error,
void (*done)(void* done_arg, grpc_cq_completion* storage), void* done_arg,
grpc_cq_completion* storage) {
grpc_cq_completion* storage, bool internal) {
GPR_TIMER_SCOPE("cq_end_op_for_callback", 0);
cq_callback_data* cqd = static_cast<cq_callback_data*> DATA_FROM_CQ(cq);
bool is_success = (error == GRPC_ERROR_NONE);
if (GRPC_TRACE_FLAG_ENABLED(grpc_api_trace) ||
(GRPC_TRACE_FLAG_ENABLED(grpc_trace_operation_failures) &&
@ -856,16 +856,25 @@ static void cq_end_op_for_callback(
cq_finish_shutdown_callback(cq);
}
GRPC_ERROR_UNREF(error);
auto* functor = static_cast<grpc_experimental_completion_queue_functor*>(tag);
grpc_core::ApplicationCallbackExecCtx::Enqueue(functor, is_success);
if (internal) {
grpc_core::ApplicationCallbackExecCtx::Enqueue(functor,
(error == GRPC_ERROR_NONE));
} else {
GRPC_CLOSURE_SCHED(
GRPC_CLOSURE_CREATE(
functor_callback, functor,
grpc_core::Executor::Scheduler(grpc_core::ExecutorJobType::SHORT)),
GRPC_ERROR_REF(error));
}
GRPC_ERROR_UNREF(error);
}
void grpc_cq_end_op(grpc_completion_queue* cq, void* tag, grpc_error* error,
void (*done)(void* done_arg, grpc_cq_completion* storage),
void* done_arg, grpc_cq_completion* storage) {
cq->vtable->end_op(cq, tag, error, done, done_arg, storage);
void* done_arg, grpc_cq_completion* storage,
bool internal) {
cq->vtable->end_op(cq, tag, error, done, done_arg, storage, internal);
}
typedef struct {
@ -1343,7 +1352,11 @@ 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);
grpc_core::ApplicationCallbackExecCtx::Enqueue(callback, true);
GRPC_CLOSURE_SCHED(
GRPC_CLOSURE_CREATE(
functor_callback, callback,
grpc_core::Executor::Scheduler(grpc_core::ExecutorJobType::SHORT)),
GRPC_ERROR_NONE);
}
static void cq_shutdown_callback(grpc_completion_queue* cq) {

@ -77,7 +77,8 @@ bool grpc_cq_begin_op(grpc_completion_queue* cc, void* tag);
grpc_cq_begin_op */
void grpc_cq_end_op(grpc_completion_queue* cc, void* tag, grpc_error* error,
void (*done)(void* done_arg, grpc_cq_completion* storage),
void* done_arg, grpc_cq_completion* storage);
void* done_arg, grpc_cq_completion* storage,
bool internal = false);
grpc_pollset* grpc_cq_pollset(grpc_completion_queue* cc);

@ -513,7 +513,7 @@ static void publish_call(grpc_server* server, call_data* calld, size_t cq_idx,
}
grpc_cq_end_op(calld->cq_new, rc->tag, GRPC_ERROR_NONE, done_request_event,
rc, &rc->completion);
rc, &rc->completion, true);
}
static void publish_new_rpc(void* arg, grpc_error* error) {
@ -625,8 +625,8 @@ static void start_new_rpc(grpc_call_element* elem) {
if (chand->registered_methods && calld->path_set && calld->host_set) {
/* TODO(ctiller): unify these two searches */
/* check for an exact match with host */
hash = GRPC_MDSTR_KV_HASH(grpc_slice_hash(calld->host),
grpc_slice_hash(calld->path));
hash = GRPC_MDSTR_KV_HASH(grpc_slice_hash_internal(calld->host),
grpc_slice_hash_internal(calld->path));
for (i = 0; i <= chand->registered_method_max_probes; i++) {
rm = &chand->registered_methods[(hash + i) %
chand->registered_method_slots];
@ -644,7 +644,7 @@ static void start_new_rpc(grpc_call_element* elem) {
return;
}
/* check for a wildcard method definition (no host set) */
hash = GRPC_MDSTR_KV_HASH(0, grpc_slice_hash(calld->path));
hash = GRPC_MDSTR_KV_HASH(0, grpc_slice_hash_internal(calld->path));
for (i = 0; i <= chand->registered_method_max_probes; i++) {
rm = &chand->registered_methods[(hash + i) %
chand->registered_method_slots];
@ -1200,8 +1200,8 @@ void grpc_server_setup_transport(
has_host = false;
}
method = grpc_slice_intern(grpc_slice_from_static_string(rm->method));
hash = GRPC_MDSTR_KV_HASH(has_host ? grpc_slice_hash(host) : 0,
grpc_slice_hash(method));
hash = GRPC_MDSTR_KV_HASH(has_host ? grpc_slice_hash_internal(host) : 0,
grpc_slice_hash_internal(method));
for (probes = 0; chand->registered_methods[(hash + probes) % slots]
.server_registered_method != nullptr;
probes++)

@ -29,7 +29,8 @@
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/surface/validate_metadata.h"
static grpc_error* conforms_to(grpc_slice slice, const uint8_t* legal_bits,
static grpc_error* conforms_to(const grpc_slice& slice,
const uint8_t* legal_bits,
const char* err_desc) {
const uint8_t* p = GRPC_SLICE_START_PTR(slice);
const uint8_t* e = GRPC_SLICE_END_PTR(slice);
@ -57,7 +58,7 @@ static int error2int(grpc_error* error) {
return r;
}
grpc_error* grpc_validate_header_key_is_legal(grpc_slice slice) {
grpc_error* grpc_validate_header_key_is_legal(const grpc_slice& slice) {
static const uint8_t legal_header_bits[256 / 8] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xff, 0x03, 0x00, 0x00, 0x00,
0x80, 0xfe, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@ -77,7 +78,8 @@ int grpc_header_key_is_legal(grpc_slice slice) {
return error2int(grpc_validate_header_key_is_legal(slice));
}
grpc_error* grpc_validate_header_nonbin_value_is_legal(grpc_slice slice) {
grpc_error* grpc_validate_header_nonbin_value_is_legal(
const grpc_slice& slice) {
static const uint8_t legal_header_bits[256 / 8] = {
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@ -89,7 +91,11 @@ int grpc_header_nonbin_value_is_legal(grpc_slice slice) {
return error2int(grpc_validate_header_nonbin_value_is_legal(slice));
}
int grpc_is_binary_header_internal(const grpc_slice& slice) {
return grpc_key_is_binary_header(GRPC_SLICE_START_PTR(slice),
GRPC_SLICE_LENGTH(slice));
}
int grpc_is_binary_header(grpc_slice slice) {
if (GRPC_SLICE_LENGTH(slice) < 5) return 0;
return 0 == memcmp(GRPC_SLICE_END_PTR(slice) - 4, "-bin", 4);
return grpc_is_binary_header_internal(slice);
}

@ -24,7 +24,18 @@
#include <grpc/slice.h>
#include "src/core/lib/iomgr/error.h"
grpc_error* grpc_validate_header_key_is_legal(grpc_slice slice);
grpc_error* grpc_validate_header_nonbin_value_is_legal(grpc_slice slice);
grpc_error* grpc_validate_header_key_is_legal(const grpc_slice& slice);
grpc_error* grpc_validate_header_nonbin_value_is_legal(const grpc_slice& slice);
int grpc_is_binary_header_internal(const grpc_slice& slice);
inline int grpc_key_is_binary_header(const uint8_t* buf, size_t length) {
if (length < 5) return 0;
return 0 == memcmp(buf + length - 4, "-bin", 4);
}
inline int grpc_is_refcounted_slice_binary_header(const grpc_slice& slice) {
GPR_DEBUG_ASSERT(slice.refcount != nullptr);
return grpc_key_is_binary_header(slice.data.refcounted.bytes,
slice.data.refcounted.length);
}
#endif /* GRPC_CORE_LIB_SURFACE_VALIDATE_METADATA_H */

@ -43,6 +43,7 @@
using grpc_core::AllocatedMetadata;
using grpc_core::InternedMetadata;
using grpc_core::StaticMetadata;
using grpc_core::UserData;
/* There are two kinds of mdelem and mdstr instances.
@ -100,15 +101,20 @@ void grpc_mdelem_trace_unref(void* md, const grpc_slice& key,
#define TABLE_IDX(hash, capacity) (((hash) >> (LOG2_SHARD_COUNT)) % (capacity))
#define SHARD_IDX(hash) ((hash) & ((1 << (LOG2_SHARD_COUNT)) - 1))
void StaticMetadata::HashInit() {
uint32_t k_hash = grpc_slice_hash_internal(kv_.key);
uint32_t v_hash = grpc_slice_hash_internal(kv_.value);
hash_ = GRPC_MDSTR_KV_HASH(k_hash, v_hash);
}
AllocatedMetadata::AllocatedMetadata(const grpc_slice& key,
const grpc_slice& value)
: key_(grpc_slice_ref_internal(key)),
value_(grpc_slice_ref_internal(value)),
refcnt_(1) {
: RefcountedMdBase(grpc_slice_ref_internal(key),
grpc_slice_ref_internal(value)) {
#ifndef NDEBUG
if (grpc_trace_metadata.enabled()) {
char* key_str = grpc_slice_to_c_string(key_);
char* value_str = grpc_slice_to_c_string(value_);
char* key_str = grpc_slice_to_c_string(key);
char* value_str = grpc_slice_to_c_string(value);
gpr_log(GPR_DEBUG, "ELM ALLOC:%p:%" PRIdPTR ": '%s' = '%s'", this,
RefValue(), key_str, value_str);
gpr_free(key_str);
@ -118,8 +124,8 @@ AllocatedMetadata::AllocatedMetadata(const grpc_slice& key,
}
AllocatedMetadata::~AllocatedMetadata() {
grpc_slice_unref_internal(key_);
grpc_slice_unref_internal(value_);
grpc_slice_unref_internal(key());
grpc_slice_unref_internal(value());
void* user_data = user_data_.data.Load(grpc_core::MemoryOrder::RELAXED);
if (user_data) {
destroy_user_data_func destroy_user_data =
@ -131,15 +137,13 @@ AllocatedMetadata::~AllocatedMetadata() {
InternedMetadata::InternedMetadata(const grpc_slice& key,
const grpc_slice& value, uint32_t hash,
InternedMetadata* next)
: key_(grpc_slice_ref_internal(key)),
value_(grpc_slice_ref_internal(value)),
refcnt_(1),
hash_(hash),
: RefcountedMdBase(grpc_slice_ref_internal(key),
grpc_slice_ref_internal(value), hash),
link_(next) {
#ifndef NDEBUG
if (grpc_trace_metadata.enabled()) {
char* key_str = grpc_slice_to_c_string(key_);
char* value_str = grpc_slice_to_c_string(value_);
char* key_str = grpc_slice_to_c_string(key);
char* value_str = grpc_slice_to_c_string(value);
gpr_log(GPR_DEBUG, "ELM NEW:%p:%" PRIdPTR ": '%s' = '%s'", this,
RefValue(), key_str, value_str);
gpr_free(key_str);
@ -149,8 +153,8 @@ InternedMetadata::InternedMetadata(const grpc_slice& key,
}
InternedMetadata::~InternedMetadata() {
grpc_slice_unref_internal(key_);
grpc_slice_unref_internal(value_);
grpc_slice_unref_internal(key());
grpc_slice_unref_internal(value());
void* user_data = user_data_.data.Load(grpc_core::MemoryOrder::RELAXED);
if (user_data) {
destroy_user_data_func destroy_user_data =
@ -223,17 +227,20 @@ void grpc_mdctx_global_shutdown() {
}
}
#ifndef NDEBUG
static int is_mdelem_static(grpc_mdelem e) {
return GRPC_MDELEM_DATA(e) >= &grpc_static_mdelem_table[0] &&
GRPC_MDELEM_DATA(e) <
return reinterpret_cast<grpc_core::StaticMetadata*>(GRPC_MDELEM_DATA(e)) >=
&grpc_static_mdelem_table[0] &&
reinterpret_cast<grpc_core::StaticMetadata*>(GRPC_MDELEM_DATA(e)) <
&grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
}
#endif
void InternedMetadata::RefWithShardLocked(mdtab_shard* shard) {
#ifndef NDEBUG
if (grpc_trace_metadata.enabled()) {
char* key_str = grpc_slice_to_c_string(key_);
char* value_str = grpc_slice_to_c_string(value_);
char* key_str = grpc_slice_to_c_string(key());
char* value_str = grpc_slice_to_c_string(value());
intptr_t value = RefValue();
gpr_log(__FILE__, __LINE__, GPR_LOG_SEVERITY_DEBUG,
"ELM REF:%p:%" PRIdPTR "->%" PRIdPTR ": '%s' = '%s'", this, value,
@ -323,8 +330,8 @@ grpc_mdelem grpc_mdelem_create(
}
}
uint32_t hash =
GRPC_MDSTR_KV_HASH(grpc_slice_hash(key), grpc_slice_hash(value));
uint32_t hash = GRPC_MDSTR_KV_HASH(grpc_slice_hash_refcounted(key),
grpc_slice_hash_refcounted(value));
InternedMetadata* md;
mdtab_shard* shard = &g_shards[SHARD_IDX(hash)];
size_t idx;
@ -391,8 +398,11 @@ void* grpc_mdelem_get_user_data(grpc_mdelem md, void (*destroy_func)(void*)) {
case GRPC_MDELEM_STORAGE_EXTERNAL:
return nullptr;
case GRPC_MDELEM_STORAGE_STATIC:
return (void*)grpc_static_mdelem_user_data[GRPC_MDELEM_DATA(md) -
grpc_static_mdelem_table];
return reinterpret_cast<void*>(
grpc_static_mdelem_user_data
[reinterpret_cast<grpc_core::StaticMetadata*>(
GRPC_MDELEM_DATA(md)) -
grpc_static_mdelem_table]);
case GRPC_MDELEM_STORAGE_ALLOCATED: {
auto* am = reinterpret_cast<AllocatedMetadata*>(GRPC_MDELEM_DATA(md));
return get_user_data(am->user_data(), destroy_func);
@ -430,15 +440,18 @@ void* grpc_mdelem_set_user_data(grpc_mdelem md, void (*destroy_func)(void*),
return nullptr;
case GRPC_MDELEM_STORAGE_STATIC:
destroy_func(data);
return (void*)grpc_static_mdelem_user_data[GRPC_MDELEM_DATA(md) -
grpc_static_mdelem_table];
return reinterpret_cast<void*>(
grpc_static_mdelem_user_data
[reinterpret_cast<grpc_core::StaticMetadata*>(
GRPC_MDELEM_DATA(md)) -
grpc_static_mdelem_table]);
case GRPC_MDELEM_STORAGE_ALLOCATED: {
auto* am = reinterpret_cast<AllocatedMetadata*>(GRPC_MDELEM_DATA(md));
return set_user_data(am->user_data(), destroy_func, data);
}
case GRPC_MDELEM_STORAGE_INTERNED: {
auto* im = reinterpret_cast<InternedMetadata*> GRPC_MDELEM_DATA(md);
GPR_ASSERT(!is_mdelem_static(md));
GPR_DEBUG_ASSERT(!is_mdelem_static(md));
return set_user_data(im->user_data(), destroy_func, data);
}
}
@ -482,3 +495,20 @@ void grpc_mdelem_do_unref(grpc_mdelem gmd DEBUG_ARGS) {
}
}
}
void grpc_mdelem_on_final_unref(grpc_mdelem_data_storage storage, void* ptr,
uint32_t hash DEBUG_ARGS) {
switch (storage) {
case GRPC_MDELEM_STORAGE_EXTERNAL:
case GRPC_MDELEM_STORAGE_STATIC:
return;
case GRPC_MDELEM_STORAGE_INTERNED: {
note_disposed_interned_metadata(hash);
break;
}
case GRPC_MDELEM_STORAGE_ALLOCATED: {
grpc_core::Delete(reinterpret_cast<AllocatedMetadata*>(ptr));
break;
}
}
}

@ -21,7 +21,7 @@
#include <grpc/support/port_platform.h>
#include "include/grpc/impl/codegen/log.h"
#include <grpc/impl/codegen/log.h>
#include <grpc/grpc.h>
#include <grpc/slice.h>
@ -80,17 +80,22 @@ typedef struct grpc_mdelem_data {
this bit set in their integer value */
#define GRPC_MDELEM_STORAGE_INTERNED_BIT 1
/* External and static storage metadata has no refcount to ref/unref. Allocated
* and interned metadata do have a refcount. Metadata ref and unref methods use
* a switch statement on this enum to determine which behaviour to execute.
* Keeping the no-ref cases together and the ref-cases together leads to
* slightly better code generation (9 inlined instructions rather than 10). */
typedef enum {
/* memory pointed to by grpc_mdelem::payload is owned by an external system */
GRPC_MDELEM_STORAGE_EXTERNAL = 0,
/* memory pointed to by grpc_mdelem::payload is interned by the metadata
system */
GRPC_MDELEM_STORAGE_INTERNED = GRPC_MDELEM_STORAGE_INTERNED_BIT,
/* memory is in the static metadata table */
GRPC_MDELEM_STORAGE_STATIC = GRPC_MDELEM_STORAGE_INTERNED_BIT,
/* memory pointed to by grpc_mdelem::payload is allocated by the metadata
system */
GRPC_MDELEM_STORAGE_ALLOCATED = 2,
/* memory is in the static metadata table */
GRPC_MDELEM_STORAGE_STATIC = 2 | GRPC_MDELEM_STORAGE_INTERNED_BIT,
/* memory pointed to by grpc_mdelem::payload is interned by the metadata
system */
GRPC_MDELEM_STORAGE_INTERNED = 2 | GRPC_MDELEM_STORAGE_INTERNED_BIT,
} grpc_mdelem_data_storage;
struct grpc_mdelem {
@ -141,6 +146,16 @@ inline bool grpc_mdelem_static_value_eq(grpc_mdelem a, grpc_mdelem b_static) {
if (a.payload == b_static.payload) return true;
return grpc_slice_eq_static_interned(GRPC_MDVALUE(a), GRPC_MDVALUE(b_static));
}
#define GRPC_MDISNULL(md) (GRPC_MDELEM_DATA(md) == NULL)
inline bool grpc_mdelem_both_interned_eq(grpc_mdelem a_interned,
grpc_mdelem b_interned) {
GPR_DEBUG_ASSERT(GRPC_MDELEM_IS_INTERNED(a_interned) ||
GRPC_MDISNULL(a_interned));
GPR_DEBUG_ASSERT(GRPC_MDELEM_IS_INTERNED(b_interned) ||
GRPC_MDISNULL(b_interned));
return a_interned.payload == b_interned.payload;
}
/* Mutator and accessor for grpc_mdelem user data. The destructor function
is used as a type tag and is checked during user_data fetch. */
@ -169,17 +184,34 @@ struct UserData {
grpc_core::Atomic<void*> data;
};
class InternedMetadata {
class StaticMetadata {
public:
struct BucketLink {
explicit BucketLink(InternedMetadata* md) : next(md) {}
StaticMetadata(const grpc_slice& key, const grpc_slice& value)
: kv_({key, value}), hash_(0) {}
InternedMetadata* next = nullptr;
};
const grpc_mdelem_data& data() const { return kv_; }
InternedMetadata(const grpc_slice& key, const grpc_slice& value,
uint32_t hash, InternedMetadata* next);
~InternedMetadata();
void HashInit();
uint32_t hash() { return hash_; }
private:
grpc_mdelem_data kv_;
/* private only data */
uint32_t hash_;
};
class RefcountedMdBase {
public:
RefcountedMdBase(const grpc_slice& key, const grpc_slice& value)
: key_(key), value_(value), refcnt_(1) {}
RefcountedMdBase(const grpc_slice& key, const grpc_slice& value,
uint32_t hash)
: key_(key), value_(value), refcnt_(1), hash_(hash) {}
const grpc_slice& key() const { return key_; }
const grpc_slice& value() const { return value_; }
uint32_t hash() { return hash_; }
#ifndef NDEBUG
void Ref(const char* file, int line) {
@ -191,92 +223,65 @@ class InternedMetadata {
grpc_mdelem_trace_unref(this, key_, value_, RefValue(), file, line);
return Unref();
}
#else
// We define a naked Ref() in the else-clause to make sure we don't
// inadvertently skip the assert on debug builds.
#endif
void Ref() {
/* we can assume the ref count is >= 1 as the application is calling
this function - meaning that no adjustment to mdtab_free is necessary,
simplifying the logic here to be just an atomic increment */
refcnt_.FetchAdd(1, MemoryOrder::RELAXED);
}
#endif // ifndef NDEBUG
bool Unref() {
const intptr_t prior = refcnt_.FetchSub(1, MemoryOrder::ACQ_REL);
GPR_DEBUG_ASSERT(prior > 0);
return prior == 1;
}
void RefWithShardLocked(mdtab_shard* shard);
const grpc_slice& key() const { return key_; }
const grpc_slice& value() const { return value_; }
UserData* user_data() { return &user_data_; }
uint32_t hash() { return hash_; }
InternedMetadata* bucket_next() { return link_.next; }
void set_bucket_next(InternedMetadata* md) { link_.next = md; }
static size_t CleanupLinkedMetadata(BucketLink* head);
private:
protected:
intptr_t RefValue() { return refcnt_.Load(MemoryOrder::RELAXED); }
bool AllRefsDropped() { return refcnt_.Load(MemoryOrder::ACQUIRE) == 0; }
bool FirstRef() { return refcnt_.FetchAdd(1, MemoryOrder::RELAXED) == 0; }
intptr_t RefValue() { return refcnt_.Load(MemoryOrder::RELAXED); }
private:
/* must be byte compatible with grpc_mdelem_data */
grpc_slice key_;
grpc_slice value_;
/* private only data */
grpc_core::Atomic<intptr_t> refcnt_;
uint32_t hash_;
uint32_t hash_ = 0;
};
UserData user_data_;
class InternedMetadata : public RefcountedMdBase {
public:
struct BucketLink {
explicit BucketLink(InternedMetadata* md) : next(md) {}
InternedMetadata* next = nullptr;
};
InternedMetadata(const grpc_slice& key, const grpc_slice& value,
uint32_t hash, InternedMetadata* next);
~InternedMetadata();
void RefWithShardLocked(mdtab_shard* shard);
UserData* user_data() { return &user_data_; }
InternedMetadata* bucket_next() { return link_.next; }
void set_bucket_next(InternedMetadata* md) { link_.next = md; }
static size_t CleanupLinkedMetadata(BucketLink* head);
private:
UserData user_data_;
BucketLink link_;
};
/* Shadow structure for grpc_mdelem_data for allocated elements */
class AllocatedMetadata {
class AllocatedMetadata : public RefcountedMdBase {
public:
AllocatedMetadata(const grpc_slice& key, const grpc_slice& value);
~AllocatedMetadata();
const grpc_slice& key() const { return key_; }
const grpc_slice& value() const { return value_; }
UserData* user_data() { return &user_data_; }
#ifndef NDEBUG
void Ref(const char* file, int line) {
grpc_mdelem_trace_ref(this, key_, value_, RefValue(), file, line);
Ref();
}
bool Unref(const char* file, int line) {
grpc_mdelem_trace_unref(this, key_, value_, RefValue(), file, line);
return Unref();
}
#endif // ifndef NDEBUG
void Ref() {
/* we can assume the ref count is >= 1 as the application is calling
this function - meaning that no adjustment to mdtab_free is necessary,
simplifying the logic here to be just an atomic increment */
refcnt_.FetchAdd(1, MemoryOrder::RELAXED);
}
bool Unref() {
const intptr_t prior = refcnt_.FetchSub(1, MemoryOrder::ACQ_REL);
GPR_DEBUG_ASSERT(prior > 0);
return prior == 1;
}
private:
intptr_t RefValue() { return refcnt_.Load(MemoryOrder::RELAXED); }
/* must be byte compatible with grpc_mdelem_data */
grpc_slice key_;
grpc_slice value_;
/* private only data */
grpc_core::Atomic<intptr_t> refcnt_;
UserData user_data_;
};
@ -321,30 +326,40 @@ inline grpc_mdelem grpc_mdelem_ref(grpc_mdelem gmd) {
#ifndef NDEBUG
#define GRPC_MDELEM_UNREF(s) grpc_mdelem_unref((s), __FILE__, __LINE__)
void grpc_mdelem_do_unref(grpc_mdelem gmd, const char* file, int line);
void grpc_mdelem_on_final_unref(grpc_mdelem_data_storage storage, void* ptr,
uint32_t hash, const char* file, int line);
inline void grpc_mdelem_unref(grpc_mdelem gmd, const char* file, int line) {
#else
#define GRPC_MDELEM_UNREF(s) grpc_mdelem_unref((s))
void grpc_mdelem_do_unref(grpc_mdelem gmd);
void grpc_mdelem_on_final_unref(grpc_mdelem_data_storage storage, void* ptr,
uint32_t hash);
inline void grpc_mdelem_unref(grpc_mdelem gmd) {
#endif
switch (GRPC_MDELEM_STORAGE(gmd)) {
const grpc_mdelem_data_storage storage = GRPC_MDELEM_STORAGE(gmd);
switch (storage) {
case GRPC_MDELEM_STORAGE_EXTERNAL:
case GRPC_MDELEM_STORAGE_STATIC:
return;
case GRPC_MDELEM_STORAGE_INTERNED:
case GRPC_MDELEM_STORAGE_ALLOCATED:
auto* md =
reinterpret_cast<grpc_core::RefcountedMdBase*> GRPC_MDELEM_DATA(gmd);
/* once the refcount hits zero, some other thread can come along and
free an interned md at any time: it's unsafe from this point on to
access it so we read the hash now. */
uint32_t hash = md->hash();
if (GPR_UNLIKELY(md->Unref())) {
#ifndef NDEBUG
grpc_mdelem_do_unref(gmd, file, line);
grpc_mdelem_on_final_unref(storage, md, hash, file, line);
#else
grpc_mdelem_do_unref(gmd);
grpc_mdelem_on_final_unref(storage, md, hash);
#endif
}
return;
}
}
#define GRPC_MDNULL GRPC_MAKE_MDELEM(NULL, GRPC_MDELEM_STORAGE_EXTERNAL)
#define GRPC_MDISNULL(md) (GRPC_MDELEM_DATA(md) == NULL)
/* We add 32 bytes of padding as per RFC-7540 section 6.5.2. */
#define GRPC_MDELEM_LENGTH(e) \

@ -390,184 +390,270 @@ grpc_mdelem grpc_static_mdelem_for_static_strings(intptr_t a, intptr_t b) {
uint32_t h = elems_phash(k);
return h < GPR_ARRAY_SIZE(elem_keys) && elem_keys[h] == k &&
elem_idxs[h] != 255
? GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[elem_idxs[h]],
? GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[elem_idxs[h]].data(),
GRPC_MDELEM_STORAGE_STATIC)
: GRPC_MDNULL;
}
grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT] = {
{{&grpc_static_metadata_refcounts[3], {{10, g_bytes + 19}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[1], {{7, g_bytes + 5}}},
{&grpc_static_metadata_refcounts[40], {{3, g_bytes + 612}}}},
{{&grpc_static_metadata_refcounts[1], {{7, g_bytes + 5}}},
{&grpc_static_metadata_refcounts[41], {{4, g_bytes + 615}}}},
{{&grpc_static_metadata_refcounts[0], {{5, g_bytes + 0}}},
{&grpc_static_metadata_refcounts[42], {{1, g_bytes + 619}}}},
{{&grpc_static_metadata_refcounts[0], {{5, g_bytes + 0}}},
{&grpc_static_metadata_refcounts[43], {{11, g_bytes + 620}}}},
{{&grpc_static_metadata_refcounts[4], {{7, g_bytes + 29}}},
{&grpc_static_metadata_refcounts[44], {{4, g_bytes + 631}}}},
{{&grpc_static_metadata_refcounts[4], {{7, g_bytes + 29}}},
{&grpc_static_metadata_refcounts[45], {{5, g_bytes + 635}}}},
{{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[46], {{3, g_bytes + 640}}}},
{{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[47], {{3, g_bytes + 643}}}},
{{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[48], {{3, g_bytes + 646}}}},
{{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[49], {{3, g_bytes + 649}}}},
{{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[50], {{3, g_bytes + 652}}}},
{{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[51], {{3, g_bytes + 655}}}},
{{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[52], {{3, g_bytes + 658}}}},
{{&grpc_static_metadata_refcounts[53], {{14, g_bytes + 661}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
{&grpc_static_metadata_refcounts[54], {{13, g_bytes + 675}}}},
{{&grpc_static_metadata_refcounts[55], {{15, g_bytes + 688}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[56], {{13, g_bytes + 703}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[57], {{6, g_bytes + 716}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[58], {{27, g_bytes + 722}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[59], {{3, g_bytes + 749}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[60], {{5, g_bytes + 752}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[61], {{13, g_bytes + 757}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[62], {{13, g_bytes + 770}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[63], {{19, g_bytes + 783}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[15], {{16, g_bytes + 170}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[64], {{16, g_bytes + 802}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[65], {{14, g_bytes + 818}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[66], {{16, g_bytes + 832}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[67], {{13, g_bytes + 848}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[14], {{12, g_bytes + 158}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[68], {{6, g_bytes + 861}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[69], {{4, g_bytes + 867}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[70], {{4, g_bytes + 871}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[71], {{6, g_bytes + 875}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[72], {{7, g_bytes + 881}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[73], {{4, g_bytes + 888}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[20], {{4, g_bytes + 278}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[74], {{8, g_bytes + 892}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[75], {{17, g_bytes + 900}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[76], {{13, g_bytes + 917}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[77], {{8, g_bytes + 930}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[78], {{19, g_bytes + 938}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[79], {{13, g_bytes + 957}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[80], {{4, g_bytes + 970}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[81], {{8, g_bytes + 974}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[82], {{12, g_bytes + 982}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[83], {{18, g_bytes + 994}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[84], {{19, g_bytes + 1012}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[85], {{5, g_bytes + 1031}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[86], {{7, g_bytes + 1036}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[87], {{7, g_bytes + 1043}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[88], {{11, g_bytes + 1050}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[89], {{6, g_bytes + 1061}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[90], {{10, g_bytes + 1067}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[91], {{25, g_bytes + 1077}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[92], {{17, g_bytes + 1102}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[19], {{10, g_bytes + 268}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[93], {{4, g_bytes + 1119}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[94], {{3, g_bytes + 1123}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[95], {{16, g_bytes + 1126}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[7], {{11, g_bytes + 50}}},
{&grpc_static_metadata_refcounts[96], {{1, g_bytes + 1142}}}},
{{&grpc_static_metadata_refcounts[7], {{11, g_bytes + 50}}},
{&grpc_static_metadata_refcounts[25], {{1, g_bytes + 350}}}},
{{&grpc_static_metadata_refcounts[7], {{11, g_bytes + 50}}},
{&grpc_static_metadata_refcounts[26], {{1, g_bytes + 351}}}},
{{&grpc_static_metadata_refcounts[9], {{13, g_bytes + 77}}},
{&grpc_static_metadata_refcounts[97], {{8, g_bytes + 1143}}}},
{{&grpc_static_metadata_refcounts[9], {{13, g_bytes + 77}}},
{&grpc_static_metadata_refcounts[38], {{4, g_bytes + 597}}}},
{{&grpc_static_metadata_refcounts[9], {{13, g_bytes + 77}}},
{&grpc_static_metadata_refcounts[37], {{7, g_bytes + 590}}}},
{{&grpc_static_metadata_refcounts[5], {{2, g_bytes + 36}}},
{&grpc_static_metadata_refcounts[98], {{8, g_bytes + 1151}}}},
{{&grpc_static_metadata_refcounts[14], {{12, g_bytes + 158}}},
{&grpc_static_metadata_refcounts[99], {{16, g_bytes + 1159}}}},
{{&grpc_static_metadata_refcounts[4], {{7, g_bytes + 29}}},
{&grpc_static_metadata_refcounts[100], {{4, g_bytes + 1175}}}},
{{&grpc_static_metadata_refcounts[1], {{7, g_bytes + 5}}},
{&grpc_static_metadata_refcounts[101], {{3, g_bytes + 1179}}}},
{{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[15], {{16, g_bytes + 170}}},
{&grpc_static_metadata_refcounts[97], {{8, g_bytes + 1143}}}},
{{&grpc_static_metadata_refcounts[15], {{16, g_bytes + 170}}},
{&grpc_static_metadata_refcounts[38], {{4, g_bytes + 597}}}},
{{&grpc_static_metadata_refcounts[21], {{8, g_bytes + 282}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[102], {{11, g_bytes + 1182}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}},
{{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[97], {{8, g_bytes + 1143}}}},
{{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[37], {{7, g_bytes + 590}}}},
{{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[103], {{16, g_bytes + 1193}}}},
{{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[38], {{4, g_bytes + 597}}}},
{{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[104], {{13, g_bytes + 1209}}}},
{{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[105], {{12, g_bytes + 1222}}}},
{{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[106], {{21, g_bytes + 1234}}}},
{{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
{&grpc_static_metadata_refcounts[97], {{8, g_bytes + 1143}}}},
{{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
{&grpc_static_metadata_refcounts[38], {{4, g_bytes + 597}}}},
{{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
{&grpc_static_metadata_refcounts[104], {{13, g_bytes + 1209}}}},
grpc_core::StaticMetadata grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT] = {
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[3], {{10, g_bytes + 19}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[1], {{7, g_bytes + 5}}},
{&grpc_static_metadata_refcounts[40], {{3, g_bytes + 612}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[1], {{7, g_bytes + 5}}},
{&grpc_static_metadata_refcounts[41], {{4, g_bytes + 615}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[0], {{5, g_bytes + 0}}},
{&grpc_static_metadata_refcounts[42], {{1, g_bytes + 619}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[0], {{5, g_bytes + 0}}},
{&grpc_static_metadata_refcounts[43], {{11, g_bytes + 620}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[4], {{7, g_bytes + 29}}},
{&grpc_static_metadata_refcounts[44], {{4, g_bytes + 631}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[4], {{7, g_bytes + 29}}},
{&grpc_static_metadata_refcounts[45], {{5, g_bytes + 635}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[46], {{3, g_bytes + 640}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[47], {{3, g_bytes + 643}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[48], {{3, g_bytes + 646}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[49], {{3, g_bytes + 649}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[50], {{3, g_bytes + 652}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[51], {{3, g_bytes + 655}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[2], {{7, g_bytes + 12}}},
{&grpc_static_metadata_refcounts[52], {{3, g_bytes + 658}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[53], {{14, g_bytes + 661}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
{&grpc_static_metadata_refcounts[54], {{13, g_bytes + 675}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[55], {{15, g_bytes + 688}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[56], {{13, g_bytes + 703}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[57], {{6, g_bytes + 716}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[58], {{27, g_bytes + 722}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[59], {{3, g_bytes + 749}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[60], {{5, g_bytes + 752}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[61], {{13, g_bytes + 757}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[62], {{13, g_bytes + 770}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[63], {{19, g_bytes + 783}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[15], {{16, g_bytes + 170}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[64], {{16, g_bytes + 802}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[65], {{14, g_bytes + 818}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[66], {{16, g_bytes + 832}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[67], {{13, g_bytes + 848}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[14], {{12, g_bytes + 158}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[68], {{6, g_bytes + 861}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[69], {{4, g_bytes + 867}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[70], {{4, g_bytes + 871}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[71], {{6, g_bytes + 875}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[72], {{7, g_bytes + 881}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[73], {{4, g_bytes + 888}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[20], {{4, g_bytes + 278}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[74], {{8, g_bytes + 892}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[75], {{17, g_bytes + 900}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[76], {{13, g_bytes + 917}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[77], {{8, g_bytes + 930}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[78], {{19, g_bytes + 938}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[79], {{13, g_bytes + 957}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[80], {{4, g_bytes + 970}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[81], {{8, g_bytes + 974}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[82], {{12, g_bytes + 982}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[83], {{18, g_bytes + 994}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[84], {{19, g_bytes + 1012}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[85], {{5, g_bytes + 1031}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[86], {{7, g_bytes + 1036}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[87], {{7, g_bytes + 1043}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[88], {{11, g_bytes + 1050}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[89], {{6, g_bytes + 1061}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[90], {{10, g_bytes + 1067}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[91], {{25, g_bytes + 1077}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[92], {{17, g_bytes + 1102}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[19], {{10, g_bytes + 268}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[93], {{4, g_bytes + 1119}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[94], {{3, g_bytes + 1123}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[95], {{16, g_bytes + 1126}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[7], {{11, g_bytes + 50}}},
{&grpc_static_metadata_refcounts[96], {{1, g_bytes + 1142}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[7], {{11, g_bytes + 50}}},
{&grpc_static_metadata_refcounts[25], {{1, g_bytes + 350}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[7], {{11, g_bytes + 50}}},
{&grpc_static_metadata_refcounts[26], {{1, g_bytes + 351}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[9], {{13, g_bytes + 77}}},
{&grpc_static_metadata_refcounts[97], {{8, g_bytes + 1143}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[9], {{13, g_bytes + 77}}},
{&grpc_static_metadata_refcounts[38], {{4, g_bytes + 597}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[9], {{13, g_bytes + 77}}},
{&grpc_static_metadata_refcounts[37], {{7, g_bytes + 590}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[5], {{2, g_bytes + 36}}},
{&grpc_static_metadata_refcounts[98], {{8, g_bytes + 1151}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[14], {{12, g_bytes + 158}}},
{&grpc_static_metadata_refcounts[99], {{16, g_bytes + 1159}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[4], {{7, g_bytes + 29}}},
{&grpc_static_metadata_refcounts[100], {{4, g_bytes + 1175}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[1], {{7, g_bytes + 5}}},
{&grpc_static_metadata_refcounts[101], {{3, g_bytes + 1179}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[15], {{16, g_bytes + 170}}},
{&grpc_static_metadata_refcounts[97], {{8, g_bytes + 1143}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[15], {{16, g_bytes + 170}}},
{&grpc_static_metadata_refcounts[38], {{4, g_bytes + 597}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[21], {{8, g_bytes + 282}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[102], {{11, g_bytes + 1182}}},
{&grpc_static_metadata_refcounts[29], {{0, g_bytes + 354}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[97], {{8, g_bytes + 1143}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[37], {{7, g_bytes + 590}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[103], {{16, g_bytes + 1193}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[38], {{4, g_bytes + 597}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[104], {{13, g_bytes + 1209}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[105], {{12, g_bytes + 1222}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[10], {{20, g_bytes + 90}}},
{&grpc_static_metadata_refcounts[106], {{21, g_bytes + 1234}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
{&grpc_static_metadata_refcounts[97], {{8, g_bytes + 1143}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
{&grpc_static_metadata_refcounts[38], {{4, g_bytes + 597}}}),
grpc_core::StaticMetadata(
{&grpc_static_metadata_refcounts[16], {{15, g_bytes + 186}}},
{&grpc_static_metadata_refcounts[104], {{13, g_bytes + 1209}}}),
};
const uint8_t grpc_static_accept_encoding_metadata[8] = {0, 76, 77, 78,
79, 80, 81, 82};

@ -269,266 +269,353 @@ extern grpc_slice_refcount
((static_slice).refcount - grpc_static_metadata_refcounts)))
#define GRPC_STATIC_MDELEM_COUNT 86
extern grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
extern grpc_core::StaticMetadata
grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
extern uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT];
/* ":authority": "" */
#define GRPC_MDELEM_AUTHORITY_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[0], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_AUTHORITY_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[0].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":method": "GET" */
#define GRPC_MDELEM_METHOD_GET \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[1], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_METHOD_GET \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[1].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":method": "POST" */
#define GRPC_MDELEM_METHOD_POST \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[2], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_METHOD_POST \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[2].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":path": "/" */
#define GRPC_MDELEM_PATH_SLASH \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[3], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_PATH_SLASH \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[3].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":path": "/index.html" */
#define GRPC_MDELEM_PATH_SLASH_INDEX_DOT_HTML \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[4], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_PATH_SLASH_INDEX_DOT_HTML \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[4].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":scheme": "http" */
#define GRPC_MDELEM_SCHEME_HTTP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[5], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_SCHEME_HTTP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[5].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":scheme": "https" */
#define GRPC_MDELEM_SCHEME_HTTPS \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[6], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_SCHEME_HTTPS \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[6].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":status": "200" */
#define GRPC_MDELEM_STATUS_200 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[7], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_STATUS_200 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[7].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":status": "204" */
#define GRPC_MDELEM_STATUS_204 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[8], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_STATUS_204 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[8].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":status": "206" */
#define GRPC_MDELEM_STATUS_206 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[9], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_STATUS_206 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[9].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":status": "304" */
#define GRPC_MDELEM_STATUS_304 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[10], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_STATUS_304 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[10].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":status": "400" */
#define GRPC_MDELEM_STATUS_400 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[11], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_STATUS_400 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[11].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":status": "404" */
#define GRPC_MDELEM_STATUS_404 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[12], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_STATUS_404 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[12].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":status": "500" */
#define GRPC_MDELEM_STATUS_500 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[13], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_STATUS_500 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[13].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "accept-charset": "" */
#define GRPC_MDELEM_ACCEPT_CHARSET_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[14], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_ACCEPT_CHARSET_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[14].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "accept-encoding": "gzip, deflate" */
#define GRPC_MDELEM_ACCEPT_ENCODING_GZIP_COMMA_DEFLATE \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[15], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_ACCEPT_ENCODING_GZIP_COMMA_DEFLATE \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[15].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "accept-language": "" */
#define GRPC_MDELEM_ACCEPT_LANGUAGE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[16], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_ACCEPT_LANGUAGE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[16].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "accept-ranges": "" */
#define GRPC_MDELEM_ACCEPT_RANGES_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[17], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_ACCEPT_RANGES_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[17].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "accept": "" */
#define GRPC_MDELEM_ACCEPT_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[18], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_ACCEPT_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[18].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "access-control-allow-origin": "" */
#define GRPC_MDELEM_ACCESS_CONTROL_ALLOW_ORIGIN_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[19], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_ACCESS_CONTROL_ALLOW_ORIGIN_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[19].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "age": "" */
#define GRPC_MDELEM_AGE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[20], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_AGE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[20].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "allow": "" */
#define GRPC_MDELEM_ALLOW_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[21], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_ALLOW_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[21].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "authorization": "" */
#define GRPC_MDELEM_AUTHORIZATION_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[22], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_AUTHORIZATION_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[22].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "cache-control": "" */
#define GRPC_MDELEM_CACHE_CONTROL_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[23], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_CACHE_CONTROL_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[23].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "content-disposition": "" */
#define GRPC_MDELEM_CONTENT_DISPOSITION_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[24], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_CONTENT_DISPOSITION_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[24].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "content-encoding": "" */
#define GRPC_MDELEM_CONTENT_ENCODING_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[25], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_CONTENT_ENCODING_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[25].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "content-language": "" */
#define GRPC_MDELEM_CONTENT_LANGUAGE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[26], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_CONTENT_LANGUAGE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[26].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "content-length": "" */
#define GRPC_MDELEM_CONTENT_LENGTH_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[27], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_CONTENT_LENGTH_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[27].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "content-location": "" */
#define GRPC_MDELEM_CONTENT_LOCATION_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[28], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_CONTENT_LOCATION_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[28].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "content-range": "" */
#define GRPC_MDELEM_CONTENT_RANGE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[29], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_CONTENT_RANGE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[29].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "content-type": "" */
#define GRPC_MDELEM_CONTENT_TYPE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[30], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_CONTENT_TYPE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[30].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "cookie": "" */
#define GRPC_MDELEM_COOKIE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[31], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_COOKIE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[31].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "date": "" */
#define GRPC_MDELEM_DATE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[32], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_DATE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[32].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "etag": "" */
#define GRPC_MDELEM_ETAG_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[33], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_ETAG_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[33].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "expect": "" */
#define GRPC_MDELEM_EXPECT_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[34], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_EXPECT_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[34].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "expires": "" */
#define GRPC_MDELEM_EXPIRES_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[35], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_EXPIRES_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[35].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "from": "" */
#define GRPC_MDELEM_FROM_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[36], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_FROM_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[36].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "host": "" */
#define GRPC_MDELEM_HOST_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[37], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_HOST_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[37].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "if-match": "" */
#define GRPC_MDELEM_IF_MATCH_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[38], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_IF_MATCH_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[38].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "if-modified-since": "" */
#define GRPC_MDELEM_IF_MODIFIED_SINCE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[39], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_IF_MODIFIED_SINCE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[39].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "if-none-match": "" */
#define GRPC_MDELEM_IF_NONE_MATCH_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[40], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_IF_NONE_MATCH_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[40].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "if-range": "" */
#define GRPC_MDELEM_IF_RANGE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[41], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_IF_RANGE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[41].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "if-unmodified-since": "" */
#define GRPC_MDELEM_IF_UNMODIFIED_SINCE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[42], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_IF_UNMODIFIED_SINCE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[42].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "last-modified": "" */
#define GRPC_MDELEM_LAST_MODIFIED_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[43], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_LAST_MODIFIED_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[43].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "link": "" */
#define GRPC_MDELEM_LINK_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[44], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_LINK_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[44].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "location": "" */
#define GRPC_MDELEM_LOCATION_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[45], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_LOCATION_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[45].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "max-forwards": "" */
#define GRPC_MDELEM_MAX_FORWARDS_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[46], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_MAX_FORWARDS_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[46].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "proxy-authenticate": "" */
#define GRPC_MDELEM_PROXY_AUTHENTICATE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[47], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_PROXY_AUTHENTICATE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[47].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "proxy-authorization": "" */
#define GRPC_MDELEM_PROXY_AUTHORIZATION_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[48], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_PROXY_AUTHORIZATION_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[48].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "range": "" */
#define GRPC_MDELEM_RANGE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[49], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_RANGE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[49].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "referer": "" */
#define GRPC_MDELEM_REFERER_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[50], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_REFERER_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[50].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "refresh": "" */
#define GRPC_MDELEM_REFRESH_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[51], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_REFRESH_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[51].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "retry-after": "" */
#define GRPC_MDELEM_RETRY_AFTER_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[52], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_RETRY_AFTER_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[52].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "server": "" */
#define GRPC_MDELEM_SERVER_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[53], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_SERVER_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[53].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "set-cookie": "" */
#define GRPC_MDELEM_SET_COOKIE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[54], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_SET_COOKIE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[54].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "strict-transport-security": "" */
#define GRPC_MDELEM_STRICT_TRANSPORT_SECURITY_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[55], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_STRICT_TRANSPORT_SECURITY_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[55].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "transfer-encoding": "" */
#define GRPC_MDELEM_TRANSFER_ENCODING_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[56], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_TRANSFER_ENCODING_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[56].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "user-agent": "" */
#define GRPC_MDELEM_USER_AGENT_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[57], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_USER_AGENT_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[57].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "vary": "" */
#define GRPC_MDELEM_VARY_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[58], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_VARY_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[58].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "via": "" */
#define GRPC_MDELEM_VIA_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[59], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_VIA_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[59].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "www-authenticate": "" */
#define GRPC_MDELEM_WWW_AUTHENTICATE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[60], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_WWW_AUTHENTICATE_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[60].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "grpc-status": "0" */
#define GRPC_MDELEM_GRPC_STATUS_0 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[61], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_GRPC_STATUS_0 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[61].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "grpc-status": "1" */
#define GRPC_MDELEM_GRPC_STATUS_1 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[62], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_GRPC_STATUS_1 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[62].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "grpc-status": "2" */
#define GRPC_MDELEM_GRPC_STATUS_2 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[63], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_GRPC_STATUS_2 \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[63].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "grpc-encoding": "identity" */
#define GRPC_MDELEM_GRPC_ENCODING_IDENTITY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[64], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_GRPC_ENCODING_IDENTITY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[64].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "grpc-encoding": "gzip" */
#define GRPC_MDELEM_GRPC_ENCODING_GZIP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[65], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_GRPC_ENCODING_GZIP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[65].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "grpc-encoding": "deflate" */
#define GRPC_MDELEM_GRPC_ENCODING_DEFLATE \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[66], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_GRPC_ENCODING_DEFLATE \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[66].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "te": "trailers" */
#define GRPC_MDELEM_TE_TRAILERS \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[67], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_TE_TRAILERS \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[67].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "content-type": "application/grpc" */
#define GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[68], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[68].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":scheme": "grpc" */
#define GRPC_MDELEM_SCHEME_GRPC \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[69], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_SCHEME_GRPC \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[69].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* ":method": "PUT" */
#define GRPC_MDELEM_METHOD_PUT \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[70], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_METHOD_PUT \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[70].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "accept-encoding": "" */
#define GRPC_MDELEM_ACCEPT_ENCODING_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[71], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_ACCEPT_ENCODING_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[71].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "content-encoding": "identity" */
#define GRPC_MDELEM_CONTENT_ENCODING_IDENTITY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[72], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_CONTENT_ENCODING_IDENTITY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[72].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "content-encoding": "gzip" */
#define GRPC_MDELEM_CONTENT_ENCODING_GZIP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[73], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_CONTENT_ENCODING_GZIP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[73].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "lb-token": "" */
#define GRPC_MDELEM_LB_TOKEN_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[74], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_LB_TOKEN_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[74].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "lb-cost-bin": "" */
#define GRPC_MDELEM_LB_COST_BIN_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[75], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_LB_COST_BIN_EMPTY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[75].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "grpc-accept-encoding": "identity" */
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[76], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[76].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "grpc-accept-encoding": "deflate" */
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[77], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[77].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "grpc-accept-encoding": "identity,deflate" */
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[78], GRPC_MDELEM_STORAGE_STATIC))
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[78].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "grpc-accept-encoding": "gzip" */
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_GZIP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[79], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_GZIP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[79].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "grpc-accept-encoding": "identity,gzip" */
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_GZIP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[80], GRPC_MDELEM_STORAGE_STATIC))
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[80].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "grpc-accept-encoding": "deflate,gzip" */
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE_COMMA_GZIP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[81], GRPC_MDELEM_STORAGE_STATIC))
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[81].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "grpc-accept-encoding": "identity,deflate,gzip" */
#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[82], GRPC_MDELEM_STORAGE_STATIC))
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[82].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "accept-encoding": "identity" */
#define GRPC_MDELEM_ACCEPT_ENCODING_IDENTITY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[83], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_ACCEPT_ENCODING_IDENTITY \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[83].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "accept-encoding": "gzip" */
#define GRPC_MDELEM_ACCEPT_ENCODING_GZIP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[84], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_ACCEPT_ENCODING_GZIP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[84].data(), \
GRPC_MDELEM_STORAGE_STATIC))
/* "accept-encoding": "identity,gzip" */
#define GRPC_MDELEM_ACCEPT_ENCODING_IDENTITY_COMMA_GZIP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[85], GRPC_MDELEM_STORAGE_STATIC))
#define GRPC_MDELEM_ACCEPT_ENCODING_IDENTITY_COMMA_GZIP \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[85].data(), \
GRPC_MDELEM_STORAGE_STATIC))
grpc_mdelem grpc_static_mdelem_for_static_strings(intptr_t a, intptr_t b);
typedef enum {
@ -597,14 +684,16 @@ typedef union {
: 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( \
&grpc_static_mdelem_table[grpc_static_accept_encoding_metadata[(algs)]], \
#define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs) \
(GRPC_MAKE_MDELEM( \
&grpc_static_mdelem_table[grpc_static_accept_encoding_metadata[(algs)]] \
.data(), \
GRPC_MDELEM_STORAGE_STATIC))
extern const uint8_t grpc_static_accept_stream_encoding_metadata[4];
#define GRPC_MDELEM_ACCEPT_STREAM_ENCODING_FOR_ALGORITHMS(algs) \
(GRPC_MAKE_MDELEM(&grpc_static_mdelem_table \
[grpc_static_accept_stream_encoding_metadata[(algs)]], \
[grpc_static_accept_stream_encoding_metadata[(algs)]] \
.data(), \
GRPC_MDELEM_STORAGE_STATIC))
#endif /* GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H */

@ -42,14 +42,17 @@
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/surface/completion_queue.h"
namespace grpc {
static internal::GrpcLibraryInitializer g_gli_initializer;
Channel::Channel(
const grpc::string& host, grpc_channel* channel,
std::vector<
std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators)
void ::grpc::experimental::ChannelResetConnectionBackoff(Channel* channel) {
grpc_impl::experimental::ChannelResetConnectionBackoff(channel);
}
namespace grpc_impl {
static ::grpc::internal::GrpcLibraryInitializer g_gli_initializer;
Channel::Channel(const grpc::string& host, grpc_channel* channel,
std::vector<std::unique_ptr<
::grpc::experimental::ClientInterceptorFactoryInterface>>
interceptor_creators)
: host_(host), c_channel_(channel) {
interceptor_creators_ = std::move(interceptor_creators);
g_gli_initializer.summon();
@ -65,7 +68,8 @@ Channel::~Channel() {
namespace {
inline grpc_slice SliceFromArray(const char* arr, size_t len) {
return g_core_codegen_interface->grpc_slice_from_copied_buffer(arr, len);
return ::grpc::g_core_codegen_interface->grpc_slice_from_copied_buffer(arr,
len);
}
grpc::string GetChannelInfoField(grpc_channel* channel,
@ -103,10 +107,9 @@ void ChannelResetConnectionBackoff(Channel* channel) {
} // namespace experimental
internal::Call Channel::CreateCallInternal(const internal::RpcMethod& method,
ClientContext* context,
CompletionQueue* cq,
size_t interceptor_pos) {
::grpc::internal::Call Channel::CreateCallInternal(
const ::grpc::internal::RpcMethod& method, ::grpc::ClientContext* context,
::grpc::CompletionQueue* cq, size_t interceptor_pos) {
const bool kRegistered = method.channel_tag() && context->authority().empty();
grpc_call* c_call = nullptr;
if (kRegistered) {
@ -115,7 +118,7 @@ internal::Call Channel::CreateCallInternal(const internal::RpcMethod& method,
context->propagation_options_.c_bitmask(), cq->cq(),
method.channel_tag(), context->raw_deadline(), nullptr);
} else {
const string* host_str = nullptr;
const ::grpc::string* host_str = nullptr;
if (!context->authority_.empty()) {
host_str = &context->authority_;
} else if (!host_.empty()) {
@ -125,7 +128,7 @@ internal::Call Channel::CreateCallInternal(const internal::RpcMethod& method,
SliceFromArray(method.name(), strlen(method.name()));
grpc_slice host_slice;
if (host_str != nullptr) {
host_slice = SliceFromCopiedString(*host_str);
host_slice = ::grpc::SliceFromCopiedString(*host_str);
}
c_call = grpc_channel_create_call(
c_channel_, context->propagate_from_call_,
@ -147,17 +150,17 @@ internal::Call Channel::CreateCallInternal(const internal::RpcMethod& method,
interceptor_creators_, interceptor_pos);
context->set_call(c_call, shared_from_this());
return internal::Call(c_call, this, cq, info);
return ::grpc::internal::Call(c_call, this, cq, info);
}
::grpc::internal::Call Channel::CreateCall(const internal::RpcMethod& method,
ClientContext* context,
CompletionQueue* cq) {
::grpc::internal::Call Channel::CreateCall(
const ::grpc::internal::RpcMethod& method, ::grpc::ClientContext* context,
CompletionQueue* cq) {
return CreateCallInternal(method, context, cq, 0);
}
void Channel::PerformOpsOnCall(internal::CallOpSetInterface* ops,
internal::Call* call) {
void Channel::PerformOpsOnCall(::grpc::internal::CallOpSetInterface* ops,
::grpc::internal::Call* call) {
ops->FillOps(
call); // Make a copy of call. It's fine since Call just has pointers
}
@ -173,7 +176,7 @@ grpc_connectivity_state Channel::GetState(bool try_to_connect) {
namespace {
class TagSaver final : public internal::CompletionQueueTag {
class TagSaver final : public ::grpc::internal::CompletionQueueTag {
public:
explicit TagSaver(void* tag) : tag_(tag) {}
~TagSaver() override {}
@ -191,7 +194,7 @@ class TagSaver final : public internal::CompletionQueueTag {
void Channel::NotifyOnStateChangeImpl(grpc_connectivity_state last_observed,
gpr_timespec deadline,
CompletionQueue* cq, void* tag) {
::grpc::CompletionQueue* cq, void* tag) {
TagSaver* tag_saver = new TagSaver(tag);
grpc_channel_watch_connectivity_state(c_channel_, last_observed, deadline,
cq->cq(), tag_saver);
@ -199,7 +202,7 @@ void Channel::NotifyOnStateChangeImpl(grpc_connectivity_state last_observed,
bool Channel::WaitForStateChangeImpl(grpc_connectivity_state last_observed,
gpr_timespec deadline) {
CompletionQueue cq;
::grpc::CompletionQueue cq;
bool ok = false;
void* tag = nullptr;
NotifyOnStateChangeImpl(last_observed, deadline, &cq, nullptr);
@ -214,7 +217,7 @@ class ShutdownCallback : public grpc_experimental_completion_queue_functor {
ShutdownCallback() { functor_run = &ShutdownCallback::Run; }
// TakeCQ takes ownership of the cq into the shutdown callback
// so that the shutdown callback will be responsible for destroying it
void TakeCQ(CompletionQueue* cq) { cq_ = cq; }
void TakeCQ(::grpc::CompletionQueue* cq) { cq_ = cq; }
// The Run function will get invoked by the completion queue library
// when the shutdown is actually complete
@ -225,17 +228,17 @@ class ShutdownCallback : public grpc_experimental_completion_queue_functor {
}
private:
CompletionQueue* cq_ = nullptr;
::grpc::CompletionQueue* cq_ = nullptr;
};
} // namespace
CompletionQueue* Channel::CallbackCQ() {
::grpc::CompletionQueue* Channel::CallbackCQ() {
// TODO(vjpai): Consider using a single global CQ for the default CQ
// if there is no explicit per-channel CQ registered
grpc::internal::MutexLock l(&mu_);
if (callback_cq_ == nullptr) {
auto* shutdown_callback = new ShutdownCallback;
callback_cq_ = new CompletionQueue(grpc_completion_queue_attributes{
callback_cq_ = new ::grpc::CompletionQueue(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_CALLBACK, GRPC_CQ_DEFAULT_POLLING,
shutdown_callback});
@ -245,4 +248,4 @@ CompletionQueue* Channel::CallbackCQ() {
return callback_cq_;
}
} // namespace grpc
} // namespace grpc_impl

@ -31,6 +31,11 @@
#include <grpcpp/server_context.h>
#include <grpcpp/support/time.h>
namespace grpc_impl {
class Channel;
}
namespace grpc {
class DefaultGlobalClientCallbacks final
@ -83,8 +88,8 @@ void ClientContext::AddMetadata(const grpc::string& meta_key,
send_initial_metadata_.insert(std::make_pair(meta_key, meta_value));
}
void ClientContext::set_call(grpc_call* call,
const std::shared_ptr<Channel>& channel) {
void ClientContext::set_call(
grpc_call* call, const std::shared_ptr<::grpc_impl::Channel>& channel) {
grpc::internal::MutexLock lock(&mu_);
GPR_ASSERT(call_ == nullptr);
call_ = call;

@ -71,7 +71,7 @@ std::shared_ptr<grpc::Channel> CreateCustomChannelWithInterceptors(
interceptor_creators) {
return creds ? creds->CreateChannelWithInterceptors(
target, args, std::move(interceptor_creators))
: ::grpc::CreateChannelInternal(
: grpc::CreateChannelInternal(
"",
grpc_lame_client_channel_create(
nullptr, GRPC_STATUS_INVALID_ARGUMENT,

@ -26,8 +26,8 @@ namespace grpc {
std::shared_ptr<Channel> CreateChannelInternal(
const grpc::string& host, grpc_channel* c_channel,
std::vector<
std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
std::vector<std::unique_ptr<
::grpc::experimental::ClientInterceptorFactoryInterface>>
interceptor_creators) {
return std::shared_ptr<Channel>(
new Channel(host, c_channel, std::move(interceptor_creators)));

@ -30,8 +30,8 @@ namespace grpc {
std::shared_ptr<Channel> CreateChannelInternal(
const grpc::string& host, grpc_channel* c_channel,
std::vector<
std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
std::vector<std::unique_ptr<
::grpc::experimental::ClientInterceptorFactoryInterface>>
interceptor_creators);
} // namespace grpc

@ -34,7 +34,7 @@ std::shared_ptr<grpc::Channel> CreateInsecureChannelFromFd(
const grpc::string& target, int fd) {
grpc::internal::GrpcLibrary init_lib;
init_lib.init();
return grpc::CreateChannelInternal(
return ::grpc::CreateChannelInternal(
"", grpc_insecure_channel_create_from_fd(target.c_str(), fd, nullptr),
std::vector<std::unique_ptr<
grpc::experimental::ClientInterceptorFactoryInterface>>());
@ -46,7 +46,7 @@ std::shared_ptr<grpc::Channel> CreateCustomInsecureChannelFromFd(
init_lib.init();
grpc_channel_args channel_args;
args.SetChannelArgs(&channel_args);
return grpc::CreateChannelInternal(
return ::grpc::CreateChannelInternal(
"",
grpc_insecure_channel_create_from_fd(target.c_str(), fd, &channel_args),
std::vector<std::unique_ptr<
@ -65,7 +65,7 @@ CreateCustomInsecureChannelWithInterceptorsFromFd(
init_lib.init();
grpc_channel_args channel_args;
args.SetChannelArgs(&channel_args);
return grpc::CreateChannelInternal(
return ::grpc::CreateChannelInternal(
"",
grpc_insecure_channel_create_from_fd(target.c_str(), fd, &channel_args),
std::move(interceptor_creators));

@ -29,6 +29,8 @@
namespace grpc_impl {
class Channel;
class SecureChannelCredentials final : public ChannelCredentials {
public:
explicit SecureChannelCredentials(grpc_channel_credentials* c_creds);

@ -24,9 +24,9 @@
#include <grpcpp/impl/grpc_library.h>
#include <grpcpp/support/time.h>
namespace grpc {
namespace grpc_impl {
static internal::GrpcLibraryInitializer g_gli_initializer;
static ::grpc::internal::GrpcLibraryInitializer g_gli_initializer;
// 'CompletionQueue' constructor can safely call GrpcLibraryCodegen(false) here
// i.e not have GrpcLibraryCodegen call grpc_init(). This is because, to create
@ -52,7 +52,8 @@ CompletionQueue::NextStatus CompletionQueue::AsyncNextInternal(
case GRPC_QUEUE_SHUTDOWN:
return SHUTDOWN;
case GRPC_OP_COMPLETE:
auto core_cq_tag = static_cast<internal::CompletionQueueTag*>(ev.tag);
auto core_cq_tag =
static_cast<::grpc::internal::CompletionQueueTag*>(ev.tag);
*ok = ev.success != 0;
*tag = core_cq_tag;
if (core_cq_tag->FinalizeResult(tag, ok)) {
@ -79,7 +80,8 @@ bool CompletionQueue::CompletionQueueTLSCache::Flush(void** tag, bool* ok) {
flushed_ = true;
if (grpc_completion_queue_thread_local_cache_flush(cq_->cq_, &res_tag,
&res)) {
auto core_cq_tag = static_cast<internal::CompletionQueueTag*>(res_tag);
auto core_cq_tag =
static_cast<::grpc::internal::CompletionQueueTag*>(res_tag);
*ok = res == 1;
if (core_cq_tag->FinalizeResult(tag, ok)) {
return true;
@ -88,4 +90,4 @@ bool CompletionQueue::CompletionQueueTLSCache::Flush(void** tag, bool* ok) {
return false;
}
} // namespace grpc
} // namespace grpc_impl

@ -0,0 +1,40 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <grpc/grpc.h>
#include <grpcpp/support/validate_service_config.h>
#include "src/core/ext/filters/client_channel/service_config.h"
namespace grpc {
namespace experimental {
grpc::string ValidateServiceConfigJSON(
const grpc::string& service_config_json) {
grpc_init();
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::ServiceConfig::Create(service_config_json.c_str(), &error);
grpc::string return_value;
if (error != GRPC_ERROR_NONE) {
return_value = grpc_error_string(error);
GRPC_ERROR_UNREF(error);
}
grpc_shutdown();
return return_value;
}
} // namespace experimental
} // namespace grpc

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

@ -1,6 +1,6 @@
/*
*
* Copyright 2015 gRPC authors.
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,10 +16,19 @@
*
*/
#import <Foundation/Foundation.h>
#ifdef GRPC_COMPILE_WITH_CRONET
@interface Tests : NSObject
@end
#ifdef __cplusplus
extern "C" {
#endif
@implementation Tests
@end
/**
* Enable Cronet for once.
*/
void configureCronet(void);
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,39 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifdef GRPC_COMPILE_WITH_CRONET
#import "ConfigureCronet.h"
#import <Cronet/Cronet.h>
void configureCronet(void) {
static dispatch_once_t configureCronet;
dispatch_once(&configureCronet, ^{
NSLog(@"configureCronet()");
[Cronet setHttp2Enabled:YES];
[Cronet setSslKeyLogFileName:@"Documents/key"];
[Cronet enableTestCertVerifierForTesting];
NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask] lastObject];
NSLog(@"Documents directory: %@", url);
[Cronet start];
[Cronet startNetLogToFile:@"cronet_netlog.json" logBytes:YES];
});
}
#endif

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>gRPC.$(PRODUCT_NAME:rfc1034identifier)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

@ -49,6 +49,8 @@
#import <Cronet/Cronet.h>
#include <grpc/grpc_cronet.h>
#import "../ConfigureCronet.h"
typedef struct fullstack_secure_fixture_data {
char *localaddr;
} fullstack_secure_fixture_data;
@ -176,13 +178,7 @@ static char *roots_filename;
grpc_init();
[Cronet setHttp2Enabled:YES];
[Cronet enableTestCertVerifierForTesting];
NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask] lastObject];
NSLog(@"Documents directory: %@", url);
[Cronet start];
[Cronet startNetLogToFile:@"cronet_netlog.json" logBytes:YES];
configureCronet();
}
// The tearDown() function is run after all test cases finish running

@ -20,6 +20,8 @@
#import <netinet/in.h>
#import <sys/socket.h>
#import "../ConfigureCronet.h"
#import <Cronet/Cronet.h>
#import <grpc/grpc.h>
#import <grpc/grpc_cronet.h>
@ -37,6 +39,7 @@
#import "test/core/end2end/data/ssl_test_data.h"
#import "test/core/util/test_config.h"
#define GRPC_SHADOW_BORINGSSL_SYMBOLS
#import "src/core/tsi/grpc_shadow_boringssl.h"
#import <openssl_grpc/ssl.h>
@ -61,16 +64,7 @@ static void drain_cq(grpc_completion_queue *cq) {
grpc_test_init(1, argv);
grpc_init();
[Cronet setHttp2Enabled:YES];
[Cronet setSslKeyLogFileName:@"Documents/key"];
[Cronet enableTestCertVerifierForTesting];
NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask] lastObject];
NSLog(@"Documents directory: %@", url);
[Cronet start];
[Cronet startNetLogToFile:@"Documents/cronet_netlog.json" logBytes:YES];
configureCronet();
init_ssl();
}

@ -44,6 +44,10 @@ static int32_t kRemoteInteropServerOverhead = 12;
return kRemoteSSLHost;
}
+ (BOOL)useCronet {
return YES;
}
- (int32_t)encodingOverhead {
return kRemoteInteropServerOverhead; // bytes
}

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

@ -59,4 +59,9 @@
*/
+ (NSString *)hostNameOverride;
/**
* Whether to use Cronet for all the v1 API tests in the test suite.
*/
+ (BOOL)useCronet;
@end

@ -36,6 +36,9 @@
#import <grpc/grpc.h>
#import <grpc/support/log.h>
#import "../ConfigureCronet.h"
#import "InteropTestsBlockCallbacks.h"
#define TEST_TIMEOUT 32
extern const char *kCFStreamVarName;
@ -76,81 +79,6 @@ BOOL isRemoteInteropTest(NSString *host) {
return [host isEqualToString:@"grpc-test.sandbox.googleapis.com"];
}
// Convenience class to use blocks as callbacks
@interface InteropTestsBlockCallbacks : NSObject<GRPCProtoResponseHandler>
- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
messageCallback:(void (^)(id))messageCallback
closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback
writeMessageCallback:(void (^)(void))writeMessageCallback;
- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
messageCallback:(void (^)(id))messageCallback
closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback;
@end
@implementation InteropTestsBlockCallbacks {
void (^_initialMetadataCallback)(NSDictionary *);
void (^_messageCallback)(id);
void (^_closeCallback)(NSDictionary *, NSError *);
void (^_writeMessageCallback)(void);
dispatch_queue_t _dispatchQueue;
}
- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
messageCallback:(void (^)(id))messageCallback
closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback
writeMessageCallback:(void (^)(void))writeMessageCallback {
if ((self = [super init])) {
_initialMetadataCallback = initialMetadataCallback;
_messageCallback = messageCallback;
_closeCallback = closeCallback;
_writeMessageCallback = writeMessageCallback;
_dispatchQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL);
}
return self;
}
- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
messageCallback:(void (^)(id))messageCallback
closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback {
return [self initWithInitialMetadataCallback:initialMetadataCallback
messageCallback:messageCallback
closeCallback:closeCallback
writeMessageCallback:nil];
}
- (void)didReceiveInitialMetadata:(NSDictionary *)initialMetadata {
if (_initialMetadataCallback) {
_initialMetadataCallback(initialMetadata);
}
}
- (void)didReceiveProtoMessage:(GPBMessage *)message {
if (_messageCallback) {
_messageCallback(message);
}
}
- (void)didCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error {
if (_closeCallback) {
_closeCallback(trailingMetadata, error);
}
}
- (void)didWriteMessage {
if (_writeMessageCallback) {
_writeMessageCallback();
}
}
- (dispatch_queue_t)dispatchQueue {
return _dispatchQueue;
}
@end
#pragma mark Tests
@implementation InteropTests {
@ -180,13 +108,17 @@ BOOL isRemoteInteropTest(NSString *host) {
return nil;
}
+ (BOOL)useCronet {
return NO;
}
+ (void)setUp {
NSLog(@"InteropTest Started, class: %@", [[self class] description]);
#ifdef GRPC_COMPILE_WITH_CRONET
// Cronet setup
[Cronet setHttp2Enabled:YES];
[Cronet start];
[GRPCCall useCronetWithEngine:[Cronet getGlobalEngine]];
configureCronet();
if ([self useCronet]) {
[GRPCCall useCronetWithEngine:[Cronet getGlobalEngine]];
}
#endif
#ifdef GRPC_CFSTREAM
setenv(kCFStreamVarName, "1", 1);

@ -0,0 +1,33 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#import <ProtoRPC/ProtoRPC.h>
// Convenience class to use blocks as callbacks
@interface InteropTestsBlockCallbacks : NSObject<GRPCProtoResponseHandler>
- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
messageCallback:(void (^)(id))messageCallback
closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback
writeMessageCallback:(void (^)(void))writeMessageCallback;
- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
messageCallback:(void (^)(id))messageCallback
closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback;
@end

@ -0,0 +1,80 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#import "InteropTestsBlockCallbacks.h"
@implementation InteropTestsBlockCallbacks {
void (^_initialMetadataCallback)(NSDictionary *);
void (^_messageCallback)(id);
void (^_closeCallback)(NSDictionary *, NSError *);
void (^_writeMessageCallback)(void);
dispatch_queue_t _dispatchQueue;
}
- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
messageCallback:(void (^)(id))messageCallback
closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback
writeMessageCallback:(void (^)(void))writeMessageCallback {
if ((self = [super init])) {
_initialMetadataCallback = initialMetadataCallback;
_messageCallback = messageCallback;
_closeCallback = closeCallback;
_writeMessageCallback = writeMessageCallback;
_dispatchQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL);
}
return self;
}
- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
messageCallback:(void (^)(id))messageCallback
closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback {
return [self initWithInitialMetadataCallback:initialMetadataCallback
messageCallback:messageCallback
closeCallback:closeCallback
writeMessageCallback:nil];
}
- (void)didReceiveInitialMetadata:(NSDictionary *)initialMetadata {
if (_initialMetadataCallback) {
_initialMetadataCallback(initialMetadata);
}
}
- (void)didReceiveProtoMessage:(GPBMessage *)message {
if (_messageCallback) {
_messageCallback(message);
}
}
- (void)didCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error {
if (_closeCallback) {
_closeCallback(trailingMetadata, error);
}
}
- (void)didWriteMessage {
if (_writeMessageCallback) {
_writeMessageCallback();
}
}
- (dispatch_queue_t)dispatchQueue {
return _dispatchQueue;
}
@end

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

Loading…
Cancel
Save