diff options
49 files changed, 1098 insertions, 76 deletions
@@ -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 @@ -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 @@ -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 = ×pec_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> |