aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--BUILD16
-rw-r--r--CMakeLists.txt6
-rw-r--r--Makefile7
-rw-r--r--binding.gyp2
-rw-r--r--build.yaml4
-rw-r--r--config.m42
-rw-r--r--doc/core/pending_api_cleanups.md2
-rw-r--r--doc/cpp/pending_api_cleanups.md15
-rw-r--r--gRPC-Core.podspec6
-rwxr-xr-xgrpc.gemspec4
-rw-r--r--include/grpc++/impl/codegen/client_context.h20
-rw-r--r--include/grpc/impl/codegen/grpc_types.h20
-rw-r--r--package.xml4
-rw-r--r--src/core/ext/client_config/client_channel.c94
-rw-r--r--src/core/ext/client_config/method_config.c286
-rw-r--r--src/core/ext/client_config/method_config.h97
-rw-r--r--src/core/ext/client_config/resolver_result.h9
-rw-r--r--src/core/ext/client_config/subchannel.c4
-rw-r--r--src/core/ext/client_config/subchannel.h3
-rw-r--r--src/core/ext/lb_policy/grpclb/grpclb.c5
-rw-r--r--src/core/ext/lb_policy/pick_first/pick_first.c1
-rw-r--r--src/core/ext/lb_policy/round_robin/round_robin.c1
-rw-r--r--src/core/ext/resolver/sockaddr/sockaddr_resolver.c21
-rw-r--r--src/core/lib/channel/channel_args.c12
-rw-r--r--src/core/lib/channel/channel_args.h4
-rw-r--r--src/core/lib/channel/channel_stack.c3
-rw-r--r--src/core/lib/channel/channel_stack.h3
-rw-r--r--src/core/lib/channel/deadline_filter.c14
-rw-r--r--src/core/lib/channel/deadline_filter.h5
-rw-r--r--src/core/lib/channel/message_size_filter.c60
-rw-r--r--src/core/lib/surface/call.c8
-rw-r--r--src/core/lib/transport/hashtable.c139
-rw-r--r--src/core/lib/transport/hashtable.h82
-rw-r--r--src/cpp/client/client_context.cc3
-rw-r--r--src/python/grpcio/grpc_core_dependencies.py2
-rw-r--r--test/core/client_config/resolvers/sockaddr_resolver_test.c84
-rw-r--r--test/core/end2end/fake_resolver.c49
-rw-r--r--test/cpp/end2end/client_crash_test.cc4
-rw-r--r--test/cpp/end2end/hybrid_end2end_test.cc10
-rw-r--r--test/cpp/end2end/server_crash_test_client.cc2
-rw-r--r--test/cpp/qps/driver.cc6
-rw-r--r--tools/doxygen/Doxyfile.core.internal4
-rw-r--r--tools/run_tests/sources_and_headers.json6
-rw-r--r--vsprojects/vcxproj/grpc/grpc.vcxproj6
-rw-r--r--vsprojects/vcxproj/grpc/grpc.vcxproj.filters12
-rw-r--r--vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj3
-rw-r--r--vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters6
-rw-r--r--vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj6
-rw-r--r--vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters12
49 files changed, 1098 insertions, 76 deletions
diff --git a/BUILD b/BUILD
index 4763bc0abd..c8581d2fd4 100644
--- a/BUILD
+++ b/BUILD
@@ -239,6 +239,7 @@ cc_library(
"src/core/lib/surface/server.h",
"src/core/lib/transport/byte_stream.h",
"src/core/lib/transport/connectivity_state.h",
+ "src/core/lib/transport/hashtable.h",
"src/core/lib/transport/metadata.h",
"src/core/lib/transport/metadata_batch.h",
"src/core/lib/transport/static_metadata.h",
@@ -298,6 +299,7 @@ cc_library(
"src/core/ext/client_config/lb_policy.h",
"src/core/ext/client_config/lb_policy_factory.h",
"src/core/ext/client_config/lb_policy_registry.h",
+ "src/core/ext/client_config/method_config.h",
"src/core/ext/client_config/parse_address.h",
"src/core/ext/client_config/resolver.h",
"src/core/ext/client_config/resolver_factory.h",
@@ -409,6 +411,7 @@ cc_library(
"src/core/lib/surface/version.c",
"src/core/lib/transport/byte_stream.c",
"src/core/lib/transport/connectivity_state.c",
+ "src/core/lib/transport/hashtable.c",
"src/core/lib/transport/metadata.c",
"src/core/lib/transport/metadata_batch.c",
"src/core/lib/transport/static_metadata.c",
@@ -478,6 +481,7 @@ cc_library(
"src/core/ext/client_config/lb_policy.c",
"src/core/ext/client_config/lb_policy_factory.c",
"src/core/ext/client_config/lb_policy_registry.c",
+ "src/core/ext/client_config/method_config.c",
"src/core/ext/client_config/parse_address.c",
"src/core/ext/client_config/resolver.c",
"src/core/ext/client_config/resolver_factory.c",
@@ -640,6 +644,7 @@ cc_library(
"src/core/lib/surface/server.h",
"src/core/lib/transport/byte_stream.h",
"src/core/lib/transport/connectivity_state.h",
+ "src/core/lib/transport/hashtable.h",
"src/core/lib/transport/metadata.h",
"src/core/lib/transport/metadata_batch.h",
"src/core/lib/transport/static_metadata.h",
@@ -676,6 +681,7 @@ cc_library(
"src/core/ext/client_config/lb_policy.h",
"src/core/ext/client_config/lb_policy_factory.h",
"src/core/ext/client_config/lb_policy_registry.h",
+ "src/core/ext/client_config/method_config.h",
"src/core/ext/client_config/parse_address.h",
"src/core/ext/client_config/resolver.h",
"src/core/ext/client_config/resolver_factory.h",
@@ -795,6 +801,7 @@ cc_library(
"src/core/lib/surface/version.c",
"src/core/lib/transport/byte_stream.c",
"src/core/lib/transport/connectivity_state.c",
+ "src/core/lib/transport/hashtable.c",
"src/core/lib/transport/metadata.c",
"src/core/lib/transport/metadata_batch.c",
"src/core/lib/transport/static_metadata.c",
@@ -838,6 +845,7 @@ cc_library(
"src/core/ext/client_config/lb_policy.c",
"src/core/ext/client_config/lb_policy_factory.c",
"src/core/ext/client_config/lb_policy_registry.c",
+ "src/core/ext/client_config/method_config.c",
"src/core/ext/client_config/parse_address.c",
"src/core/ext/client_config/resolver.c",
"src/core/ext/client_config/resolver_factory.c",
@@ -996,6 +1004,7 @@ cc_library(
"src/core/lib/surface/server.h",
"src/core/lib/transport/byte_stream.h",
"src/core/lib/transport/connectivity_state.h",
+ "src/core/lib/transport/hashtable.h",
"src/core/lib/transport/metadata.h",
"src/core/lib/transport/metadata_batch.h",
"src/core/lib/transport/static_metadata.h",
@@ -1031,6 +1040,7 @@ cc_library(
"src/core/ext/client_config/lb_policy.h",
"src/core/ext/client_config/lb_policy_factory.h",
"src/core/ext/client_config/lb_policy_registry.h",
+ "src/core/ext/client_config/method_config.h",
"src/core/ext/client_config/parse_address.h",
"src/core/ext/client_config/resolver.h",
"src/core/ext/client_config/resolver_factory.h",
@@ -1143,6 +1153,7 @@ cc_library(
"src/core/lib/surface/version.c",
"src/core/lib/transport/byte_stream.c",
"src/core/lib/transport/connectivity_state.c",
+ "src/core/lib/transport/hashtable.c",
"src/core/lib/transport/metadata.c",
"src/core/lib/transport/metadata_batch.c",
"src/core/lib/transport/static_metadata.c",
@@ -1186,6 +1197,7 @@ cc_library(
"src/core/ext/client_config/lb_policy.c",
"src/core/ext/client_config/lb_policy_factory.c",
"src/core/ext/client_config/lb_policy_registry.c",
+ "src/core/ext/client_config/method_config.c",
"src/core/ext/client_config/parse_address.c",
"src/core/ext/client_config/resolver.c",
"src/core/ext/client_config/resolver_factory.c",
@@ -1903,6 +1915,7 @@ objc_library(
"src/core/lib/surface/version.c",
"src/core/lib/transport/byte_stream.c",
"src/core/lib/transport/connectivity_state.c",
+ "src/core/lib/transport/hashtable.c",
"src/core/lib/transport/metadata.c",
"src/core/lib/transport/metadata_batch.c",
"src/core/lib/transport/static_metadata.c",
@@ -1972,6 +1985,7 @@ objc_library(
"src/core/ext/client_config/lb_policy.c",
"src/core/ext/client_config/lb_policy_factory.c",
"src/core/ext/client_config/lb_policy_registry.c",
+ "src/core/ext/client_config/method_config.c",
"src/core/ext/client_config/parse_address.c",
"src/core/ext/client_config/resolver.c",
"src/core/ext/client_config/resolver_factory.c",
@@ -2113,6 +2127,7 @@ objc_library(
"src/core/lib/surface/server.h",
"src/core/lib/transport/byte_stream.h",
"src/core/lib/transport/connectivity_state.h",
+ "src/core/lib/transport/hashtable.h",
"src/core/lib/transport/metadata.h",
"src/core/lib/transport/metadata_batch.h",
"src/core/lib/transport/static_metadata.h",
@@ -2172,6 +2187,7 @@ objc_library(
"src/core/ext/client_config/lb_policy.h",
"src/core/ext/client_config/lb_policy_factory.h",
"src/core/ext/client_config/lb_policy_registry.h",
+ "src/core/ext/client_config/method_config.h",
"src/core/ext/client_config/parse_address.h",
"src/core/ext/client_config/resolver.h",
"src/core/ext/client_config/resolver_factory.h",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 97cedbe449..def25b41b8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -376,6 +376,7 @@ add_library(grpc
src/core/lib/surface/version.c
src/core/lib/transport/byte_stream.c
src/core/lib/transport/connectivity_state.c
+ src/core/lib/transport/hashtable.c
src/core/lib/transport/metadata.c
src/core/lib/transport/metadata_batch.c
src/core/lib/transport/static_metadata.c
@@ -445,6 +446,7 @@ add_library(grpc
src/core/ext/client_config/lb_policy.c
src/core/ext/client_config/lb_policy_factory.c
src/core/ext/client_config/lb_policy_registry.c
+ src/core/ext/client_config/method_config.c
src/core/ext/client_config/parse_address.c
src/core/ext/client_config/resolver.c
src/core/ext/client_config/resolver_factory.c
@@ -635,6 +637,7 @@ add_library(grpc_cronet
src/core/lib/surface/version.c
src/core/lib/transport/byte_stream.c
src/core/lib/transport/connectivity_state.c
+ src/core/lib/transport/hashtable.c
src/core/lib/transport/metadata.c
src/core/lib/transport/metadata_batch.c
src/core/lib/transport/static_metadata.c
@@ -678,6 +681,7 @@ add_library(grpc_cronet
src/core/ext/client_config/lb_policy.c
src/core/ext/client_config/lb_policy_factory.c
src/core/ext/client_config/lb_policy_registry.c
+ src/core/ext/client_config/method_config.c
src/core/ext/client_config/parse_address.c
src/core/ext/client_config/resolver.c
src/core/ext/client_config/resolver_factory.c
@@ -866,6 +870,7 @@ add_library(grpc_unsecure
src/core/lib/surface/version.c
src/core/lib/transport/byte_stream.c
src/core/lib/transport/connectivity_state.c
+ src/core/lib/transport/hashtable.c
src/core/lib/transport/metadata.c
src/core/lib/transport/metadata_batch.c
src/core/lib/transport/static_metadata.c
@@ -909,6 +914,7 @@ add_library(grpc_unsecure
src/core/ext/client_config/lb_policy.c
src/core/ext/client_config/lb_policy_factory.c
src/core/ext/client_config/lb_policy_registry.c
+ src/core/ext/client_config/method_config.c
src/core/ext/client_config/parse_address.c
src/core/ext/client_config/resolver.c
src/core/ext/client_config/resolver_factory.c
diff --git a/Makefile b/Makefile
index fc0c38f3c7..4a35aacd21 100644
--- a/Makefile
+++ b/Makefile
@@ -2613,6 +2613,7 @@ LIBGRPC_SRC = \
src/core/lib/surface/version.c \
src/core/lib/transport/byte_stream.c \
src/core/lib/transport/connectivity_state.c \
+ src/core/lib/transport/hashtable.c \
src/core/lib/transport/metadata.c \
src/core/lib/transport/metadata_batch.c \
src/core/lib/transport/static_metadata.c \
@@ -2682,6 +2683,7 @@ LIBGRPC_SRC = \
src/core/ext/client_config/lb_policy.c \
src/core/ext/client_config/lb_policy_factory.c \
src/core/ext/client_config/lb_policy_registry.c \
+ src/core/ext/client_config/method_config.c \
src/core/ext/client_config/parse_address.c \
src/core/ext/client_config/resolver.c \
src/core/ext/client_config/resolver_factory.c \
@@ -2890,6 +2892,7 @@ LIBGRPC_CRONET_SRC = \
src/core/lib/surface/version.c \
src/core/lib/transport/byte_stream.c \
src/core/lib/transport/connectivity_state.c \
+ src/core/lib/transport/hashtable.c \
src/core/lib/transport/metadata.c \
src/core/lib/transport/metadata_batch.c \
src/core/lib/transport/static_metadata.c \
@@ -2933,6 +2936,7 @@ LIBGRPC_CRONET_SRC = \
src/core/ext/client_config/lb_policy.c \
src/core/ext/client_config/lb_policy_factory.c \
src/core/ext/client_config/lb_policy_registry.c \
+ src/core/ext/client_config/method_config.c \
src/core/ext/client_config/parse_address.c \
src/core/ext/client_config/resolver.c \
src/core/ext/client_config/resolver_factory.c \
@@ -3157,6 +3161,7 @@ LIBGRPC_TEST_UTIL_SRC = \
src/core/lib/surface/version.c \
src/core/lib/transport/byte_stream.c \
src/core/lib/transport/connectivity_state.c \
+ src/core/lib/transport/hashtable.c \
src/core/lib/transport/metadata.c \
src/core/lib/transport/metadata_batch.c \
src/core/lib/transport/static_metadata.c \
@@ -3351,6 +3356,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/surface/version.c \
src/core/lib/transport/byte_stream.c \
src/core/lib/transport/connectivity_state.c \
+ src/core/lib/transport/hashtable.c \
src/core/lib/transport/metadata.c \
src/core/lib/transport/metadata_batch.c \
src/core/lib/transport/static_metadata.c \
@@ -3394,6 +3400,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/ext/client_config/lb_policy.c \
src/core/ext/client_config/lb_policy_factory.c \
src/core/ext/client_config/lb_policy_registry.c \
+ src/core/ext/client_config/method_config.c \
src/core/ext/client_config/parse_address.c \
src/core/ext/client_config/resolver.c \
src/core/ext/client_config/resolver_factory.c \
diff --git a/binding.gyp b/binding.gyp
index 58edda2e63..88acd1786b 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -651,6 +651,7 @@
'src/core/lib/surface/version.c',
'src/core/lib/transport/byte_stream.c',
'src/core/lib/transport/connectivity_state.c',
+ 'src/core/lib/transport/hashtable.c',
'src/core/lib/transport/metadata.c',
'src/core/lib/transport/metadata_batch.c',
'src/core/lib/transport/static_metadata.c',
@@ -720,6 +721,7 @@
'src/core/ext/client_config/lb_policy.c',
'src/core/ext/client_config/lb_policy_factory.c',
'src/core/ext/client_config/lb_policy_registry.c',
+ 'src/core/ext/client_config/method_config.c',
'src/core/ext/client_config/parse_address.c',
'src/core/ext/client_config/resolver.c',
'src/core/ext/client_config/resolver_factory.c',
diff --git a/build.yaml b/build.yaml
index 9e8b4c3304..10278c577b 100644
--- a/build.yaml
+++ b/build.yaml
@@ -243,6 +243,7 @@ filegroups:
- src/core/lib/surface/server.h
- src/core/lib/transport/byte_stream.h
- src/core/lib/transport/connectivity_state.h
+ - src/core/lib/transport/hashtable.h
- src/core/lib/transport/metadata.h
- src/core/lib/transport/metadata_batch.h
- src/core/lib/transport/static_metadata.h
@@ -336,6 +337,7 @@ filegroups:
- src/core/lib/surface/version.c
- src/core/lib/transport/byte_stream.c
- src/core/lib/transport/connectivity_state.c
+ - src/core/lib/transport/hashtable.c
- src/core/lib/transport/metadata.c
- src/core/lib/transport/metadata_batch.c
- src/core/lib/transport/static_metadata.c
@@ -356,6 +358,7 @@ filegroups:
- src/core/ext/client_config/lb_policy.h
- src/core/ext/client_config/lb_policy_factory.h
- src/core/ext/client_config/lb_policy_registry.h
+ - src/core/ext/client_config/method_config.h
- src/core/ext/client_config/parse_address.h
- src/core/ext/client_config/resolver.h
- src/core/ext/client_config/resolver_factory.h
@@ -376,6 +379,7 @@ filegroups:
- src/core/ext/client_config/lb_policy.c
- src/core/ext/client_config/lb_policy_factory.c
- src/core/ext/client_config/lb_policy_registry.c
+ - src/core/ext/client_config/method_config.c
- src/core/ext/client_config/parse_address.c
- src/core/ext/client_config/resolver.c
- src/core/ext/client_config/resolver_factory.c
diff --git a/config.m4 b/config.m4
index 0f103655a8..f65f617f9a 100644
--- a/config.m4
+++ b/config.m4
@@ -170,6 +170,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/surface/version.c \
src/core/lib/transport/byte_stream.c \
src/core/lib/transport/connectivity_state.c \
+ src/core/lib/transport/hashtable.c \
src/core/lib/transport/metadata.c \
src/core/lib/transport/metadata_batch.c \
src/core/lib/transport/static_metadata.c \
@@ -239,6 +240,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/client_config/lb_policy.c \
src/core/ext/client_config/lb_policy_factory.c \
src/core/ext/client_config/lb_policy_registry.c \
+ src/core/ext/client_config/method_config.c \
src/core/ext/client_config/parse_address.c \
src/core/ext/client_config/resolver.c \
src/core/ext/client_config/resolver_factory.c \
diff --git a/doc/core/pending_api_cleanups.md b/doc/core/pending_api_cleanups.md
index a12e8a9dfb..a0a960e5e2 100644
--- a/doc/core/pending_api_cleanups.md
+++ b/doc/core/pending_api_cleanups.md
@@ -15,3 +15,5 @@ number:
`include/grpc/impl/codegen/grpc_types.h` (commit `af00d8b`)
- remove `ServerBuilder::SetMaxMessageSize()` method from
`include/grpc++/server_builder.h` (commit `6980362`)
+- remove `GRPC_INITIAL_METADATA_IGNORE_CONNECTIVITY` macro from
+ `include/grpc/impl/codegen/grpc_types.h` (commit `59c9f90`)
diff --git a/doc/cpp/pending_api_cleanups.md b/doc/cpp/pending_api_cleanups.md
new file mode 100644
index 0000000000..3e77b657c6
--- /dev/null
+++ b/doc/cpp/pending_api_cleanups.md
@@ -0,0 +1,15 @@
+There are times when we make changes that include a temporary shim for
+backward-compatibility (e.g., a macro or some other function to preserve
+the original API) to avoid having to bump the major version number in
+the next release. However, when we do eventually want to release a
+feature that does change the API in a non-backward-compatible way, we
+will wind up bumping the major version number anyway, at which point we
+can take the opportunity to clean up any pending backward-compatibility
+shims.
+
+This file lists all pending backward-compatibility changes that should
+be cleaned up the next time we are going to bump the major version
+number:
+
+- remove `ClientContext::set_fail_fast()` method from
+ `include/grpc++/impl/codegen/client_context.h` (commit `9477724`)
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 6886bdfb5a..ffa7ca0825 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -326,6 +326,7 @@ Pod::Spec.new do |s|
'src/core/lib/surface/server.h',
'src/core/lib/transport/byte_stream.h',
'src/core/lib/transport/connectivity_state.h',
+ 'src/core/lib/transport/hashtable.h',
'src/core/lib/transport/metadata.h',
'src/core/lib/transport/metadata_batch.h',
'src/core/lib/transport/static_metadata.h',
@@ -385,6 +386,7 @@ Pod::Spec.new do |s|
'src/core/ext/client_config/lb_policy.h',
'src/core/ext/client_config/lb_policy_factory.h',
'src/core/ext/client_config/lb_policy_registry.h',
+ 'src/core/ext/client_config/method_config.h',
'src/core/ext/client_config/parse_address.h',
'src/core/ext/client_config/resolver.h',
'src/core/ext/client_config/resolver_factory.h',
@@ -500,6 +502,7 @@ Pod::Spec.new do |s|
'src/core/lib/surface/version.c',
'src/core/lib/transport/byte_stream.c',
'src/core/lib/transport/connectivity_state.c',
+ 'src/core/lib/transport/hashtable.c',
'src/core/lib/transport/metadata.c',
'src/core/lib/transport/metadata_batch.c',
'src/core/lib/transport/static_metadata.c',
@@ -569,6 +572,7 @@ Pod::Spec.new do |s|
'src/core/ext/client_config/lb_policy.c',
'src/core/ext/client_config/lb_policy_factory.c',
'src/core/ext/client_config/lb_policy_registry.c',
+ 'src/core/ext/client_config/method_config.c',
'src/core/ext/client_config/parse_address.c',
'src/core/ext/client_config/resolver.c',
'src/core/ext/client_config/resolver_factory.c',
@@ -699,6 +703,7 @@ Pod::Spec.new do |s|
'src/core/lib/surface/server.h',
'src/core/lib/transport/byte_stream.h',
'src/core/lib/transport/connectivity_state.h',
+ 'src/core/lib/transport/hashtable.h',
'src/core/lib/transport/metadata.h',
'src/core/lib/transport/metadata_batch.h',
'src/core/lib/transport/static_metadata.h',
@@ -758,6 +763,7 @@ Pod::Spec.new do |s|
'src/core/ext/client_config/lb_policy.h',
'src/core/ext/client_config/lb_policy_factory.h',
'src/core/ext/client_config/lb_policy_registry.h',
+ 'src/core/ext/client_config/method_config.h',
'src/core/ext/client_config/parse_address.h',
'src/core/ext/client_config/resolver.h',
'src/core/ext/client_config/resolver_factory.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index 6079ea2aef..e547811332 100755
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -246,6 +246,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/surface/server.h )
s.files += %w( src/core/lib/transport/byte_stream.h )
s.files += %w( src/core/lib/transport/connectivity_state.h )
+ s.files += %w( src/core/lib/transport/hashtable.h )
s.files += %w( src/core/lib/transport/metadata.h )
s.files += %w( src/core/lib/transport/metadata_batch.h )
s.files += %w( src/core/lib/transport/static_metadata.h )
@@ -305,6 +306,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/client_config/lb_policy.h )
s.files += %w( src/core/ext/client_config/lb_policy_factory.h )
s.files += %w( src/core/ext/client_config/lb_policy_registry.h )
+ s.files += %w( src/core/ext/client_config/method_config.h )
s.files += %w( src/core/ext/client_config/parse_address.h )
s.files += %w( src/core/ext/client_config/resolver.h )
s.files += %w( src/core/ext/client_config/resolver_factory.h )
@@ -420,6 +422,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/surface/version.c )
s.files += %w( src/core/lib/transport/byte_stream.c )
s.files += %w( src/core/lib/transport/connectivity_state.c )
+ s.files += %w( src/core/lib/transport/hashtable.c )
s.files += %w( src/core/lib/transport/metadata.c )
s.files += %w( src/core/lib/transport/metadata_batch.c )
s.files += %w( src/core/lib/transport/static_metadata.c )
@@ -489,6 +492,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/client_config/lb_policy.c )
s.files += %w( src/core/ext/client_config/lb_policy_factory.c )
s.files += %w( src/core/ext/client_config/lb_policy_registry.c )
+ s.files += %w( src/core/ext/client_config/method_config.c )
s.files += %w( src/core/ext/client_config/parse_address.c )
s.files += %w( src/core/ext/client_config/resolver.c )
s.files += %w( src/core/ext/client_config/resolver_factory.c )
diff --git a/include/grpc++/impl/codegen/client_context.h b/include/grpc++/impl/codegen/client_context.h
index 387d807c4b..a330ed06bb 100644
--- a/include/grpc++/impl/codegen/client_context.h
+++ b/include/grpc++/impl/codegen/client_context.h
@@ -226,8 +226,14 @@ class ClientContext {
/// EXPERIMENTAL: Set this request to be cacheable
void set_cacheable(bool cacheable) { cacheable_ = cacheable; }
- /// EXPERIMENTAL: Trigger fail-fast or not on this request
- void set_fail_fast(bool fail_fast) { fail_fast_ = fail_fast; }
+ /// EXPERIMENTAL: Trigger wait-for-ready or not on this request
+ void set_wait_for_ready(bool wait_for_ready) {
+ wait_for_ready_ = wait_for_ready;
+ wait_for_ready_explicitly_set_ = true;
+ }
+
+ /// DEPRECATED: Use set_wait_for_ready() instead.
+ void set_fail_fast(bool fail_fast) { set_wait_for_ready(!fail_fast); }
#ifndef GRPC_CXX0X_NO_CHRONO
/// Return the deadline for the client call.
@@ -347,14 +353,18 @@ class ClientContext {
uint32_t initial_metadata_flags() const {
return (idempotent_ ? GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST : 0) |
- (fail_fast_ ? 0 : GRPC_INITIAL_METADATA_IGNORE_CONNECTIVITY) |
- (cacheable_ ? GRPC_INITIAL_METADATA_CACHEABLE_REQUEST : 0);
+ (wait_for_ready_ ? GRPC_INITIAL_METADATA_WAIT_FOR_READY : 0) |
+ (cacheable_ ? GRPC_INITIAL_METADATA_CACHEABLE_REQUEST : 0) |
+ (wait_for_ready_explicitly_set_
+ ? GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET
+ : 0);
}
grpc::string authority() { return authority_; }
bool initial_metadata_received_;
- bool fail_fast_;
+ bool wait_for_ready_;
+ bool wait_for_ready_explicitly_set_;
bool idempotent_;
bool cacheable_;
std::shared_ptr<Channel> channel_;
diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h
index 07e7cff201..a3fc683e57 100644
--- a/include/grpc/impl/codegen/grpc_types.h
+++ b/include/grpc/impl/codegen/grpc_types.h
@@ -201,6 +201,9 @@ typedef struct {
#define GRPC_ARG_MAX_METADATA_SIZE "grpc.max_metadata_size"
/** If non-zero, allow the use of SO_REUSEPORT if it's available (default 1) */
#define GRPC_ARG_ALLOW_REUSEPORT "grpc.so_reuseport"
+/** Service config data, to be passed to subchannels.
+ Not intended for external use. */
+#define GRPC_ARG_SERVICE_CONFIG "grpc.service_config"
/** \} */
/** Result of a grpc call. If the caller satisfies the prerequisites of a
@@ -257,15 +260,22 @@ typedef enum grpc_call_error {
/** Signal that the call is idempotent */
#define GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST (0x00000010u)
/** Signal that the call should not return UNAVAILABLE before it has started */
-#define GRPC_INITIAL_METADATA_IGNORE_CONNECTIVITY (0x00000020u)
+#define GRPC_INITIAL_METADATA_WAIT_FOR_READY (0x00000020u)
+/** DEPRECATED: for backward compatibility */
+#define GRPC_INITIAL_METADATA_IGNORE_CONNECTIVITY \
+ GRPC_INITIAL_METADATA_WAIT_FOR_READY
/** Signal that the call is cacheable. GRPC is free to use GET verb */
#define GRPC_INITIAL_METADATA_CACHEABLE_REQUEST (0x00000040u)
+/** Signal that GRPC_INITIAL_METADATA_WAIT_FOR_READY was explicitly set
+ by the calling application. */
+#define GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET (0x00000080u)
/** Mask of all valid flags */
-#define GRPC_INITIAL_METADATA_USED_MASK \
- (GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST | \
- GRPC_INITIAL_METADATA_IGNORE_CONNECTIVITY | \
- GRPC_INITIAL_METADATA_CACHEABLE_REQUEST)
+#define GRPC_INITIAL_METADATA_USED_MASK \
+ (GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST | \
+ GRPC_INITIAL_METADATA_WAIT_FOR_READY | \
+ GRPC_INITIAL_METADATA_CACHEABLE_REQUEST | \
+ GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET)
/** A single metadata element */
typedef struct grpc_metadata {
diff --git a/package.xml b/package.xml
index 7bac695787..bf452c3b16 100644
--- a/package.xml
+++ b/package.xml
@@ -253,6 +253,7 @@
<file baseinstalldir="/" name="src/core/lib/surface/server.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/byte_stream.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/connectivity_state.h" role="src" />
+ <file baseinstalldir="/" name="src/core/lib/transport/hashtable.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/metadata.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/metadata_batch.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/static_metadata.h" role="src" />
@@ -312,6 +313,7 @@
<file baseinstalldir="/" name="src/core/ext/client_config/lb_policy.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_config/lb_policy_factory.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_config/lb_policy_registry.h" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/client_config/method_config.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_config/parse_address.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_config/resolver.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_config/resolver_factory.h" role="src" />
@@ -427,6 +429,7 @@
<file baseinstalldir="/" name="src/core/lib/surface/version.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/byte_stream.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/connectivity_state.c" role="src" />
+ <file baseinstalldir="/" name="src/core/lib/transport/hashtable.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/metadata.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/metadata_batch.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/static_metadata.c" role="src" />
@@ -496,6 +499,7 @@
<file baseinstalldir="/" name="src/core/ext/client_config/lb_policy.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_config/lb_policy_factory.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_config/lb_policy_registry.c" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/client_config/method_config.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_config/parse_address.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_config/resolver.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_config/resolver_factory.c" role="src" />
diff --git a/src/core/ext/client_config/client_channel.c b/src/core/ext/client_config/client_channel.c
index 31f435ef62..19b621296e 100644
--- a/src/core/ext/client_config/client_channel.c
+++ b/src/core/ext/client_config/client_channel.c
@@ -43,6 +43,7 @@
#include <grpc/support/useful.h>
#include "src/core/ext/client_config/lb_policy_registry.h"
+#include "src/core/ext/client_config/method_config.h"
#include "src/core/ext/client_config/subchannel.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/connected_channel.h"
@@ -53,6 +54,9 @@
#include "src/core/lib/support/string.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/transport/connectivity_state.h"
+#include "src/core/lib/transport/metadata.h"
+#include "src/core/lib/transport/metadata_batch.h"
+#include "src/core/lib/transport/static_metadata.h"
/* Client channel implementation */
@@ -68,12 +72,13 @@ typedef struct client_channel_channel_data {
/** client channel factory */
grpc_client_channel_factory *client_channel_factory;
- /** mutex protecting client configuration, including all
- variables below in this data structure */
+ /** mutex protecting all variables below in this data structure */
gpr_mu mu;
- /** currently active load balancer - guarded by mu */
+ /** currently active load balancer */
grpc_lb_policy *lb_policy;
- /** incoming resolver result - set by resolver.next(), guarded by mu */
+ /** method config table */
+ grpc_method_config_table *method_config_table;
+ /** incoming resolver result - set by resolver.next() */
grpc_resolver_result *resolver_result;
/** a list of closures that are all waiting for config to come in */
grpc_closure_list waiting_for_config_closures;
@@ -111,10 +116,10 @@ static void set_channel_connectivity_state_locked(grpc_exec_ctx *exec_ctx,
if ((state == GRPC_CHANNEL_TRANSIENT_FAILURE ||
state == GRPC_CHANNEL_SHUTDOWN) &&
chand->lb_policy != NULL) {
- /* cancel fail-fast picks */
+ /* cancel picks with wait_for_ready=false */
grpc_lb_policy_cancel_picks(
exec_ctx, chand->lb_policy,
- /* mask= */ GRPC_INITIAL_METADATA_IGNORE_CONNECTIVITY,
+ /* mask= */ GRPC_INITIAL_METADATA_WAIT_FOR_READY,
/* check= */ 0, GRPC_ERROR_REF(error));
}
grpc_connectivity_state_set(exec_ctx, &chand->state_tracker, state, error,
@@ -172,6 +177,7 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
channel_data *chand = arg;
grpc_lb_policy *lb_policy = NULL;
grpc_lb_policy *old_lb_policy;
+ grpc_method_config_table *method_config_table = NULL;
grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE;
bool exit_idle = false;
grpc_error *state_error = GRPC_ERROR_CREATE("No load balancing policy");
@@ -219,6 +225,13 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
state =
grpc_lb_policy_check_connectivity(exec_ctx, lb_policy, &state_error);
}
+ const grpc_arg *channel_arg = grpc_channel_args_find(
+ lb_policy_args.additional_args, GRPC_ARG_SERVICE_CONFIG);
+ if (channel_arg != NULL) {
+ GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER);
+ method_config_table = grpc_method_config_table_ref(
+ (grpc_method_config_table *)channel_arg->value.pointer.p);
+ }
grpc_resolver_result_unref(exec_ctx, chand->resolver_result);
chand->resolver_result = NULL;
}
@@ -231,6 +244,10 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
gpr_mu_lock(&chand->mu);
old_lb_policy = chand->lb_policy;
chand->lb_policy = lb_policy;
+ if (chand->method_config_table != NULL) {
+ grpc_method_config_table_unref(chand->method_config_table);
+ }
+ chand->method_config_table = method_config_table;
if (lb_policy != NULL) {
grpc_exec_ctx_enqueue_list(exec_ctx, &chand->waiting_for_config_closures,
NULL);
@@ -391,6 +408,9 @@ static void cc_destroy_channel_elem(grpc_exec_ctx *exec_ctx,
chand->interested_parties);
GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel");
}
+ if (chand->method_config_table != NULL) {
+ grpc_method_config_table_unref(chand->method_config_table);
+ }
grpc_connectivity_state_destroy(exec_ctx, &chand->state_tracker);
grpc_pollset_set_destroy(chand->interested_parties);
gpr_mu_destroy(&chand->mu);
@@ -425,6 +445,15 @@ typedef struct client_channel_call_data {
grpc_deadline_state deadline_state;
gpr_timespec deadline;
+ enum {
+ WAIT_FOR_READY_UNSET,
+ WAIT_FOR_READY_FALSE,
+ WAIT_FOR_READY_TRUE
+ } wait_for_ready_from_service_config;
+
+ // Request path.
+ grpc_mdstr *path;
+
grpc_error *cancel_error;
/** either 0 for no call, 1 for cancelled, or a pointer to a
@@ -527,10 +556,11 @@ static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg,
GRPC_ERROR_CREATE_REFERENCING(
"Cancelled before creating subchannel", &error, 1));
} else {
+ /* Create call on subchannel. */
grpc_subchannel_call *subchannel_call = NULL;
grpc_error *new_error = grpc_connected_subchannel_create_call(
- exec_ctx, calld->connected_subchannel, calld->pollent, calld->deadline,
- &subchannel_call);
+ exec_ctx, calld->connected_subchannel, calld->pollent, calld->path,
+ calld->deadline, &subchannel_call);
if (new_error != GRPC_ERROR_NONE) {
new_error = grpc_error_add_child(new_error, error);
subchannel_call = CANCELLED_CALL;
@@ -737,12 +767,24 @@ retry:
calld->connected_subchannel == NULL &&
op->send_initial_metadata != NULL) {
calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL;
+ // If the application explicitly set wait_for_ready, use that.
+ // Otherwise, if the service config specified a value for this
+ // method, use that.
+ uint32_t initial_metadata_flags = op->send_initial_metadata_flags;
+ if ((initial_metadata_flags &
+ GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET) == 0 &&
+ calld->wait_for_ready_from_service_config != WAIT_FOR_READY_UNSET) {
+ if (calld->wait_for_ready_from_service_config == WAIT_FOR_READY_TRUE) {
+ initial_metadata_flags |= GRPC_INITIAL_METADATA_WAIT_FOR_READY;
+ } else {
+ initial_metadata_flags &= ~GRPC_INITIAL_METADATA_WAIT_FOR_READY;
+ }
+ }
grpc_closure_init(&calld->next_step, subchannel_ready, calld);
GRPC_CALL_STACK_REF(calld->owning_call, "pick_subchannel");
if (pick_subchannel(exec_ctx, elem, op->send_initial_metadata,
- op->send_initial_metadata_flags,
- &calld->connected_subchannel, &calld->next_step,
- GRPC_ERROR_NONE)) {
+ initial_metadata_flags, &calld->connected_subchannel,
+ &calld->next_step, GRPC_ERROR_NONE)) {
calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, "pick_subchannel");
}
@@ -752,8 +794,8 @@ retry:
calld->connected_subchannel != NULL) {
grpc_subchannel_call *subchannel_call = NULL;
grpc_error *error = grpc_connected_subchannel_create_call(
- exec_ctx, calld->connected_subchannel, calld->pollent, calld->deadline,
- &subchannel_call);
+ exec_ctx, calld->connected_subchannel, calld->pollent, calld->path,
+ calld->deadline, &subchannel_call);
if (error != GRPC_ERROR_NONE) {
subchannel_call = CANCELLED_CALL;
fail_locked(exec_ctx, calld, GRPC_ERROR_REF(error));
@@ -774,9 +816,32 @@ retry:
static grpc_error *cc_init_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
grpc_call_element_args *args) {
+ channel_data *chand = elem->channel_data;
call_data *calld = elem->call_data;
- grpc_deadline_state_init(exec_ctx, elem, args);
+ gpr_mu_lock(&chand->mu);
+ grpc_method_config_table *method_config_table =
+ chand->method_config_table == NULL
+ ? NULL
+ : grpc_method_config_table_ref(chand->method_config_table);
+ gpr_mu_unlock(&chand->mu);
+ grpc_method_config *method_config =
+ method_config_table == NULL ? NULL
+ : grpc_method_config_table_get_method_config(
+ method_config_table, args->path);
+ grpc_deadline_state_init(exec_ctx, elem, args, method_config);
+ calld->wait_for_ready_from_service_config = WAIT_FOR_READY_UNSET;
+ if (method_config != NULL) {
+ bool *wait_for_ready = grpc_method_config_get_wait_for_ready(method_config);
+ if (wait_for_ready != NULL) {
+ calld->wait_for_ready_from_service_config =
+ *wait_for_ready ? WAIT_FOR_READY_TRUE : WAIT_FOR_READY_FALSE;
+ }
+ }
+ if (method_config_table != NULL) {
+ grpc_method_config_table_unref(method_config_table);
+ }
calld->deadline = args->deadline;
+ calld->path = GRPC_MDSTR_REF(args->path);
calld->cancel_error = GRPC_ERROR_NONE;
gpr_atm_rel_store(&calld->subchannel_call, 0);
gpr_mu_init(&calld->mu);
@@ -797,6 +862,7 @@ static void cc_destroy_call_elem(grpc_exec_ctx *exec_ctx,
void *and_free_memory) {
call_data *calld = elem->call_data;
grpc_deadline_state_destroy(exec_ctx, elem);
+ GRPC_MDSTR_UNREF(calld->path);
GRPC_ERROR_UNREF(calld->cancel_error);
grpc_subchannel_call *call = GET_CALL(calld);
if (call != NULL && call != CANCELLED_CALL) {
diff --git a/src/core/ext/client_config/method_config.c b/src/core/ext/client_config/method_config.c
new file mode 100644
index 0000000000..888b32c7f1
--- /dev/null
+++ b/src/core/ext/client_config/method_config.c
@@ -0,0 +1,286 @@
+//
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include "src/core/ext/client_config/method_config.h"
+
+#include <string.h>
+
+#include <grpc/impl/codegen/grpc_types.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/transport/hashtable.h"
+#include "src/core/lib/transport/metadata.h"
+
+//
+// grpc_method_config
+//
+
+// bool vtable
+
+static void* bool_copy(void* valuep) {
+ bool value = *(bool*)valuep;
+ bool* new_value = gpr_malloc(sizeof(bool));
+ *new_value = value;
+ return new_value;
+}
+
+static int bool_cmp(void* v1, void* v2) {
+ bool b1 = *(bool*)v1;
+ bool b2 = *(bool*)v2;
+ if (!b1 && b2) return -1;
+ if (b1 && !b2) return 1;
+ return 0;
+}
+
+static grpc_hash_table_vtable bool_vtable = {gpr_free, bool_copy, bool_cmp};
+
+// timespec vtable
+
+static void* timespec_copy(void* valuep) {
+ gpr_timespec value = *(gpr_timespec*)valuep;
+ gpr_timespec* new_value = gpr_malloc(sizeof(gpr_timespec));
+ *new_value = value;
+ return new_value;
+}
+
+static int timespec_cmp(void* v1, void* v2) {
+ return gpr_time_cmp(*(gpr_timespec*)v1, *(gpr_timespec*)v2);
+}
+
+static grpc_hash_table_vtable timespec_vtable = {gpr_free, timespec_copy,
+ timespec_cmp};
+
+// int32 vtable
+
+static void* int32_copy(void* valuep) {
+ int32_t value = *(int32_t*)valuep;
+ int32_t* new_value = gpr_malloc(sizeof(int32_t));
+ *new_value = value;
+ return new_value;
+}
+
+static int int32_cmp(void* v1, void* v2) {
+ int32_t i1 = *(int32_t*)v1;
+ int32_t i2 = *(int32_t*)v2;
+ if (i1 < i2) return -1;
+ if (i1 > i2) return 1;
+ return 0;
+}
+
+static grpc_hash_table_vtable int32_vtable = {gpr_free, int32_copy, int32_cmp};
+
+// Hash table keys.
+#define GRPC_METHOD_CONFIG_WAIT_FOR_READY "grpc.wait_for_ready" // bool
+#define GRPC_METHOD_CONFIG_TIMEOUT "grpc.timeout" // gpr_timespec
+#define GRPC_METHOD_CONFIG_MAX_REQUEST_MESSAGE_BYTES \
+ "grpc.max_request_message_bytes" // int32
+#define GRPC_METHOD_CONFIG_MAX_RESPONSE_MESSAGE_BYTES \
+ "grpc.max_response_message_bytes" // int32
+
+struct grpc_method_config {
+ grpc_hash_table* table;
+ grpc_mdstr* wait_for_ready_key;
+ grpc_mdstr* timeout_key;
+ grpc_mdstr* max_request_message_bytes_key;
+ grpc_mdstr* max_response_message_bytes_key;
+};
+
+grpc_method_config* grpc_method_config_create(
+ bool* wait_for_ready, gpr_timespec* timeout,
+ int32_t* max_request_message_bytes, int32_t* max_response_message_bytes) {
+ grpc_method_config* method_config = gpr_malloc(sizeof(grpc_method_config));
+ memset(method_config, 0, sizeof(grpc_method_config));
+ method_config->wait_for_ready_key =
+ grpc_mdstr_from_string(GRPC_METHOD_CONFIG_WAIT_FOR_READY);
+ method_config->timeout_key =
+ grpc_mdstr_from_string(GRPC_METHOD_CONFIG_TIMEOUT);
+ method_config->max_request_message_bytes_key =
+ grpc_mdstr_from_string(GRPC_METHOD_CONFIG_MAX_REQUEST_MESSAGE_BYTES);
+ method_config->max_response_message_bytes_key =
+ grpc_mdstr_from_string(GRPC_METHOD_CONFIG_MAX_RESPONSE_MESSAGE_BYTES);
+ grpc_hash_table_entry entries[4];
+ size_t num_entries = 0;
+ if (wait_for_ready != NULL) {
+ entries[num_entries].key = method_config->wait_for_ready_key;
+ entries[num_entries].value = wait_for_ready;
+ entries[num_entries].vtable = &bool_vtable;
+ ++num_entries;
+ }
+ if (timeout != NULL) {
+ entries[num_entries].key = method_config->timeout_key;
+ entries[num_entries].value = timeout;
+ entries[num_entries].vtable = &timespec_vtable;
+ ++num_entries;
+ }
+ if (max_request_message_bytes != NULL) {
+ entries[num_entries].key = method_config->max_request_message_bytes_key;
+ entries[num_entries].value = max_request_message_bytes;
+ entries[num_entries].vtable = &int32_vtable;
+ ++num_entries;
+ }
+ if (max_response_message_bytes != NULL) {
+ entries[num_entries].key = method_config->max_response_message_bytes_key;
+ entries[num_entries].value = max_response_message_bytes;
+ entries[num_entries].vtable = &int32_vtable;
+ ++num_entries;
+ }
+ method_config->table = grpc_hash_table_create(num_entries, entries);
+ return method_config;
+}
+
+grpc_method_config* grpc_method_config_ref(grpc_method_config* method_config) {
+ grpc_hash_table_ref(method_config->table);
+ return method_config;
+}
+
+void grpc_method_config_unref(grpc_method_config* method_config) {
+ if (grpc_hash_table_unref(method_config->table)) {
+ GRPC_MDSTR_UNREF(method_config->wait_for_ready_key);
+ GRPC_MDSTR_UNREF(method_config->timeout_key);
+ GRPC_MDSTR_UNREF(method_config->max_request_message_bytes_key);
+ GRPC_MDSTR_UNREF(method_config->max_response_message_bytes_key);
+ gpr_free(method_config);
+ }
+}
+
+int grpc_method_config_cmp(grpc_method_config* method_config1,
+ grpc_method_config* method_config2) {
+ return grpc_hash_table_cmp(method_config1->table, method_config2->table);
+}
+
+bool* grpc_method_config_get_wait_for_ready(grpc_method_config* method_config) {
+ return grpc_hash_table_get(method_config->table,
+ method_config->wait_for_ready_key);
+}
+
+gpr_timespec* grpc_method_config_get_timeout(
+ grpc_method_config* method_config) {
+ return grpc_hash_table_get(method_config->table, method_config->timeout_key);
+}
+
+int32_t* grpc_method_config_get_max_request_message_bytes(
+ grpc_method_config* method_config) {
+ return grpc_hash_table_get(method_config->table,
+ method_config->max_request_message_bytes_key);
+}
+
+int32_t* grpc_method_config_get_max_response_message_bytes(
+ grpc_method_config* method_config) {
+ return grpc_hash_table_get(method_config->table,
+ method_config->max_response_message_bytes_key);
+}
+
+//
+// grpc_method_config_table
+//
+
+static void method_config_unref(void* valuep) {
+ grpc_method_config_unref(valuep);
+}
+
+static void* method_config_ref(void* valuep) {
+ return grpc_method_config_ref(valuep);
+}
+
+static int method_config_cmp(void* valuep1, void* valuep2) {
+ return grpc_method_config_cmp(valuep1, valuep2);
+}
+
+static const grpc_hash_table_vtable method_config_table_vtable = {
+ method_config_unref, method_config_ref, method_config_cmp};
+
+grpc_method_config_table* grpc_method_config_table_create(
+ size_t num_entries, grpc_method_config_table_entry* entries) {
+ grpc_hash_table_entry hash_table_entries[num_entries];
+ for (size_t i = 0; i < num_entries; ++i) {
+ hash_table_entries[i].key = entries[i].method_name;
+ hash_table_entries[i].value = entries[i].method_config;
+ hash_table_entries[i].vtable = &method_config_table_vtable;
+ }
+ return grpc_hash_table_create(num_entries, hash_table_entries);
+}
+
+grpc_method_config_table* grpc_method_config_table_ref(
+ grpc_method_config_table* table) {
+ return grpc_hash_table_ref(table);
+}
+
+void grpc_method_config_table_unref(grpc_method_config_table* table) {
+ grpc_hash_table_unref(table);
+}
+
+int grpc_method_config_table_cmp(grpc_method_config_table* table1,
+ grpc_method_config_table* table2) {
+ return grpc_hash_table_cmp(table1, table2);
+}
+
+grpc_method_config* grpc_method_config_table_get_method_config(
+ grpc_method_config_table* table, grpc_mdstr* path) {
+ grpc_method_config* method_config = grpc_hash_table_get(table, path);
+ // If we didn't find a match for the path, try looking for a wildcard
+ // entry (i.e., change "/service/method" to "/service/*").
+ if (method_config == NULL) {
+ const char* path_str = grpc_mdstr_as_c_string(path);
+ const char* sep = strrchr(path_str, '/') + 1;
+ const size_t len = (size_t)(sep - path_str);
+ char buf[len + 2]; // '*' and NUL
+ memcpy(buf, path_str, len);
+ buf[len] = '*';
+ buf[len + 1] = '\0';
+ grpc_mdstr* wildcard_path = grpc_mdstr_from_string(buf);
+ method_config = grpc_hash_table_get(table, wildcard_path);
+ GRPC_MDSTR_UNREF(wildcard_path);
+ }
+ return method_config;
+}
+
+static void* copy_arg(void* p) { return grpc_method_config_table_ref(p); }
+
+static void destroy_arg(void* p) { grpc_method_config_table_unref(p); }
+
+static int cmp_arg(void* p1, void* p2) {
+ return grpc_method_config_table_cmp(p1, p2);
+}
+
+static grpc_arg_pointer_vtable arg_vtable = {copy_arg, destroy_arg, cmp_arg};
+
+grpc_arg grpc_method_config_table_create_channel_arg(
+ grpc_method_config_table* table) {
+ grpc_arg arg;
+ arg.type = GRPC_ARG_POINTER;
+ arg.key = GRPC_ARG_SERVICE_CONFIG;
+ arg.value.pointer.p = table;
+ arg.value.pointer.vtable = &arg_vtable;
+ return arg;
+}
diff --git a/src/core/ext/client_config/method_config.h b/src/core/ext/client_config/method_config.h
new file mode 100644
index 0000000000..65b34a768a
--- /dev/null
+++ b/src/core/ext/client_config/method_config.h
@@ -0,0 +1,97 @@
+//
+// Copyright 2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef GRPC_CORE_EXT_CLIENT_CONFIG_METHOD_CONFIG_H
+#define GRPC_CORE_EXT_CLIENT_CONFIG_METHOD_CONFIG_H
+
+#include <stdbool.h>
+
+#include <grpc/impl/codegen/gpr_types.h>
+#include <grpc/impl/codegen/grpc_types.h>
+
+#include "src/core/lib/transport/hashtable.h"
+#include "src/core/lib/transport/metadata.h"
+
+/// Per-method configuration.
+typedef struct grpc_method_config grpc_method_config;
+
+/// Any parameter may be NULL to indicate that the value is unset.
+grpc_method_config* grpc_method_config_create(
+ bool* wait_for_ready, gpr_timespec* timeout,
+ int32_t* max_request_message_bytes, int32_t* max_response_message_bytes);
+
+grpc_method_config* grpc_method_config_ref(grpc_method_config* method_config);
+void grpc_method_config_unref(grpc_method_config* method_config);
+
+int grpc_method_config_cmp(grpc_method_config* method_config1,
+ grpc_method_config* method_config2);
+
+/// These methods return NULL if the requested field is unset.
+/// The caller does NOT take ownership of the result.
+bool* grpc_method_config_get_wait_for_ready(grpc_method_config* method_config);
+gpr_timespec* grpc_method_config_get_timeout(grpc_method_config* method_config);
+int32_t* grpc_method_config_get_max_request_message_bytes(
+ grpc_method_config* method_config);
+int32_t* grpc_method_config_get_max_response_message_bytes(
+ grpc_method_config* method_config);
+
+/// A table of method configs.
+typedef grpc_hash_table grpc_method_config_table;
+
+typedef struct grpc_method_config_table_entry {
+ /// The name is of one of the following forms:
+ /// service/method -- specifies exact service and method name
+ /// service/* -- matches all methods for the specified service
+ grpc_mdstr* method_name;
+ grpc_method_config* method_config;
+} grpc_method_config_table_entry;
+
+/// Takes new references to all keys and values in \a entries.
+grpc_method_config_table* grpc_method_config_table_create(
+ size_t num_entries, grpc_method_config_table_entry* entries);
+
+grpc_method_config_table* grpc_method_config_table_ref(
+ grpc_method_config_table* table);
+void grpc_method_config_table_unref(grpc_method_config_table* table);
+
+int grpc_method_config_table_cmp(grpc_method_config_table* table1,
+ grpc_method_config_table* table2);
+
+/// Returns NULL if the method has no config.
+/// Caller does NOT own a reference to the result.
+grpc_method_config* grpc_method_config_table_get_method_config(
+ grpc_method_config_table* table, grpc_mdstr* path);
+
+/// Returns a channel arg containing \a table.
+grpc_arg grpc_method_config_table_create_channel_arg(
+ grpc_method_config_table* table);
+
+#endif /* GRPC_CORE_EXT_CLIENT_CONFIG_METHOD_CONFIG_H */
diff --git a/src/core/ext/client_config/resolver_result.h b/src/core/ext/client_config/resolver_result.h
index 414c2e2482..a7ea7c0f4b 100644
--- a/src/core/ext/client_config/resolver_result.h
+++ b/src/core/ext/client_config/resolver_result.h
@@ -52,22 +52,17 @@ typedef struct grpc_resolver_result grpc_resolver_result;
grpc_resolver_result* grpc_resolver_result_create(
const char* server_name, grpc_lb_addresses* addresses,
const char* lb_policy_name, grpc_channel_args* lb_policy_args);
+
void grpc_resolver_result_ref(grpc_resolver_result* result);
void grpc_resolver_result_unref(grpc_exec_ctx* exec_ctx,
grpc_resolver_result* result);
-/// Caller does NOT take ownership of result.
+/// Accessors. Caller does NOT take ownership of results.
const char* grpc_resolver_result_get_server_name(grpc_resolver_result* result);
-
-/// Caller does NOT take ownership of result.
grpc_lb_addresses* grpc_resolver_result_get_addresses(
grpc_resolver_result* result);
-
-/// Caller does NOT take ownership of result.
const char* grpc_resolver_result_get_lb_policy_name(
grpc_resolver_result* result);
-
-/// Caller does NOT take ownership of result.
grpc_channel_args* grpc_resolver_result_get_lb_policy_args(
grpc_resolver_result* result);
diff --git a/src/core/ext/client_config/subchannel.c b/src/core/ext/client_config/subchannel.c
index 0bbaa3e382..b3154f7cbb 100644
--- a/src/core/ext/client_config/subchannel.c
+++ b/src/core/ext/client_config/subchannel.c
@@ -704,7 +704,7 @@ grpc_connected_subchannel *grpc_subchannel_get_connected_subchannel(
grpc_error *grpc_connected_subchannel_create_call(
grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con,
- grpc_polling_entity *pollent, gpr_timespec deadline,
+ grpc_polling_entity *pollent, grpc_mdstr *path, gpr_timespec deadline,
grpc_subchannel_call **call) {
grpc_channel_stack *chanstk = CHANNEL_STACK_FROM_CONNECTION(con);
*call = gpr_malloc(sizeof(grpc_subchannel_call) + chanstk->call_stack_size);
@@ -712,7 +712,7 @@ grpc_error *grpc_connected_subchannel_create_call(
(*call)->connection = con; // Ref is added below.
grpc_error *error =
grpc_call_stack_init(exec_ctx, chanstk, 1, subchannel_call_destroy, *call,
- NULL, NULL, deadline, callstk);
+ NULL, NULL, path, deadline, callstk);
if (error != GRPC_ERROR_NONE) {
const char *error_string = grpc_error_string(error);
gpr_log(GPR_ERROR, "error: %s", error_string);
diff --git a/src/core/ext/client_config/subchannel.h b/src/core/ext/client_config/subchannel.h
index 3330621071..f8de26dfd5 100644
--- a/src/core/ext/client_config/subchannel.h
+++ b/src/core/ext/client_config/subchannel.h
@@ -38,6 +38,7 @@
#include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/transport/connectivity_state.h"
+#include "src/core/lib/transport/metadata.h"
/** A (sub-)channel that knows how to connect to exactly one target
address. Provides a target for load balancing. */
@@ -110,7 +111,7 @@ void grpc_subchannel_call_unref(grpc_exec_ctx *exec_ctx,
/** construct a subchannel call */
grpc_error *grpc_connected_subchannel_create_call(
grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *connected_subchannel,
- grpc_polling_entity *pollent, gpr_timespec deadline,
+ grpc_polling_entity *pollent, grpc_mdstr *path, gpr_timespec deadline,
grpc_subchannel_call **subchannel_call);
/** process a transport level op */
diff --git a/src/core/ext/lb_policy/grpclb/grpclb.c b/src/core/ext/lb_policy/grpclb/grpclb.c
index bdfe65a62a..db425f817b 100644
--- a/src/core/ext/lb_policy/grpclb/grpclb.c
+++ b/src/core/ext/lb_policy/grpclb/grpclb.c
@@ -112,6 +112,7 @@
#include "src/core/ext/client_config/parse_address.h"
#include "src/core/ext/lb_policy/grpclb/grpclb.h"
#include "src/core/ext/lb_policy/grpclb/load_balancer_api.h"
+#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/iomgr/sockaddr.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/support/string.h"
@@ -285,6 +286,7 @@ typedef struct glb_lb_policy {
const char *server_name;
grpc_client_channel_factory *cc_factory;
+ grpc_channel_args *args;
/** for communicating with the LB server */
grpc_channel *lb_channel;
@@ -442,6 +444,7 @@ static grpc_lb_policy *create_rr(grpc_exec_ctx *exec_ctx,
args.server_name = glb_policy->server_name;
args.client_channel_factory = glb_policy->cc_factory;
args.addresses = process_serverlist(serverlist);
+ args.additional_args = glb_policy->args;
grpc_lb_policy *rr = grpc_lb_policy_create(exec_ctx, "round_robin", &args);
@@ -567,6 +570,7 @@ static grpc_lb_policy *glb_create(grpc_exec_ctx *exec_ctx,
* Create a client channel over them to communicate with a LB service */
glb_policy->server_name = gpr_strdup(args->server_name);
glb_policy->cc_factory = args->client_channel_factory;
+ glb_policy->args = grpc_channel_args_copy(args->additional_args);
GPR_ASSERT(glb_policy->cc_factory != NULL);
/* construct a target from the addresses in args, given in the form
@@ -633,6 +637,7 @@ static void glb_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
GPR_ASSERT(glb_policy->pending_picks == NULL);
GPR_ASSERT(glb_policy->pending_pings == NULL);
gpr_free((void *)glb_policy->server_name);
+ grpc_channel_args_destroy(glb_policy->args);
grpc_channel_destroy(glb_policy->lb_channel);
glb_policy->lb_channel = NULL;
grpc_connectivity_state_destroy(exec_ctx, &glb_policy->state_tracker);
diff --git a/src/core/ext/lb_policy/pick_first/pick_first.c b/src/core/ext/lb_policy/pick_first/pick_first.c
index 961a0c9b19..c0efbe511b 100644
--- a/src/core/ext/lb_policy/pick_first/pick_first.c
+++ b/src/core/ext/lb_policy/pick_first/pick_first.c
@@ -478,6 +478,7 @@ static grpc_lb_policy *create_pick_first(grpc_exec_ctx *exec_ctx,
sc_args.addr =
(struct sockaddr *)(&args->addresses->addresses[i].address.addr);
sc_args.addr_len = args->addresses->addresses[i].address.len;
+ sc_args.args = args->additional_args;
grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel(
exec_ctx, args->client_channel_factory, &sc_args);
diff --git a/src/core/ext/lb_policy/round_robin/round_robin.c b/src/core/ext/lb_policy/round_robin/round_robin.c
index 930fa86aca..37856c228d 100644
--- a/src/core/ext/lb_policy/round_robin/round_robin.c
+++ b/src/core/ext/lb_policy/round_robin/round_robin.c
@@ -641,6 +641,7 @@ static grpc_lb_policy *round_robin_create(grpc_exec_ctx *exec_ctx,
sc_args.addr =
(struct sockaddr *)(&args->addresses->addresses[i].address.addr);
sc_args.addr_len = args->addresses->addresses[i].address.len;
+ sc_args.args = args->additional_args;
grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel(
exec_ctx, args->client_channel_factory, &sc_args);
diff --git a/src/core/ext/resolver/sockaddr/sockaddr_resolver.c b/src/core/ext/resolver/sockaddr/sockaddr_resolver.c
index d17a166850..dff0079aad 100644
--- a/src/core/ext/resolver/sockaddr/sockaddr_resolver.c
+++ b/src/core/ext/resolver/sockaddr/sockaddr_resolver.c
@@ -33,6 +33,7 @@
#include <stdbool.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <grpc/support/alloc.h>
@@ -42,6 +43,7 @@
#include "src/core/ext/client_config/parse_address.h"
#include "src/core/ext/client_config/resolver_registry.h"
+#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/unix_sockets_posix.h"
#include "src/core/lib/support/string.h"
@@ -121,7 +123,7 @@ static void sockaddr_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
*r->target_result = grpc_resolver_result_create(
r->target_name,
grpc_lb_addresses_copy(r->addresses, NULL /* user_data_copy */),
- NULL /* lb_policy_name */, NULL);
+ NULL /* lb_policy_name */, NULL /* lb_policy_args */);
grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL);
r->next_completion = NULL;
}
@@ -130,8 +132,8 @@ static void sockaddr_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
static void sockaddr_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *gr) {
sockaddr_resolver *r = (sockaddr_resolver *)gr;
gpr_mu_destroy(&r->mu);
- grpc_lb_addresses_destroy(r->addresses, NULL /* user_data_destroy */);
gpr_free(r->target_name);
+ grpc_lb_addresses_destroy(r->addresses, NULL /* user_data_destroy */);
gpr_free(r);
}
@@ -163,26 +165,23 @@ static void do_nothing(void *ignored) {}
static grpc_resolver *sockaddr_create(
grpc_resolver_args *args,
int parse(grpc_uri *uri, struct sockaddr_storage *dst, size_t *len)) {
- bool errors_found = false;
- sockaddr_resolver *r;
- gpr_slice path_slice;
- gpr_slice_buffer path_parts;
-
if (0 != strcmp(args->uri->authority, "")) {
gpr_log(GPR_ERROR, "authority based uri's not supported by the %s scheme",
args->uri->scheme);
return NULL;
}
- r = gpr_malloc(sizeof(sockaddr_resolver));
+ sockaddr_resolver *r = gpr_malloc(sizeof(sockaddr_resolver));
memset(r, 0, sizeof(*r));
+ r->target_name = gpr_strdup(args->uri->path);
- path_slice =
+ gpr_slice path_slice =
gpr_slice_new(args->uri->path, strlen(args->uri->path), do_nothing);
+ gpr_slice_buffer path_parts;
gpr_slice_buffer_init(&path_parts);
-
gpr_slice_split(path_slice, ",", &path_parts);
r->addresses = grpc_lb_addresses_create(path_parts.count);
+ bool errors_found = false;
for (size_t i = 0; i < r->addresses->num_addresses; i++) {
grpc_uri ith_uri = *args->uri;
char *part_str = gpr_dump_slice(path_parts.slices[i], GPR_DUMP_ASCII);
@@ -195,8 +194,6 @@ static grpc_resolver *sockaddr_create(
gpr_free(part_str);
if (errors_found) break;
}
-
- r->target_name = gpr_strdup(args->uri->path);
gpr_slice_buffer_destroy(&path_parts);
gpr_slice_unref(path_slice);
if (errors_found) {
diff --git a/src/core/lib/channel/channel_args.c b/src/core/lib/channel/channel_args.c
index 3a56b1ff20..2957d2c818 100644
--- a/src/core/lib/channel/channel_args.c
+++ b/src/core/lib/channel/channel_args.c
@@ -272,6 +272,18 @@ int grpc_channel_args_compare(const grpc_channel_args *a,
return 0;
}
+const grpc_arg *grpc_channel_args_find(const grpc_channel_args *args,
+ const char *name) {
+ if (args != NULL) {
+ for (size_t i = 0; i < args->num_args; ++i) {
+ if (strcmp(args->args[i].key, name) == 0) {
+ return &args->args[i];
+ }
+ }
+ }
+ return NULL;
+}
+
int grpc_channel_arg_get_integer(grpc_arg *arg, grpc_integer_options options) {
if (arg->type != GRPC_ARG_INTEGER) {
gpr_log(GPR_ERROR, "%s ignored: it must be an integer", arg->key);
diff --git a/src/core/lib/channel/channel_args.h b/src/core/lib/channel/channel_args.h
index 586a296d1f..a80340c0fa 100644
--- a/src/core/lib/channel/channel_args.h
+++ b/src/core/lib/channel/channel_args.h
@@ -89,6 +89,10 @@ uint32_t grpc_channel_args_compression_algorithm_get_states(
int grpc_channel_args_compare(const grpc_channel_args *a,
const grpc_channel_args *b);
+/** Returns the value of argument \a name from \a args, or NULL if not found. */
+const grpc_arg *grpc_channel_args_find(const grpc_channel_args *args,
+ const char *name);
+
typedef struct grpc_integer_options {
int default_value; // Return this if value is outside of expected bounds.
int min_value;
diff --git a/src/core/lib/channel/channel_stack.c b/src/core/lib/channel/channel_stack.c
index 57d34d9e9a..205496f2f2 100644
--- a/src/core/lib/channel/channel_stack.c
+++ b/src/core/lib/channel/channel_stack.c
@@ -162,7 +162,7 @@ grpc_error *grpc_call_stack_init(
grpc_exec_ctx *exec_ctx, grpc_channel_stack *channel_stack,
int initial_refs, grpc_iomgr_cb_func destroy, void *destroy_arg,
grpc_call_context_element *context, const void *transport_server_data,
- gpr_timespec deadline, grpc_call_stack *call_stack) {
+ grpc_mdstr *path, gpr_timespec deadline, grpc_call_stack *call_stack) {
grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(channel_stack);
grpc_call_element_args args;
size_t count = channel_stack->count;
@@ -183,6 +183,7 @@ grpc_error *grpc_call_stack_init(
args.call_stack = call_stack;
args.server_transport_data = transport_server_data;
args.context = context;
+ args.path = path;
args.deadline = deadline;
call_elems[i].filter = channel_elems[i].filter;
call_elems[i].channel_data = channel_elems[i].channel_data;
diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h
index 1cfe2885d8..5b46cd32a3 100644
--- a/src/core/lib/channel/channel_stack.h
+++ b/src/core/lib/channel/channel_stack.h
@@ -74,6 +74,7 @@ typedef struct {
grpc_call_stack *call_stack;
const void *server_transport_data;
grpc_call_context_element *context;
+ grpc_mdstr *path;
gpr_timespec deadline;
} grpc_call_element_args;
@@ -225,7 +226,7 @@ grpc_error *grpc_call_stack_init(
grpc_exec_ctx *exec_ctx, grpc_channel_stack *channel_stack,
int initial_refs, grpc_iomgr_cb_func destroy, void *destroy_arg,
grpc_call_context_element *context, const void *transport_server_data,
- gpr_timespec deadline, grpc_call_stack *call_stack);
+ grpc_mdstr *path, gpr_timespec deadline, grpc_call_stack *call_stack);
/* Set a pollset or a pollset_set for a call stack: must occur before the first
* op is started */
void grpc_call_stack_set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/lib/channel/deadline_filter.c b/src/core/lib/channel/deadline_filter.c
index 079b98a2f8..5216338833 100644
--- a/src/core/lib/channel/deadline_filter.c
+++ b/src/core/lib/channel/deadline_filter.c
@@ -123,15 +123,23 @@ static void start_timer_after_init(grpc_exec_ctx* exec_ctx, void* arg,
}
void grpc_deadline_state_init(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
- grpc_call_element_args* args) {
+ grpc_call_element_args* args,
+ grpc_method_config* method_config) {
grpc_deadline_state* deadline_state = elem->call_data;
memset(deadline_state, 0, sizeof(*deadline_state));
deadline_state->call_stack = args->call_stack;
gpr_mu_init(&deadline_state->timer_mu);
// Deadline will always be infinite on servers, so the timer will only be
// set on clients with a finite deadline.
- const gpr_timespec deadline =
+ gpr_timespec deadline =
gpr_convert_clock_type(args->deadline, GPR_CLOCK_MONOTONIC);
+ if (method_config != NULL) {
+ gpr_timespec* per_method_deadline =
+ grpc_method_config_get_timeout(method_config);
+ if (per_method_deadline != NULL) {
+ deadline = gpr_time_min(deadline, *per_method_deadline);
+ }
+ }
if (gpr_time_cmp(deadline, gpr_inf_future(GPR_CLOCK_MONOTONIC)) != 0) {
// When the deadline passes, we indicate the failure by sending down
// an op with cancel_error set. However, we can't send down any ops
@@ -209,7 +217,7 @@ static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx,
grpc_call_element_args* args) {
// Note: size of call data is different between client and server.
memset(elem->call_data, 0, elem->filter->sizeof_call_data);
- grpc_deadline_state_init(exec_ctx, elem, args);
+ grpc_deadline_state_init(exec_ctx, elem, args, NULL /* method_config */);
return GRPC_ERROR_NONE;
}
diff --git a/src/core/lib/channel/deadline_filter.h b/src/core/lib/channel/deadline_filter.h
index 685df87761..ce6e8ea974 100644
--- a/src/core/lib/channel/deadline_filter.h
+++ b/src/core/lib/channel/deadline_filter.h
@@ -35,6 +35,8 @@
#include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/iomgr/timer.h"
+#include "src/core/ext/client_config/method_config.h"
+
// State used for filters that enforce call deadlines.
// Must be the first field in the filter's call_data.
typedef struct grpc_deadline_state {
@@ -63,7 +65,8 @@ typedef struct grpc_deadline_state {
// caller's responsibility to chain to the next filter if necessary
// after the function returns.
void grpc_deadline_state_init(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
- grpc_call_element_args* args);
+ grpc_call_element_args* args,
+ grpc_method_config* method_config);
void grpc_deadline_state_destroy(grpc_exec_ctx* exec_ctx,
grpc_call_element* elem);
void grpc_deadline_state_client_start_transport_stream_op(
diff --git a/src/core/lib/channel/message_size_filter.c b/src/core/lib/channel/message_size_filter.c
index 02fc68fc3a..a54c424e1b 100644
--- a/src/core/lib/channel/message_size_filter.c
+++ b/src/core/lib/channel/message_size_filter.c
@@ -38,6 +38,7 @@
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
+#include "src/core/ext/client_config/method_config.h"
#include "src/core/lib/channel/channel_args.h"
#define DEFAULT_MAX_SEND_MESSAGE_LENGTH -1 // Unlimited.
@@ -45,6 +46,8 @@
#define DEFAULT_MAX_RECV_MESSAGE_LENGTH (4 * 1024 * 1024)
typedef struct call_data {
+ int max_send_size;
+ int max_recv_size;
// Receive closures are chained: we inject this closure as the
// recv_message_ready up-call on transport_stream_op, and remember to
// call our next_recv_message_ready member after handling it.
@@ -58,6 +61,8 @@ typedef struct call_data {
typedef struct channel_data {
int max_send_size;
int max_recv_size;
+ // Method config table.
+ grpc_method_config_table* method_config_table;
} channel_data;
// Callback invoked when we receive a message. Here we check the max
@@ -66,13 +71,12 @@ static void recv_message_ready(grpc_exec_ctx* exec_ctx, void* user_data,
grpc_error* error) {
grpc_call_element* elem = user_data;
call_data* calld = elem->call_data;
- channel_data* chand = elem->channel_data;
- if (*calld->recv_message != NULL && chand->max_recv_size >= 0 &&
- (*calld->recv_message)->length > (size_t)chand->max_recv_size) {
+ if (*calld->recv_message != NULL && calld->max_recv_size >= 0 &&
+ (*calld->recv_message)->length > (size_t)calld->max_recv_size) {
char* message_string;
gpr_asprintf(&message_string,
"Received message larger than max (%u vs. %d)",
- (*calld->recv_message)->length, chand->max_recv_size);
+ (*calld->recv_message)->length, calld->max_recv_size);
gpr_slice message = gpr_slice_from_copied_string(message_string);
gpr_free(message_string);
grpc_call_element_send_close_with_message(
@@ -87,13 +91,12 @@ static void start_transport_stream_op(grpc_exec_ctx* exec_ctx,
grpc_call_element* elem,
grpc_transport_stream_op* op) {
call_data* calld = elem->call_data;
- channel_data* chand = elem->channel_data;
// Check max send message size.
- if (op->send_message != NULL && chand->max_send_size >= 0 &&
- op->send_message->length > (size_t)chand->max_send_size) {
+ if (op->send_message != NULL && calld->max_send_size >= 0 &&
+ op->send_message->length > (size_t)calld->max_send_size) {
char* message_string;
gpr_asprintf(&message_string, "Sent message larger than max (%u vs. %d)",
- op->send_message->length, chand->max_send_size);
+ op->send_message->length, calld->max_send_size);
gpr_slice message = gpr_slice_from_copied_string(message_string);
gpr_free(message_string);
grpc_call_element_send_close_with_message(
@@ -113,9 +116,37 @@ static void start_transport_stream_op(grpc_exec_ctx* exec_ctx,
static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx,
grpc_call_element* elem,
grpc_call_element_args* args) {
+ channel_data* chand = elem->channel_data;
call_data* calld = elem->call_data;
calld->next_recv_message_ready = NULL;
grpc_closure_init(&calld->recv_message_ready, recv_message_ready, elem);
+ // Get max sizes from channel data, then merge in per-method config values.
+ // Note: Per-method config is only available on the client, so we
+ // apply the max request size to the send limit and the max response
+ // size to the receive limit.
+ calld->max_send_size = chand->max_send_size;
+ calld->max_recv_size = chand->max_recv_size;
+ if (chand->method_config_table != NULL) {
+ grpc_method_config* method_config =
+ grpc_method_config_table_get_method_config(chand->method_config_table,
+ args->path);
+ if (method_config != NULL) {
+ int32_t* max_request_message_bytes =
+ grpc_method_config_get_max_request_message_bytes(method_config);
+ if (max_request_message_bytes != NULL &&
+ (*max_request_message_bytes < calld->max_send_size ||
+ calld->max_send_size < 0)) {
+ calld->max_send_size = *max_request_message_bytes;
+ }
+ int32_t* max_response_message_bytes =
+ grpc_method_config_get_max_response_message_bytes(method_config);
+ if (max_response_message_bytes != NULL &&
+ (*max_response_message_bytes < calld->max_recv_size ||
+ calld->max_recv_size < 0)) {
+ calld->max_recv_size = *max_response_message_bytes;
+ }
+ }
+ }
return GRPC_ERROR_NONE;
}
@@ -149,11 +180,22 @@ static void init_channel_elem(grpc_exec_ctx* exec_ctx,
grpc_channel_arg_get_integer(&args->channel_args->args[i], options);
}
}
+ // Get method config table from channel args.
+ const grpc_arg* channel_arg =
+ grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVICE_CONFIG);
+ if (channel_arg != NULL) {
+ GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER);
+ chand->method_config_table = grpc_method_config_table_ref(
+ (grpc_method_config_table*)channel_arg->value.pointer.p);
+ }
}
// Destructor for channel_data.
static void destroy_channel_elem(grpc_exec_ctx* exec_ctx,
- grpc_channel_element* elem) {}
+ grpc_channel_element* elem) {
+ channel_data* chand = elem->channel_data;
+ grpc_method_config_table_unref(chand->method_config_table);
+}
const grpc_channel_filter grpc_message_size_filter = {
start_transport_stream_op,
diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c
index 5690bcab1e..0af72547e3 100644
--- a/src/core/lib/surface/call.c
+++ b/src/core/lib/surface/call.c
@@ -242,10 +242,14 @@ grpc_call *grpc_call_create(
/* Always support no compression */
GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_COMPRESS_NONE);
call->is_client = server_transport_data == NULL;
+ grpc_mdstr *path = NULL;
if (call->is_client) {
GPR_ASSERT(add_initial_metadata_count < MAX_SEND_EXTRA_METADATA_COUNT);
for (i = 0; i < add_initial_metadata_count; i++) {
call->send_extra_metadata[i].md = add_initial_metadata[i];
+ if (add_initial_metadata[i]->key == GRPC_MDSTR_PATH) {
+ path = GRPC_MDSTR_REF(add_initial_metadata[i]->value);
+ }
}
call->send_extra_metadata_count = (int)add_initial_metadata_count;
} else {
@@ -307,7 +311,7 @@ grpc_call *grpc_call_create(
/* initial refcount dropped by grpc_call_destroy */
grpc_error *error = grpc_call_stack_init(
&exec_ctx, channel_stack, 1, destroy_call, call, call->context,
- server_transport_data, send_deadline, CALL_STACK_FROM_CALL(call));
+ server_transport_data, path, send_deadline, CALL_STACK_FROM_CALL(call));
if (error != GRPC_ERROR_NONE) {
grpc_status_code status;
const char *error_str;
@@ -332,6 +336,8 @@ grpc_call *grpc_call_create(
&exec_ctx, CALL_STACK_FROM_CALL(call), &call->pollent);
}
+ if (path != NULL) GRPC_MDSTR_UNREF(path);
+
grpc_exec_ctx_finish(&exec_ctx);
GPR_TIMER_END("grpc_call_create", 0);
return call;
diff --git a/src/core/lib/transport/hashtable.c b/src/core/lib/transport/hashtable.c
new file mode 100644
index 0000000000..838fe1026e
--- /dev/null
+++ b/src/core/lib/transport/hashtable.c
@@ -0,0 +1,139 @@
+//
+// Copyright 2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include "src/core/lib/transport/hashtable.h"
+
+#include <stdbool.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/transport/metadata.h"
+
+struct grpc_hash_table {
+ gpr_refcount refs;
+ size_t num_entries;
+ grpc_hash_table_entry* entries;
+};
+
+// Helper function for insert and get operations that performs quadratic
+// probing (https://en.wikipedia.org/wiki/Quadratic_probing).
+static size_t grpc_hash_table_find_index(grpc_hash_table* table,
+ grpc_mdstr* key, bool find_empty) {
+ for (size_t i = 0; i < table->num_entries; ++i) {
+ const size_t idx = (key->hash + i * i) % table->num_entries;
+ if (table->entries[idx].key == NULL)
+ return find_empty ? idx : table->num_entries;
+ if (table->entries[idx].key == key) return idx;
+ }
+ return table->num_entries; // Not found.
+}
+
+static void grpc_hash_table_add(grpc_hash_table* table, grpc_mdstr* key,
+ void* value,
+ const grpc_hash_table_vtable* vtable) {
+ GPR_ASSERT(value != NULL);
+ const size_t idx =
+ grpc_hash_table_find_index(table, key, true /* find_empty */);
+ // This can happen if the table is full.
+ GPR_ASSERT(idx != table->num_entries);
+ grpc_hash_table_entry* entry = &table->entries[idx];
+ entry->key = GRPC_MDSTR_REF(key);
+ entry->value = vtable->copy_value(value);
+ entry->vtable = vtable;
+}
+
+grpc_hash_table* grpc_hash_table_create(size_t num_entries,
+ grpc_hash_table_entry* entries) {
+ grpc_hash_table* table = gpr_malloc(sizeof(*table));
+ memset(table, 0, sizeof(*table));
+ gpr_ref_init(&table->refs, 1);
+ // Quadratic probing gets best performance when the table is no more
+ // than half full.
+ table->num_entries = num_entries * 2;
+ const size_t entry_size = sizeof(grpc_hash_table_entry) * table->num_entries;
+ table->entries = gpr_malloc(entry_size);
+ memset(table->entries, 0, entry_size);
+ for (size_t i = 0; i < num_entries; ++i) {
+ grpc_hash_table_entry* entry = &entries[i];
+ grpc_hash_table_add(table, entry->key, entry->value, entry->vtable);
+ }
+ return table;
+}
+
+grpc_hash_table* grpc_hash_table_ref(grpc_hash_table* table) {
+ if (table != NULL) gpr_ref(&table->refs);
+ return table;
+}
+
+int grpc_hash_table_unref(grpc_hash_table* table) {
+ if (table != NULL && gpr_unref(&table->refs)) {
+ for (size_t i = 0; i < table->num_entries; ++i) {
+ grpc_hash_table_entry* entry = &table->entries[i];
+ if (entry->key != NULL) {
+ GRPC_MDSTR_UNREF(entry->key);
+ entry->vtable->destroy_value(entry->value);
+ }
+ }
+ gpr_free(table->entries);
+ gpr_free(table);
+ return 1;
+ }
+ return 0;
+}
+
+void* grpc_hash_table_get(grpc_hash_table* table, grpc_mdstr* key) {
+ const size_t idx =
+ grpc_hash_table_find_index(table, key, false /* find_empty */);
+ if (idx == table->num_entries) return NULL; // Not found.
+ return table->entries[idx].value;
+}
+
+int grpc_hash_table_cmp(grpc_hash_table* table1, grpc_hash_table* table2) {
+ // Compare by num_entries.
+ if (table1->num_entries < table2->num_entries) return -1;
+ if (table1->num_entries > table2->num_entries) return 1;
+ for (size_t i = 0; i < table1->num_entries; ++i) {
+ grpc_hash_table_entry* e1 = &table1->entries[i];
+ grpc_hash_table_entry* e2 = &table2->entries[i];
+ // Compare keys by hash value.
+ if (e1->key->hash < e2->key->hash) return -1;
+ if (e1->key->hash > e2->key->hash) return 1;
+ // Compare by vtable (pointer equality).
+ if (e1->vtable < e2->vtable) return -1;
+ if (e1->vtable > e2->vtable) return 1;
+ // Compare values via vtable.
+ const int value_result = e1->vtable->compare_value(e1->value, e2->value);
+ if (value_result != 0) return value_result;
+ }
+ return 0;
+}
diff --git a/src/core/lib/transport/hashtable.h b/src/core/lib/transport/hashtable.h
new file mode 100644
index 0000000000..3ec48dce3a
--- /dev/null
+++ b/src/core/lib/transport/hashtable.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GRPC_CORE_LIB_TRANSPORT_HASHTABLE_H
+#define GRPC_CORE_LIB_TRANSPORT_HASHTABLE_H
+
+#include "src/core/lib/transport/metadata.h"
+
+/** Hash table implementation.
+ *
+ * This implementation uses open addressing
+ * (https://en.wikipedia.org/wiki/Open_addressing) with quadratic
+ * probing (https://en.wikipedia.org/wiki/Quadratic_probing).
+ * This means that the hash table is of fixed size and cannot contain
+ * more than that number of elements.
+ *
+ * The keys are grpc_mdstr objects. The values are arbitrary pointers
+ * with a common vtable.
+ *
+ * Hash tables are intentionally immutable, to avoid the need for locking.
+ */
+
+typedef struct grpc_hash_table grpc_hash_table;
+
+typedef struct grpc_hash_table_vtable {
+ void (*destroy_value)(void* value);
+ void* (*copy_value)(void* value);
+ int (*compare_value)(void* value1, void* value2);
+} grpc_hash_table_vtable;
+
+typedef struct grpc_hash_table_entry {
+ grpc_mdstr* key;
+ void* value; /* Must not be NULL. */
+ const grpc_hash_table_vtable* vtable;
+} grpc_hash_table_entry;
+
+/** Creates a new hash table of containing \a entries, which is an array
+ of length \a num_entries.
+ Creates its own copy of all keys and values from \a entries. */
+grpc_hash_table* grpc_hash_table_create(size_t num_entries,
+ grpc_hash_table_entry* entries);
+
+grpc_hash_table* grpc_hash_table_ref(grpc_hash_table* table);
+/** Returns 1 when \a table is destroyed. */
+int grpc_hash_table_unref(grpc_hash_table* table);
+
+/** Returns the value from \a table associated with \a key.
+ Returns NULL if \a key is not found. */
+void* grpc_hash_table_get(grpc_hash_table* table, grpc_mdstr* key);
+
+/** Compares two hash tables. */
+int grpc_hash_table_cmp(grpc_hash_table* table1, grpc_hash_table* table2);
+
+#endif /* GRPC_CORE_LIB_TRANSPORT_HASHTABLE_H */
diff --git a/src/cpp/client/client_context.cc b/src/cpp/client/client_context.cc
index 5b6aaa777b..b6008f47b1 100644
--- a/src/cpp/client/client_context.cc
+++ b/src/cpp/client/client_context.cc
@@ -59,7 +59,8 @@ static ClientContext::GlobalCallbacks* g_client_callbacks =
ClientContext::ClientContext()
: initial_metadata_received_(false),
- fail_fast_(true),
+ wait_for_ready_(false),
+ wait_for_ready_explicitly_set_(false),
idempotent_(false),
cacheable_(false),
call_(nullptr),
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 2bebf48c70..315d469a15 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -164,6 +164,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/surface/version.c',
'src/core/lib/transport/byte_stream.c',
'src/core/lib/transport/connectivity_state.c',
+ 'src/core/lib/transport/hashtable.c',
'src/core/lib/transport/metadata.c',
'src/core/lib/transport/metadata_batch.c',
'src/core/lib/transport/static_metadata.c',
@@ -233,6 +234,7 @@ CORE_SOURCE_FILES = [
'src/core/ext/client_config/lb_policy.c',
'src/core/ext/client_config/lb_policy_factory.c',
'src/core/ext/client_config/lb_policy_registry.c',
+ 'src/core/ext/client_config/method_config.c',
'src/core/ext/client_config/parse_address.c',
'src/core/ext/client_config/resolver.c',
'src/core/ext/client_config/resolver_factory.c',
diff --git a/test/core/client_config/resolvers/sockaddr_resolver_test.c b/test/core/client_config/resolvers/sockaddr_resolver_test.c
index b5d96efa1d..3fc074adf3 100644
--- a/test/core/client_config/resolvers/sockaddr_resolver_test.c
+++ b/test/core/client_config/resolvers/sockaddr_resolver_test.c
@@ -37,13 +37,21 @@
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
+#include "src/core/ext/client_config/method_config.h"
#include "src/core/ext/client_config/resolver_registry.h"
#include "src/core/ext/client_config/resolver_result.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/transport/metadata.h"
#include "test/core/util/test_config.h"
typedef struct on_resolution_arg {
char *expected_server_name;
+ const char *expected_method_name;
+ bool expected_wait_for_ready;
+ gpr_timespec expected_timeout;
+ int32_t expected_max_request_message_bytes;
+ int32_t expected_max_response_message_bytes;
grpc_resolver_result *resolver_result;
} on_resolution_arg;
@@ -52,6 +60,40 @@ void on_resolution_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
const char *server_name =
grpc_resolver_result_get_server_name(res->resolver_result);
GPR_ASSERT(strcmp(res->expected_server_name, server_name) == 0);
+ const grpc_channel_args *lb_policy_args =
+ grpc_resolver_result_get_lb_policy_args(res->resolver_result);
+ if (res->expected_method_name == NULL) {
+ GPR_ASSERT(lb_policy_args == NULL);
+ } else {
+ const grpc_arg *channel_arg =
+ grpc_channel_args_find(lb_policy_args, GRPC_ARG_SERVICE_CONFIG);
+ GPR_ASSERT(channel_arg != NULL);
+ GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER);
+ grpc_method_config_table *method_config_table =
+ (grpc_method_config_table *)channel_arg->value.pointer.p;
+ GPR_ASSERT(method_config_table != NULL);
+ grpc_mdstr *path = grpc_mdstr_from_string(res->expected_method_name);
+ grpc_method_config *method_config =
+ grpc_method_config_table_get_method_config(method_config_table, path);
+ GRPC_MDSTR_UNREF(path);
+ GPR_ASSERT(method_config != NULL);
+ bool *wait_for_ready = grpc_method_config_get_wait_for_ready(method_config);
+ GPR_ASSERT(wait_for_ready != NULL);
+ GPR_ASSERT(*wait_for_ready == res->expected_wait_for_ready);
+ gpr_timespec *timeout = grpc_method_config_get_timeout(method_config);
+ GPR_ASSERT(timeout != NULL);
+ GPR_ASSERT(gpr_time_cmp(*timeout, res->expected_timeout) == 0);
+ int32_t *max_request_message_bytes =
+ grpc_method_config_get_max_request_message_bytes(method_config);
+ GPR_ASSERT(max_request_message_bytes != NULL);
+ GPR_ASSERT(*max_request_message_bytes ==
+ res->expected_max_request_message_bytes);
+ int32_t *max_response_message_bytes =
+ grpc_method_config_get_max_response_message_bytes(method_config);
+ GPR_ASSERT(max_response_message_bytes != NULL);
+ GPR_ASSERT(*max_response_message_bytes ==
+ res->expected_max_response_message_bytes);
+ }
grpc_resolver_result_unref(exec_ctx, res->resolver_result);
}
@@ -67,13 +109,43 @@ static void test_succeeds(grpc_resolver_factory *factory, const char *string) {
args.uri = uri;
resolver = grpc_resolver_factory_create_resolver(factory, &args);
GPR_ASSERT(resolver != NULL);
-
on_resolution_arg on_res_arg;
memset(&on_res_arg, 0, sizeof(on_res_arg));
on_res_arg.expected_server_name = uri->path;
grpc_closure *on_resolution =
grpc_closure_create(on_resolution_cb, &on_res_arg);
+ grpc_resolver_next(&exec_ctx, resolver, &on_res_arg.resolver_result,
+ on_resolution);
+ GRPC_RESOLVER_UNREF(&exec_ctx, resolver, "test_succeeds");
+ grpc_exec_ctx_finish(&exec_ctx);
+ grpc_uri_destroy(uri);
+}
+static void test_succeeds_with_service_config(
+ grpc_resolver_factory *factory, const char *string, const char *method_name,
+ bool wait_for_ready, gpr_timespec timeout,
+ int32_t max_request_message_bytes, int32_t max_response_message_bytes) {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_uri *uri = grpc_uri_parse(string, 0);
+ grpc_resolver_args args;
+ grpc_resolver *resolver;
+ gpr_log(GPR_DEBUG, "test: '%s' should be valid for '%s'", string,
+ factory->vtable->scheme);
+ GPR_ASSERT(uri);
+ memset(&args, 0, sizeof(args));
+ args.uri = uri;
+ resolver = grpc_resolver_factory_create_resolver(factory, &args);
+ GPR_ASSERT(resolver != NULL);
+ on_resolution_arg on_res_arg;
+ memset(&on_res_arg, 0, sizeof(on_res_arg));
+ on_res_arg.expected_server_name = uri->path;
+ on_res_arg.expected_method_name = method_name;
+ on_res_arg.expected_wait_for_ready = wait_for_ready;
+ on_res_arg.expected_timeout = timeout;
+ on_res_arg.expected_max_request_message_bytes = max_request_message_bytes;
+ on_res_arg.expected_max_response_message_bytes = max_response_message_bytes;
+ grpc_closure *on_resolution =
+ grpc_closure_create(on_resolution_cb, &on_res_arg);
grpc_resolver_next(&exec_ctx, resolver, &on_res_arg.resolver_result,
on_resolution);
GRPC_RESOLVER_UNREF(&exec_ctx, resolver, "test_succeeds");
@@ -119,6 +191,16 @@ int main(int argc, char **argv) {
test_fails(ipv6, "ipv6:[::]:123456");
test_fails(ipv6, "ipv6:www.google.com");
+ test_succeeds_with_service_config(
+ ipv4,
+ "ipv4:127.0.0.1:1234?method_name=/service/method"
+ "&wait_for_ready=1"
+ "&timeout_seconds=7"
+ "&max_request_message_bytes=456"
+ "&max_response_message_bytes=789",
+ "/service/method", true /* wait_for_ready */,
+ (gpr_timespec){7, 0, GPR_CLOCK_MONOTONIC}, 456, 789);
+
grpc_resolver_factory_unref(ipv4);
grpc_resolver_factory_unref(ipv6);
grpc_shutdown();
diff --git a/test/core/end2end/fake_resolver.c b/test/core/end2end/fake_resolver.c
index 9b5e01b2a8..3878952f21 100644
--- a/test/core/end2end/fake_resolver.c
+++ b/test/core/end2end/fake_resolver.c
@@ -42,6 +42,7 @@
#include <grpc/support/port_platform.h>
#include <grpc/support/string_util.h>
+#include "src/core/ext/client_config/method_config.h"
#include "src/core/ext/client_config/parse_address.h"
#include "src/core/ext/client_config/resolver_registry.h"
#include "src/core/lib/channel/channel_args.h"
@@ -63,6 +64,7 @@ typedef struct {
char* target_name; // the path component of the uri passed in
grpc_lb_addresses* addresses;
char* lb_policy_name;
+ grpc_method_config_table* method_config_table;
// mutex guarding the rest of the state
gpr_mu mu;
@@ -80,6 +82,7 @@ static void fake_resolver_destroy(grpc_exec_ctx* exec_ctx, grpc_resolver* gr) {
gpr_free(r->target_name);
grpc_lb_addresses_destroy(r->addresses, NULL /* user_data_destroy */);
gpr_free(r->lb_policy_name);
+ grpc_method_config_table_unref(r->method_config_table);
gpr_free(r);
}
@@ -99,10 +102,16 @@ static void fake_resolver_maybe_finish_next_locked(grpc_exec_ctx* exec_ctx,
fake_resolver* r) {
if (r->next_completion != NULL && !r->published) {
r->published = true;
+ grpc_channel_args* lb_policy_args = NULL;
+ if (r->method_config_table != NULL) {
+ const grpc_arg arg =
+ grpc_method_config_table_create_channel_arg(r->method_config_table);
+ lb_policy_args = grpc_channel_args_copy_and_add(NULL /* src */, &arg, 1);
+ }
*r->target_result = grpc_resolver_result_create(
r->target_name,
grpc_lb_addresses_copy(r->addresses, NULL /* user_data_copy */),
- r->lb_policy_name, NULL /* lb_policy_args */);
+ r->lb_policy_name, lb_policy_args);
grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL);
r->next_completion = NULL;
}
@@ -204,6 +213,44 @@ static grpc_resolver* fake_resolver_create(grpc_resolver_factory* factory,
gpr_free(r);
return NULL;
}
+ // Construct method config table.
+ // We only support parameters for a single method.
+ const char* method_name = grpc_uri_get_query_arg(args->uri, "method_name");
+ if (method_name != NULL) {
+ const char* wait_for_ready_str =
+ grpc_uri_get_query_arg(args->uri, "wait_for_ready");
+ // Anything other than "0" is interpreted as true.
+ bool wait_for_ready =
+ wait_for_ready_str != NULL && strcmp("0", wait_for_ready_str) != 0;
+ const char* timeout_str =
+ grpc_uri_get_query_arg(args->uri, "timeout_seconds");
+ gpr_timespec timeout = {timeout_str == NULL ? 0 : atoi(timeout_str), 0,
+ GPR_CLOCK_MONOTONIC};
+ const char* max_request_message_bytes_str =
+ grpc_uri_get_query_arg(args->uri, "max_request_message_bytes");
+ int32_t max_request_message_bytes =
+ max_request_message_bytes_str == NULL
+ ? 0
+ : atoi(max_request_message_bytes_str);
+ const char* max_response_message_bytes_str =
+ grpc_uri_get_query_arg(args->uri, "max_response_message_bytes");
+ int32_t max_response_message_bytes =
+ max_response_message_bytes_str == NULL
+ ? 0
+ : atoi(max_response_message_bytes_str);
+ grpc_method_config* method_config = grpc_method_config_create(
+ wait_for_ready_str == NULL ? NULL : &wait_for_ready,
+ timeout_str == NULL ? NULL : &timeout,
+ max_request_message_bytes_str == NULL ? NULL
+ : &max_request_message_bytes,
+ max_response_message_bytes_str == NULL ? NULL
+ : &max_response_message_bytes);
+ grpc_method_config_table_entry entry = {grpc_mdstr_from_string(method_name),
+ method_config};
+ r->method_config_table = grpc_method_config_table_create(1, &entry);
+ GRPC_MDSTR_UNREF(entry.method_name);
+ grpc_method_config_unref(method_config);
+ }
gpr_ref_init(&r->refs, 1);
gpr_mu_init(&r->mu);
grpc_resolver_init(&r->base, &fake_resolver_vtable);
diff --git a/test/cpp/end2end/client_crash_test.cc b/test/cpp/end2end/client_crash_test.cc
index c452ad2beb..966c04b0e3 100644
--- a/test/cpp/end2end/client_crash_test.cc
+++ b/test/cpp/end2end/client_crash_test.cc
@@ -89,7 +89,7 @@ TEST_F(CrashTest, KillBeforeWrite) {
EchoRequest request;
EchoResponse response;
ClientContext context;
- context.set_fail_fast(false);
+ context.set_wait_for_ready(true);
auto stream = stub->BidiStream(&context);
@@ -115,7 +115,7 @@ TEST_F(CrashTest, KillAfterWrite) {
EchoRequest request;
EchoResponse response;
ClientContext context;
- context.set_fail_fast(false);
+ context.set_wait_for_ready(true);
auto stream = stub->BidiStream(&context);
diff --git a/test/cpp/end2end/hybrid_end2end_test.cc b/test/cpp/end2end/hybrid_end2end_test.cc
index 82361d0e90..8cd2e66347 100644
--- a/test/cpp/end2end/hybrid_end2end_test.cc
+++ b/test/cpp/end2end/hybrid_end2end_test.cc
@@ -261,7 +261,7 @@ class HybridEnd2endTest : public ::testing::Test {
EchoRequest send_request;
EchoResponse recv_response;
ClientContext cli_ctx;
- cli_ctx.set_fail_fast(false);
+ cli_ctx.set_wait_for_ready(true);
send_request.set_message("Hello");
Status recv_status = stub_->Echo(&cli_ctx, send_request, &recv_response);
EXPECT_EQ(send_request.message(), recv_response.message());
@@ -275,7 +275,7 @@ class HybridEnd2endTest : public ::testing::Test {
EchoRequest send_request;
EchoResponse recv_response;
ClientContext cli_ctx;
- cli_ctx.set_fail_fast(false);
+ cli_ctx.set_wait_for_ready(true);
send_request.set_message("Hello");
Status recv_status = stub->Echo(&cli_ctx, send_request, &recv_response);
EXPECT_EQ(send_request.message() + "_dup", recv_response.message());
@@ -287,7 +287,7 @@ class HybridEnd2endTest : public ::testing::Test {
EchoResponse recv_response;
grpc::string expected_message;
ClientContext cli_ctx;
- cli_ctx.set_fail_fast(false);
+ cli_ctx.set_wait_for_ready(true);
send_request.set_message("Hello");
auto stream = stub_->RequestStream(&cli_ctx, &recv_response);
for (int i = 0; i < 5; i++) {
@@ -304,7 +304,7 @@ class HybridEnd2endTest : public ::testing::Test {
EchoRequest request;
EchoResponse response;
ClientContext context;
- context.set_fail_fast(false);
+ context.set_wait_for_ready(true);
request.set_message("hello");
auto stream = stub_->ResponseStream(&context, request);
@@ -324,7 +324,7 @@ class HybridEnd2endTest : public ::testing::Test {
EchoRequest request;
EchoResponse response;
ClientContext context;
- context.set_fail_fast(false);
+ context.set_wait_for_ready(true);
grpc::string msg("hello");
auto stream = stub_->BidiStream(&context);
diff --git a/test/cpp/end2end/server_crash_test_client.cc b/test/cpp/end2end/server_crash_test_client.cc
index 10a251c952..5df09cd853 100644
--- a/test/cpp/end2end/server_crash_test_client.cc
+++ b/test/cpp/end2end/server_crash_test_client.cc
@@ -65,7 +65,7 @@ int main(int argc, char** argv) {
EchoRequest request;
EchoResponse response;
grpc::ClientContext context;
- context.set_fail_fast(false);
+ context.set_wait_for_ready(true);
if (FLAGS_mode == "bidi") {
auto stream = stub->BidiStream(&context);
diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc
index b4c18bcb46..7460bb526a 100644
--- a/test/cpp/qps/driver.cc
+++ b/test/cpp/qps/driver.cc
@@ -83,7 +83,7 @@ static std::unordered_map<string, std::deque<int>> get_hosts_and_cores(
auto stub = WorkerService::NewStub(
CreateChannel(*it, InsecureChannelCredentials()));
grpc::ClientContext ctx;
- ctx.set_fail_fast(false);
+ ctx.set_wait_for_ready(true);
CoreRequest dummy;
CoreResponse cores;
grpc::Status s = stub->CoreCount(&ctx, dummy, &cores);
@@ -167,7 +167,7 @@ namespace runsc {
static ClientContext* AllocContext(list<ClientContext>* contexts) {
contexts->emplace_back();
auto context = &contexts->back();
- context->set_fail_fast(false);
+ context->set_wait_for_ready(true);
return context;
}
@@ -527,7 +527,7 @@ bool RunQuit() {
CreateChannel(workers[i], InsecureChannelCredentials()));
Void dummy;
grpc::ClientContext ctx;
- ctx.set_fail_fast(false);
+ ctx.set_wait_for_ready(true);
Status s = stub->QuitWorker(&ctx, dummy, &dummy);
if (!s.ok()) {
gpr_log(GPR_ERROR, "Worker %zu could not be properly quit because %s", i,
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index 44f147aeb1..c9317396f6 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -863,6 +863,7 @@ src/core/lib/surface/lame_client.h \
src/core/lib/surface/server.h \
src/core/lib/transport/byte_stream.h \
src/core/lib/transport/connectivity_state.h \
+src/core/lib/transport/hashtable.h \
src/core/lib/transport/metadata.h \
src/core/lib/transport/metadata_batch.h \
src/core/lib/transport/static_metadata.h \
@@ -922,6 +923,7 @@ src/core/ext/client_config/initial_connect_string.h \
src/core/ext/client_config/lb_policy.h \
src/core/ext/client_config/lb_policy_factory.h \
src/core/ext/client_config/lb_policy_registry.h \
+src/core/ext/client_config/method_config.h \
src/core/ext/client_config/parse_address.h \
src/core/ext/client_config/resolver.h \
src/core/ext/client_config/resolver_factory.h \
@@ -1037,6 +1039,7 @@ src/core/lib/surface/validate_metadata.c \
src/core/lib/surface/version.c \
src/core/lib/transport/byte_stream.c \
src/core/lib/transport/connectivity_state.c \
+src/core/lib/transport/hashtable.c \
src/core/lib/transport/metadata.c \
src/core/lib/transport/metadata_batch.c \
src/core/lib/transport/static_metadata.c \
@@ -1106,6 +1109,7 @@ src/core/ext/client_config/initial_connect_string.c \
src/core/ext/client_config/lb_policy.c \
src/core/ext/client_config/lb_policy_factory.c \
src/core/ext/client_config/lb_policy_registry.c \
+src/core/ext/client_config/method_config.c \
src/core/ext/client_config/parse_address.c \
src/core/ext/client_config/resolver.c \
src/core/ext/client_config/resolver_factory.c \
diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json
index bbdb998df3..18d27220cc 100644
--- a/tools/run_tests/sources_and_headers.json
+++ b/tools/run_tests/sources_and_headers.json
@@ -6392,6 +6392,7 @@
"src/core/lib/surface/server.h",
"src/core/lib/transport/byte_stream.h",
"src/core/lib/transport/connectivity_state.h",
+ "src/core/lib/transport/hashtable.h",
"src/core/lib/transport/metadata.h",
"src/core/lib/transport/metadata_batch.h",
"src/core/lib/transport/static_metadata.h",
@@ -6573,6 +6574,8 @@
"src/core/lib/transport/byte_stream.h",
"src/core/lib/transport/connectivity_state.c",
"src/core/lib/transport/connectivity_state.h",
+ "src/core/lib/transport/hashtable.c",
+ "src/core/lib/transport/hashtable.h",
"src/core/lib/transport/metadata.c",
"src/core/lib/transport/metadata.h",
"src/core/lib/transport/metadata_batch.c",
@@ -6603,6 +6606,7 @@
"src/core/ext/client_config/lb_policy.h",
"src/core/ext/client_config/lb_policy_factory.h",
"src/core/ext/client_config/lb_policy_registry.h",
+ "src/core/ext/client_config/method_config.h",
"src/core/ext/client_config/parse_address.h",
"src/core/ext/client_config/resolver.h",
"src/core/ext/client_config/resolver_factory.h",
@@ -6635,6 +6639,8 @@
"src/core/ext/client_config/lb_policy_factory.h",
"src/core/ext/client_config/lb_policy_registry.c",
"src/core/ext/client_config/lb_policy_registry.h",
+ "src/core/ext/client_config/method_config.c",
+ "src/core/ext/client_config/method_config.h",
"src/core/ext/client_config/parse_address.c",
"src/core/ext/client_config/parse_address.h",
"src/core/ext/client_config/resolver.c",
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj
index 965d06d1d5..b2352d74f4 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj
@@ -372,6 +372,7 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\server.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\hashtable.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h" />
@@ -431,6 +432,7 @@
<ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\lb_policy.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\lb_policy_factory.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\lb_policy_registry.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\method_config.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\parse_address.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\resolver.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\resolver_factory.h" />
@@ -635,6 +637,8 @@
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.c">
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\hashtable.c">
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.c">
@@ -773,6 +777,8 @@
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\lb_policy_registry.c">
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\method_config.c">
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\parse_address.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\resolver.c">
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
index dddd4ecce5..ee7825ae88 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
@@ -262,6 +262,9 @@
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.c">
<Filter>src\core\lib\transport</Filter>
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\hashtable.c">
+ <Filter>src\core\lib\transport</Filter>
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata.c">
<Filter>src\core\lib\transport</Filter>
</ClCompile>
@@ -469,6 +472,9 @@
<ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\lb_policy_registry.c">
<Filter>src\core\ext\client_config</Filter>
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\method_config.c">
+ <Filter>src\core\ext\client_config</Filter>
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\parse_address.c">
<Filter>src\core\ext\client_config</Filter>
</ClCompile>
@@ -899,6 +905,9 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.h">
<Filter>src\core\lib\transport</Filter>
</ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\hashtable.h">
+ <Filter>src\core\lib\transport</Filter>
+ </ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h">
<Filter>src\core\lib\transport</Filter>
</ClInclude>
@@ -1076,6 +1085,9 @@
<ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\lb_policy_registry.h">
<Filter>src\core\ext\client_config</Filter>
</ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\method_config.h">
+ <Filter>src\core\ext\client_config</Filter>
+ </ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\parse_address.h">
<Filter>src\core\ext\client_config</Filter>
</ClInclude>
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
index b724c217ed..c7375431c8 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
@@ -265,6 +265,7 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\server.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\hashtable.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h" />
@@ -483,6 +484,8 @@
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.c">
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\hashtable.c">
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.c">
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
index 92806fa04a..18cdaa5819 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
@@ -316,6 +316,9 @@
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.c">
<Filter>src\core\lib\transport</Filter>
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\hashtable.c">
+ <Filter>src\core\lib\transport</Filter>
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata.c">
<Filter>src\core\lib\transport</Filter>
</ClCompile>
@@ -686,6 +689,9 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.h">
<Filter>src\core\lib\transport</Filter>
</ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\hashtable.h">
+ <Filter>src\core\lib\transport</Filter>
+ </ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h">
<Filter>src\core\lib\transport</Filter>
</ClInclude>
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
index b46773632c..09a1e2386d 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
@@ -362,6 +362,7 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\server.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\hashtable.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h" />
@@ -397,6 +398,7 @@
<ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\lb_policy.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\lb_policy_factory.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\lb_policy_registry.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\method_config.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\parse_address.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\resolver.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\resolver_factory.h" />
@@ -603,6 +605,8 @@
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.c">
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\hashtable.c">
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.c">
@@ -689,6 +693,8 @@
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\lb_policy_registry.c">
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\method_config.c">
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\parse_address.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\resolver.c">
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
index 6ffc1eab70..df7a9b9b43 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
@@ -265,6 +265,9 @@
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.c">
<Filter>src\core\lib\transport</Filter>
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\hashtable.c">
+ <Filter>src\core\lib\transport</Filter>
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata.c">
<Filter>src\core\lib\transport</Filter>
</ClCompile>
@@ -394,6 +397,9 @@
<ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\lb_policy_registry.c">
<Filter>src\core\ext\client_config</Filter>
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\method_config.c">
+ <Filter>src\core\ext\client_config</Filter>
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\parse_address.c">
<Filter>src\core\ext\client_config</Filter>
</ClCompile>
@@ -809,6 +815,9 @@
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.h">
<Filter>src\core\lib\transport</Filter>
</ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\hashtable.h">
+ <Filter>src\core\lib\transport</Filter>
+ </ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h">
<Filter>src\core\lib\transport</Filter>
</ClInclude>
@@ -914,6 +923,9 @@
<ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\lb_policy_registry.h">
<Filter>src\core\ext\client_config</Filter>
</ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\method_config.h">
+ <Filter>src\core\ext\client_config</Filter>
+ </ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\parse_address.h">
<Filter>src\core\ext\client_config</Filter>
</ClInclude>