diff --git a/.gitignore b/.gitignore index bc324b5f826..a8c58277c34 100644 --- a/.gitignore +++ b/.gitignore @@ -144,3 +144,5 @@ bm_*.json !.vscode/launch.json !.vscode/extensions.json +# Clion artifacts +cmake-build-debug/ diff --git a/BUILD b/BUILD index e0827d46cb1..29eed995008 100644 --- a/BUILD +++ b/BUILD @@ -2164,6 +2164,7 @@ grpc_cc_library( "include/grpcpp/impl/codegen/channel_interface.h", "include/grpcpp/impl/codegen/client_callback.h", "include/grpcpp/impl/codegen/client_context.h", + "include/grpcpp/impl/codegen/client_context_impl.h", "include/grpcpp/impl/codegen/client_interceptor.h", "include/grpcpp/impl/codegen/client_unary_call.h", "include/grpcpp/impl/codegen/completion_queue.h", @@ -2185,6 +2186,7 @@ grpc_cc_library( "include/grpcpp/impl/codegen/serialization_traits.h", "include/grpcpp/impl/codegen/server_callback.h", "include/grpcpp/impl/codegen/server_context.h", + "include/grpcpp/impl/codegen/server_context_impl.h", "include/grpcpp/impl/codegen/server_interceptor.h", "include/grpcpp/impl/codegen/server_interface.h", "include/grpcpp/impl/codegen/service_type.h", diff --git a/BUILD.gn b/BUILD.gn index 258cdc9f873..e5396f51426 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1054,6 +1054,7 @@ config("grpc_config") { "include/grpcpp/impl/codegen/channel_interface.h", "include/grpcpp/impl/codegen/client_callback.h", "include/grpcpp/impl/codegen/client_context.h", + "include/grpcpp/impl/codegen/client_context_impl.h", "include/grpcpp/impl/codegen/client_interceptor.h", "include/grpcpp/impl/codegen/client_unary_call.h", "include/grpcpp/impl/codegen/completion_queue.h", @@ -1081,6 +1082,7 @@ config("grpc_config") { "include/grpcpp/impl/codegen/serialization_traits.h", "include/grpcpp/impl/codegen/server_callback.h", "include/grpcpp/impl/codegen/server_context.h", + "include/grpcpp/impl/codegen/server_context_impl.h", "include/grpcpp/impl/codegen/server_interceptor.h", "include/grpcpp/impl/codegen/server_interface.h", "include/grpcpp/impl/codegen/service_type.h", diff --git a/CMakeLists.txt b/CMakeLists.txt index e9d2168b8de..900b527d9fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,6 +82,8 @@ if(UNIX) set(_gRPC_PLATFORM_LINUX ON) elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set(_gRPC_PLATFORM_MAC ON) + elseif(${CMAKE_SYSTEM_NAME} MATCHES "iOS") + set(_gRPC_PLATFORM_IOS ON) elseif(${CMAKE_SYSTEM_NAME} MATCHES "Android") set(_gRPC_PLATFORM_ANDROID ON) else() @@ -124,7 +126,7 @@ if(gRPC_BACKWARDS_COMPATIBILITY_MODE) endif() endif() -if (_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC) +if (_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_IOS) # C core has C++ source code, but should not depend on libstc++ (for better portability). # We need to use a few tricks to convince cmake to do that. # https://stackoverflow.com/questions/15058403/how-to-stop-cmake-from-linking-against-libstdc @@ -149,7 +151,7 @@ if(NOT MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") endif() -if(_gRPC_PLATFORM_MAC) +if(_gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_IOS) set(_gRPC_ALLTARGETS_LIBRARIES ${CMAKE_DL_LIBS} m pthread) elseif(_gRPC_PLATFORM_ANDROID) set(_gRPC_ALLTARGETS_LIBRARIES ${CMAKE_DL_LIBS} m) @@ -3313,6 +3315,7 @@ foreach(_hdr include/grpcpp/impl/codegen/channel_interface.h include/grpcpp/impl/codegen/client_callback.h include/grpcpp/impl/codegen/client_context.h + include/grpcpp/impl/codegen/client_context_impl.h include/grpcpp/impl/codegen/client_interceptor.h include/grpcpp/impl/codegen/client_unary_call.h include/grpcpp/impl/codegen/completion_queue.h @@ -3334,6 +3337,7 @@ foreach(_hdr include/grpcpp/impl/codegen/serialization_traits.h include/grpcpp/impl/codegen/server_callback.h include/grpcpp/impl/codegen/server_context.h + include/grpcpp/impl/codegen/server_context_impl.h include/grpcpp/impl/codegen/server_interceptor.h include/grpcpp/impl/codegen/server_interface.h include/grpcpp/impl/codegen/service_type.h @@ -3932,6 +3936,7 @@ foreach(_hdr include/grpcpp/impl/codegen/channel_interface.h include/grpcpp/impl/codegen/client_callback.h include/grpcpp/impl/codegen/client_context.h + include/grpcpp/impl/codegen/client_context_impl.h include/grpcpp/impl/codegen/client_interceptor.h include/grpcpp/impl/codegen/client_unary_call.h include/grpcpp/impl/codegen/completion_queue.h @@ -3953,6 +3958,7 @@ foreach(_hdr include/grpcpp/impl/codegen/serialization_traits.h include/grpcpp/impl/codegen/server_callback.h include/grpcpp/impl/codegen/server_context.h + include/grpcpp/impl/codegen/server_context_impl.h include/grpcpp/impl/codegen/server_interceptor.h include/grpcpp/impl/codegen/server_interface.h include/grpcpp/impl/codegen/service_type.h @@ -4367,6 +4373,7 @@ foreach(_hdr include/grpcpp/impl/codegen/channel_interface.h include/grpcpp/impl/codegen/client_callback.h include/grpcpp/impl/codegen/client_context.h + include/grpcpp/impl/codegen/client_context_impl.h include/grpcpp/impl/codegen/client_interceptor.h include/grpcpp/impl/codegen/client_unary_call.h include/grpcpp/impl/codegen/completion_queue.h @@ -4388,6 +4395,7 @@ foreach(_hdr include/grpcpp/impl/codegen/serialization_traits.h include/grpcpp/impl/codegen/server_callback.h include/grpcpp/impl/codegen/server_context.h + include/grpcpp/impl/codegen/server_context_impl.h include/grpcpp/impl/codegen/server_interceptor.h include/grpcpp/impl/codegen/server_interface.h include/grpcpp/impl/codegen/service_type.h @@ -4566,6 +4574,7 @@ foreach(_hdr include/grpcpp/impl/codegen/channel_interface.h include/grpcpp/impl/codegen/client_callback.h include/grpcpp/impl/codegen/client_context.h + include/grpcpp/impl/codegen/client_context_impl.h include/grpcpp/impl/codegen/client_interceptor.h include/grpcpp/impl/codegen/client_unary_call.h include/grpcpp/impl/codegen/completion_queue.h @@ -4587,6 +4596,7 @@ foreach(_hdr include/grpcpp/impl/codegen/serialization_traits.h include/grpcpp/impl/codegen/server_callback.h include/grpcpp/impl/codegen/server_context.h + include/grpcpp/impl/codegen/server_context_impl.h include/grpcpp/impl/codegen/server_interceptor.h include/grpcpp/impl/codegen/server_interface.h include/grpcpp/impl/codegen/service_type.h @@ -4925,6 +4935,7 @@ foreach(_hdr include/grpcpp/impl/codegen/channel_interface.h include/grpcpp/impl/codegen/client_callback.h include/grpcpp/impl/codegen/client_context.h + include/grpcpp/impl/codegen/client_context_impl.h include/grpcpp/impl/codegen/client_interceptor.h include/grpcpp/impl/codegen/client_unary_call.h include/grpcpp/impl/codegen/completion_queue.h @@ -4946,6 +4957,7 @@ foreach(_hdr include/grpcpp/impl/codegen/serialization_traits.h include/grpcpp/impl/codegen/server_callback.h include/grpcpp/impl/codegen/server_context.h + include/grpcpp/impl/codegen/server_context_impl.h include/grpcpp/impl/codegen/server_interceptor.h include/grpcpp/impl/codegen/server_interface.h include/grpcpp/impl/codegen/service_type.h diff --git a/Makefile b/Makefile index e56c5ec4e47..0325374e39e 100644 --- a/Makefile +++ b/Makefile @@ -5670,6 +5670,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/channel_interface.h \ include/grpcpp/impl/codegen/client_callback.h \ include/grpcpp/impl/codegen/client_context.h \ + include/grpcpp/impl/codegen/client_context_impl.h \ include/grpcpp/impl/codegen/client_interceptor.h \ include/grpcpp/impl/codegen/client_unary_call.h \ include/grpcpp/impl/codegen/completion_queue.h \ @@ -5691,6 +5692,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/serialization_traits.h \ include/grpcpp/impl/codegen/server_callback.h \ include/grpcpp/impl/codegen/server_context.h \ + include/grpcpp/impl/codegen/server_context_impl.h \ include/grpcpp/impl/codegen/server_interceptor.h \ include/grpcpp/impl/codegen/server_interface.h \ include/grpcpp/impl/codegen/service_type.h \ @@ -6297,6 +6299,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/channel_interface.h \ include/grpcpp/impl/codegen/client_callback.h \ include/grpcpp/impl/codegen/client_context.h \ + include/grpcpp/impl/codegen/client_context_impl.h \ include/grpcpp/impl/codegen/client_interceptor.h \ include/grpcpp/impl/codegen/client_unary_call.h \ include/grpcpp/impl/codegen/completion_queue.h \ @@ -6318,6 +6321,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/serialization_traits.h \ include/grpcpp/impl/codegen/server_callback.h \ include/grpcpp/impl/codegen/server_context.h \ + include/grpcpp/impl/codegen/server_context_impl.h \ include/grpcpp/impl/codegen/server_interceptor.h \ include/grpcpp/impl/codegen/server_interface.h \ include/grpcpp/impl/codegen/service_type.h \ @@ -6704,6 +6708,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/channel_interface.h \ include/grpcpp/impl/codegen/client_callback.h \ include/grpcpp/impl/codegen/client_context.h \ + include/grpcpp/impl/codegen/client_context_impl.h \ include/grpcpp/impl/codegen/client_interceptor.h \ include/grpcpp/impl/codegen/client_unary_call.h \ include/grpcpp/impl/codegen/completion_queue.h \ @@ -6725,6 +6730,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/serialization_traits.h \ include/grpcpp/impl/codegen/server_callback.h \ include/grpcpp/impl/codegen/server_context.h \ + include/grpcpp/impl/codegen/server_context_impl.h \ include/grpcpp/impl/codegen/server_interceptor.h \ include/grpcpp/impl/codegen/server_interface.h \ include/grpcpp/impl/codegen/service_type.h \ @@ -6874,6 +6880,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/channel_interface.h \ include/grpcpp/impl/codegen/client_callback.h \ include/grpcpp/impl/codegen/client_context.h \ + include/grpcpp/impl/codegen/client_context_impl.h \ include/grpcpp/impl/codegen/client_interceptor.h \ include/grpcpp/impl/codegen/client_unary_call.h \ include/grpcpp/impl/codegen/completion_queue.h \ @@ -6895,6 +6902,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/serialization_traits.h \ include/grpcpp/impl/codegen/server_callback.h \ include/grpcpp/impl/codegen/server_context.h \ + include/grpcpp/impl/codegen/server_context_impl.h \ include/grpcpp/impl/codegen/server_interceptor.h \ include/grpcpp/impl/codegen/server_interface.h \ include/grpcpp/impl/codegen/service_type.h \ @@ -7239,6 +7247,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/channel_interface.h \ include/grpcpp/impl/codegen/client_callback.h \ include/grpcpp/impl/codegen/client_context.h \ + include/grpcpp/impl/codegen/client_context_impl.h \ include/grpcpp/impl/codegen/client_interceptor.h \ include/grpcpp/impl/codegen/client_unary_call.h \ include/grpcpp/impl/codegen/completion_queue.h \ @@ -7260,6 +7269,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/serialization_traits.h \ include/grpcpp/impl/codegen/server_callback.h \ include/grpcpp/impl/codegen/server_context.h \ + include/grpcpp/impl/codegen/server_context_impl.h \ include/grpcpp/impl/codegen/server_interceptor.h \ include/grpcpp/impl/codegen/server_interface.h \ include/grpcpp/impl/codegen/service_type.h \ diff --git a/build.yaml b/build.yaml index 5c085f18787..bb53d6693fe 100644 --- a/build.yaml +++ b/build.yaml @@ -1260,6 +1260,7 @@ filegroups: - include/grpcpp/impl/codegen/channel_interface.h - include/grpcpp/impl/codegen/client_callback.h - include/grpcpp/impl/codegen/client_context.h + - include/grpcpp/impl/codegen/client_context_impl.h - include/grpcpp/impl/codegen/client_interceptor.h - include/grpcpp/impl/codegen/client_unary_call.h - include/grpcpp/impl/codegen/completion_queue.h @@ -1281,6 +1282,7 @@ filegroups: - include/grpcpp/impl/codegen/serialization_traits.h - include/grpcpp/impl/codegen/server_callback.h - include/grpcpp/impl/codegen/server_context.h + - include/grpcpp/impl/codegen/server_context_impl.h - include/grpcpp/impl/codegen/server_interceptor.h - include/grpcpp/impl/codegen/server_interface.h - include/grpcpp/impl/codegen/service_type.h diff --git a/doc/environment_variables.md b/doc/environment_variables.md index 778560d4273..ff6eaba57b7 100644 --- a/doc/environment_variables.md +++ b/doc/environment_variables.md @@ -39,7 +39,6 @@ some configuration as environment variables that can be set. gRPC C core is processing requests via debug logs. Available tracers include: - api - traces api calls to the C core - bdp_estimator - traces behavior of bdp estimation logic - - call_combiner - traces call combiner state - call_error - traces the possible errors contributing to final call status - cares_resolver - traces operations of the c-ares based DNS resolver - cares_address_sorting - traces operations of the c-ares based DNS @@ -52,9 +51,6 @@ some configuration as environment variables that can be set. - connectivity_state - traces connectivity state changes to channels - cronet - traces state in the cronet transport engine - executor - traces grpc's internal thread pool ('the executor') - - fd_trace - traces fd create(), shutdown() and close() calls for channel fds. - Also traces epoll fd create()/close() calls in epollex polling engine - traces epoll-fd creation/close calls for epollex polling engine - glb - traces the grpclb load balancer - handshaker - traces handshaking state - health_check_client - traces health checking client code @@ -74,6 +70,7 @@ some configuration as environment variables that can be set. - queue_pluck - server_channel - lightweight trace of significant server channel events - secure_endpoint - traces bytes flowing through encrypted channels + - subchannel - traces the connectivity state of subchannel - timer - timers (alarms) in the grpc internals - timer_check - more detailed trace of timer logic in grpc internals - transport_security - traces metadata about secure channel establishment @@ -85,10 +82,15 @@ some configuration as environment variables that can be set. - alarm_refcount - refcounting traces for grpc_alarm structure - metadata - tracks creation and mutation of metadata - combiner - traces combiner lock state + - call_combiner - traces call combiner state - closure - tracks closure creation, scheduling, and completion + - fd_trace - traces fd create(), shutdown() and close() calls for channel fds. + Also traces epoll fd create()/close() calls in epollex polling engine + traces epoll-fd creation/close calls for epollex polling engine - pending_tags - traces still-in-progress tags on completion queues - polling - traces the selected polling engine - polling_api - traces the api calls to polling engine + - subchannel_refcount - queue_refcount - error_refcount - stream_refcount diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index 3b463cf7b90..18ed5f89102 100644 --- a/gRPC-C++.podspec +++ b/gRPC-C++.podspec @@ -161,6 +161,7 @@ Pod::Spec.new do |s| 'include/grpcpp/impl/codegen/channel_interface.h', 'include/grpcpp/impl/codegen/client_callback.h', 'include/grpcpp/impl/codegen/client_context.h', + 'include/grpcpp/impl/codegen/client_context_impl.h', 'include/grpcpp/impl/codegen/client_interceptor.h', 'include/grpcpp/impl/codegen/client_unary_call.h', 'include/grpcpp/impl/codegen/completion_queue.h', @@ -182,6 +183,7 @@ Pod::Spec.new do |s| 'include/grpcpp/impl/codegen/serialization_traits.h', 'include/grpcpp/impl/codegen/server_callback.h', 'include/grpcpp/impl/codegen/server_context.h', + 'include/grpcpp/impl/codegen/server_context_impl.h', 'include/grpcpp/impl/codegen/server_interceptor.h', 'include/grpcpp/impl/codegen/server_interface.h', 'include/grpcpp/impl/codegen/service_type.h', diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h index 12a94dc95ea..139c0c37a1f 100644 --- a/include/grpc/grpc_security.h +++ b/include/grpc/grpc_security.h @@ -490,7 +490,7 @@ GRPCAPI grpc_server_credentials* grpc_ssl_server_credentials_create( /** Deprecated in favor of grpc_ssl_server_credentials_create_with_options. Same as grpc_ssl_server_credentials_create method except uses grpc_ssl_client_certificate_request_type enum to support more ways to - authenticate client cerificates.*/ + authenticate client certificates.*/ GRPCAPI grpc_server_credentials* grpc_ssl_server_credentials_create_ex( const char* pem_root_certs, grpc_ssl_pem_key_cert_pair* pem_key_cert_pairs, size_t num_key_cert_pairs, diff --git a/include/grpc/grpc_security_constants.h b/include/grpc/grpc_security_constants.h index a082f670107..1be524a78f8 100644 --- a/include/grpc/grpc_security_constants.h +++ b/include/grpc/grpc_security_constants.h @@ -96,7 +96,7 @@ typedef enum { /** Server requests client certificate and enforces that the client presents a certificate. - The cerificate presented by the client is verified by the gRPC framework. + The certificate presented by the client is verified by the gRPC framework. (For a successful connection the client needs to present a certificate that can be verified against the root certificate configured by the server) diff --git a/include/grpc/impl/codegen/gpr_types.h b/include/grpc/impl/codegen/gpr_types.h index d7bb54527ec..6daf3398619 100644 --- a/include/grpc/impl/codegen/gpr_types.h +++ b/include/grpc/impl/codegen/gpr_types.h @@ -48,7 +48,7 @@ typedef struct gpr_timespec { int64_t tv_sec; int32_t tv_nsec; /** Against which clock was this time measured? (or GPR_TIMESPAN if - this is a relative time meaure) */ + this is a relative time measure) */ gpr_clock_type clock_type; } gpr_timespec; diff --git a/include/grpc/slice.h b/include/grpc/slice.h index 192a8cfeef4..51fc62b44df 100644 --- a/include/grpc/slice.h +++ b/include/grpc/slice.h @@ -107,7 +107,7 @@ GPRAPI grpc_slice grpc_slice_sub_no_ref(grpc_slice s, size_t begin, size_t end); /** Splits s into two: modifies s to be s[0:split], and returns a new slice, sharing a refcount with s, that contains s[split:s.length]. - Requires s intialized, split <= s.length */ + Requires s initialized, split <= s.length */ GPRAPI grpc_slice grpc_slice_split_tail(grpc_slice* s, size_t split); typedef enum { @@ -124,7 +124,7 @@ GPRAPI grpc_slice grpc_slice_split_tail_maybe_ref(grpc_slice* s, size_t split, /** Splits s into two: modifies s to be s[split:s.length], and returns a new slice, sharing a refcount with s, that contains s[0:split]. - Requires s intialized, split <= s.length */ + Requires s initialized, split <= s.length */ GPRAPI grpc_slice grpc_slice_split_head(grpc_slice* s, size_t split); GPRAPI grpc_slice grpc_empty_slice(void); diff --git a/include/grpcpp/channel_impl.h b/include/grpcpp/channel_impl.h index 39917d2eb74..a7eee2b8981 100644 --- a/include/grpcpp/channel_impl.h +++ b/include/grpcpp/channel_impl.h @@ -85,7 +85,7 @@ class Channel final : public ::grpc::ChannelInterface, interceptor_creators); ::grpc::internal::Call CreateCall(const ::grpc::internal::RpcMethod& method, - ::grpc::ClientContext* context, + ::grpc_impl::ClientContext* context, ::grpc::CompletionQueue* cq) override; void PerformOpsOnCall(::grpc::internal::CallOpSetInterface* ops, ::grpc::internal::Call* call) override; @@ -100,8 +100,9 @@ class Channel final : public ::grpc::ChannelInterface, ::grpc::CompletionQueue* CallbackCQ() override; ::grpc::internal::Call CreateCallInternal( - const ::grpc::internal::RpcMethod& method, ::grpc::ClientContext* context, - ::grpc::CompletionQueue* cq, size_t interceptor_pos) override; + const ::grpc::internal::RpcMethod& method, + ::grpc_impl::ClientContext* context, ::grpc::CompletionQueue* cq, + size_t interceptor_pos) override; const grpc::string host_; grpc_channel* const c_channel_; // owned diff --git a/include/grpcpp/impl/codegen/channel_interface.h b/include/grpcpp/impl/codegen/channel_interface.h index 9df233b5500..836c287e509 100644 --- a/include/grpcpp/impl/codegen/channel_interface.h +++ b/include/grpcpp/impl/codegen/channel_interface.h @@ -25,12 +25,12 @@ #include namespace grpc_impl { +class ClientContext; class CompletionQueue; -} +} // namespace grpc_impl namespace grpc { class ChannelInterface; -class ClientContext; template class ClientReader; @@ -129,7 +129,7 @@ class ChannelInterface { friend class ::grpc::internal::RpcMethod; friend class ::grpc::internal::InterceptedChannel; virtual internal::Call CreateCall(const internal::RpcMethod& method, - ClientContext* context, + ::grpc_impl::ClientContext* context, ::grpc_impl::CompletionQueue* cq) = 0; virtual void PerformOpsOnCall(internal::CallOpSetInterface* ops, internal::Call* call) = 0; @@ -149,7 +149,7 @@ class ChannelInterface { // method and adding a new pure method to an interface would be a breaking // change (even though this is private and non-API) virtual internal::Call CreateCallInternal(const internal::RpcMethod& method, - ClientContext* context, + ::grpc_impl::ClientContext* context, ::grpc_impl::CompletionQueue* cq, size_t interceptor_pos) { return internal::Call(); diff --git a/include/grpcpp/impl/codegen/client_callback.h b/include/grpcpp/impl/codegen/client_callback.h index dda9aec29f3..6cba5830e4b 100644 --- a/include/grpcpp/impl/codegen/client_callback.h +++ b/include/grpcpp/impl/codegen/client_callback.h @@ -31,12 +31,11 @@ namespace grpc_impl { class Channel; -} +class ClientContext; +} // namespace grpc_impl namespace grpc { -class ClientContext; - namespace internal { class RpcMethod; diff --git a/include/grpcpp/impl/codegen/client_context.h b/include/grpcpp/impl/codegen/client_context.h index 999d8fcbfe7..02389464ce4 100644 --- a/include/grpcpp/impl/codegen/client_context.h +++ b/include/grpcpp/impl/codegen/client_context.h @@ -1,6 +1,6 @@ /* * - * Copyright 2015 gRPC authors. + * Copyright 2019 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,477 +16,15 @@ * */ -/// A ClientContext allows the person implementing a service client to: -/// -/// - Add custom metadata key-value pairs that will propagated to the server -/// side. -/// - Control call settings such as compression and authentication. -/// - Initial and trailing metadata coming from the server. -/// - Get performance metrics (ie, census). -/// -/// Context settings are only relevant to the call they are invoked with, that -/// is to say, they aren't sticky. Some of these settings, such as the -/// compression options, can be made persistent at channel construction time -/// (see \a grpc::CreateCustomChannel). -/// -/// \warning ClientContext instances should \em not be reused across rpcs. - #ifndef GRPCPP_IMPL_CODEGEN_CLIENT_CONTEXT_H #define GRPCPP_IMPL_CODEGEN_CLIENT_CONTEXT_H -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct census_context; -struct grpc_call; - -namespace grpc_impl { +#include -class CallCredentials; -class Channel; -class CompletionQueue; -} // namespace grpc_impl namespace grpc { -class ChannelInterface; -class ClientContext; - -namespace internal { -class RpcMethod; -class CallOpClientRecvStatus; -class CallOpRecvInitialMetadata; -template -class BlockingUnaryCallImpl; -template -class CallbackUnaryCallImpl; -template -class ClientCallbackReaderWriterImpl; -template -class ClientCallbackReaderImpl; -template -class ClientCallbackWriterImpl; -class ClientCallbackUnaryImpl; -} // namespace internal - -template -class ClientReader; -template -class ClientWriter; -template -class ClientReaderWriter; -template -class ClientAsyncReader; -template -class ClientAsyncWriter; -template -class ClientAsyncReaderWriter; -template -class ClientAsyncResponseReader; -class ServerContext; - -/// Options for \a ClientContext::FromServerContext specifying which traits from -/// the \a ServerContext to propagate (copy) from it into a new \a -/// ClientContext. -/// -/// \see ClientContext::FromServerContext -class PropagationOptions { - public: - PropagationOptions() : propagate_(GRPC_PROPAGATE_DEFAULTS) {} - - PropagationOptions& enable_deadline_propagation() { - propagate_ |= GRPC_PROPAGATE_DEADLINE; - return *this; - } - - PropagationOptions& disable_deadline_propagation() { - propagate_ &= ~GRPC_PROPAGATE_DEADLINE; - return *this; - } - - PropagationOptions& enable_census_stats_propagation() { - propagate_ |= GRPC_PROPAGATE_CENSUS_STATS_CONTEXT; - return *this; - } - - PropagationOptions& disable_census_stats_propagation() { - propagate_ &= ~GRPC_PROPAGATE_CENSUS_STATS_CONTEXT; - return *this; - } - - PropagationOptions& enable_census_tracing_propagation() { - propagate_ |= GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT; - return *this; - } - - PropagationOptions& disable_census_tracing_propagation() { - propagate_ &= ~GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT; - return *this; - } - - PropagationOptions& enable_cancellation_propagation() { - propagate_ |= GRPC_PROPAGATE_CANCELLATION; - return *this; - } - - PropagationOptions& disable_cancellation_propagation() { - propagate_ &= ~GRPC_PROPAGATE_CANCELLATION; - return *this; - } - - uint32_t c_bitmask() const { return propagate_; } - - private: - uint32_t propagate_; -}; - -namespace testing { -class InteropClientContextInspector; -} // namespace testing - -/// A ClientContext allows the person implementing a service client to: -/// -/// - Add custom metadata key-value pairs that will propagated to the server -/// side. -/// - Control call settings such as compression and authentication. -/// - Initial and trailing metadata coming from the server. -/// - Get performance metrics (ie, census). -/// -/// Context settings are only relevant to the call they are invoked with, that -/// is to say, they aren't sticky. Some of these settings, such as the -/// compression options, can be made persistent at channel construction time -/// (see \a grpc::CreateCustomChannel). -/// -/// \warning ClientContext instances should \em not be reused across rpcs. -/// \warning The ClientContext instance used for creating an rpc must remain -/// alive and valid for the lifetime of the rpc. -class ClientContext { - public: - ClientContext(); - ~ClientContext(); - - /// Create a new \a ClientContext as a child of an incoming server call, - /// according to \a options (\see PropagationOptions). - /// - /// \param server_context The source server context to use as the basis for - /// constructing the client context. - /// \param options The options controlling what to copy from the \a - /// server_context. - /// - /// \return A newly constructed \a ClientContext instance based on \a - /// server_context, with traits propagated (copied) according to \a options. - static std::unique_ptr FromServerContext( - const ServerContext& server_context, - PropagationOptions options = PropagationOptions()); - - /// Add the (\a meta_key, \a meta_value) pair to the metadata associated with - /// a client call. These are made available at the server side by the \a - /// grpc::ServerContext::client_metadata() method. - /// - /// \warning This method should only be called before invoking the rpc. - /// - /// \param meta_key The metadata key. If \a meta_value is binary data, it must - /// end in "-bin". - /// \param meta_value The metadata value. If its value is binary, the key name - /// must end in "-bin". - /// - /// Metadata must conform to the following format: - /// Custom-Metadata -> Binary-Header / ASCII-Header - /// Binary-Header -> {Header-Name "-bin" } {binary value} - /// ASCII-Header -> Header-Name ASCII-Value - /// Header-Name -> 1*( %x30-39 / %x61-7A / "_" / "-" / ".") ; 0-9 a-z _ - . - /// ASCII-Value -> 1*( %x20-%x7E ) ; space and printable ASCII - void AddMetadata(const grpc::string& meta_key, - const grpc::string& meta_value); - - /// Return a collection of initial metadata key-value pairs. Note that keys - /// may happen more than once (ie, a \a std::multimap is returned). - /// - /// \warning This method should only be called after initial metadata has been - /// received. For streaming calls, see \a - /// ClientReaderInterface::WaitForInitialMetadata(). - /// - /// \return A multimap of initial metadata key-value pairs from the server. - const std::multimap& - GetServerInitialMetadata() const { - GPR_CODEGEN_ASSERT(initial_metadata_received_); - return *recv_initial_metadata_.map(); - } - - /// Return a collection of trailing metadata key-value pairs. Note that keys - /// may happen more than once (ie, a \a std::multimap is returned). - /// - /// \warning This method is only callable once the stream has finished. - /// - /// \return A multimap of metadata trailing key-value pairs from the server. - const std::multimap& - GetServerTrailingMetadata() const { - // TODO(yangg) check finished - return *trailing_metadata_.map(); - } - - /// Set the deadline for the client call. - /// - /// \warning This method should only be called before invoking the rpc. - /// - /// \param deadline the deadline for the client call. Units are determined by - /// the type used. The deadline is an absolute (not relative) time. - template - void set_deadline(const T& deadline) { - TimePoint deadline_tp(deadline); - deadline_ = deadline_tp.raw_time(); - } - - /// EXPERIMENTAL: Indicate that this request is idempotent. - /// By default, RPCs are assumed to not be idempotent. - /// - /// If true, the gRPC library assumes that it's safe to initiate - /// this RPC multiple times. - void set_idempotent(bool idempotent) { idempotent_ = idempotent; } - - /// EXPERIMENTAL: Set this request to be cacheable. - /// If set, grpc is free to use the HTTP GET verb for sending the request, - /// with the possibility of receiving a cached response. - void set_cacheable(bool cacheable) { cacheable_ = cacheable; } - - /// EXPERIMENTAL: Trigger wait-for-ready or not on this request. - /// See https://github.com/grpc/grpc/blob/master/doc/wait-for-ready.md. - /// If set, if an RPC is made when a channel's connectivity state is - /// TRANSIENT_FAILURE or CONNECTING, the call will not "fail fast", - /// and the channel will wait until the channel is READY before making the - /// call. - 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); } - - /// Return the deadline for the client call. - std::chrono::system_clock::time_point deadline() const { - return Timespec2Timepoint(deadline_); - } - - /// Return a \a gpr_timespec representation of the client call's deadline. - gpr_timespec raw_deadline() const { return deadline_; } - - /// Set the per call authority header (see - /// https://tools.ietf.org/html/rfc7540#section-8.1.2.3). - void set_authority(const grpc::string& authority) { authority_ = authority; } - - /// Return the authentication context for this client call. - /// - /// \see grpc::AuthContext. - std::shared_ptr auth_context() const { - if (auth_context_.get() == nullptr) { - auth_context_ = CreateAuthContext(call_); - } - return auth_context_; - } - - /// Set credentials for the client call. - /// - /// A credentials object encapsulates all the state needed by a client to - /// authenticate with a server and make various assertions, e.g., about the - /// client’s identity, role, or whether it is authorized to make a particular - /// call. - /// - /// \see https://grpc.io/docs/guides/auth.html - void set_credentials( - const std::shared_ptr& creds) { - creds_ = creds; - } - - /// Return the compression algorithm the client call will request be used. - /// Note that the gRPC runtime may decide to ignore this request, for example, - /// due to resource constraints. - grpc_compression_algorithm compression_algorithm() const { - return compression_algorithm_; - } - - /// Set \a algorithm to be the compression algorithm used for the client call. - /// - /// \param algorithm The compression algorithm used for the client call. - void set_compression_algorithm(grpc_compression_algorithm algorithm); - - /// Flag whether the initial metadata should be \a corked - /// - /// If \a corked is true, then the initial metadata will be coalesced with the - /// write of first message in the stream. As a result, any tag set for the - /// initial metadata operation (starting a client-streaming or bidi-streaming - /// RPC) will not actually be sent to the completion queue or delivered - /// via Next. - /// - /// \param corked The flag indicating whether the initial metadata is to be - /// corked or not. - void set_initial_metadata_corked(bool corked) { - initial_metadata_corked_ = corked; - } - - /// Return the peer uri in a string. - /// - /// \warning This value is never authenticated or subject to any security - /// related code. It must not be used for any authentication related - /// functionality. Instead, use auth_context. - /// - /// \return The call's peer URI. - grpc::string peer() const; - - /// Get and set census context. - void set_census_context(struct census_context* ccp) { census_context_ = ccp; } - struct census_context* census_context() const { - return census_context_; - } - - /// Send a best-effort out-of-band cancel on the call associated with - /// this client context. The call could be in any stage; e.g., if it is - /// already finished, it may still return success. - /// - /// There is no guarantee the call will be cancelled. - /// - /// Note that TryCancel() does not change any of the tags that are pending - /// on the completion queue. All pending tags will still be delivered - /// (though their ok result may reflect the effect of cancellation). - void TryCancel(); - - /// Global Callbacks - /// - /// Can be set exactly once per application to install hooks whenever - /// a client context is constructed and destructed. - class GlobalCallbacks { - public: - virtual ~GlobalCallbacks() {} - virtual void DefaultConstructor(ClientContext* context) = 0; - virtual void Destructor(ClientContext* context) = 0; - }; - static void SetGlobalCallbacks(GlobalCallbacks* callbacks); - - /// Should be used for framework-level extensions only. - /// Applications never need to call this method. - grpc_call* c_call() { return call_; } - - /// EXPERIMENTAL debugging API - /// - /// if status is not ok() for an RPC, this will return a detailed string - /// of the gRPC Core error that led to the failure. It should not be relied - /// upon for anything other than gaining more debug data in failure cases. - grpc::string debug_error_string() const { return debug_error_string_; } - - private: - // Disallow copy and assign. - ClientContext(const ClientContext&); - ClientContext& operator=(const ClientContext&); - - friend class ::grpc::testing::InteropClientContextInspector; - friend class ::grpc::internal::CallOpClientRecvStatus; - friend class ::grpc::internal::CallOpRecvInitialMetadata; - friend class ::grpc_impl::Channel; - template - friend class ::grpc::ClientReader; - template - friend class ::grpc::ClientWriter; - template - friend class ::grpc::ClientReaderWriter; - template - friend class ::grpc::ClientAsyncReader; - template - friend class ::grpc::ClientAsyncWriter; - template - friend class ::grpc::ClientAsyncReaderWriter; - template - friend class ::grpc::ClientAsyncResponseReader; - template - friend class ::grpc::internal::BlockingUnaryCallImpl; - template - friend class ::grpc::internal::CallbackUnaryCallImpl; - template - friend class ::grpc::internal::ClientCallbackReaderWriterImpl; - template - friend class ::grpc::internal::ClientCallbackReaderImpl; - template - friend class ::grpc::internal::ClientCallbackWriterImpl; - friend class ::grpc::internal::ClientCallbackUnaryImpl; - - // Used by friend class CallOpClientRecvStatus - void set_debug_error_string(const grpc::string& debug_error_string) { - debug_error_string_ = debug_error_string; - } - - grpc_call* call() const { return call_; } - void set_call(grpc_call* call, - const std::shared_ptr<::grpc_impl::Channel>& channel); - - experimental::ClientRpcInfo* set_client_rpc_info( - const char* method, internal::RpcMethod::RpcType type, - grpc::ChannelInterface* channel, - const std::vector< - std::unique_ptr>& - creators, - size_t interceptor_pos) { - rpc_info_ = experimental::ClientRpcInfo(this, type, method, channel); - rpc_info_.RegisterInterceptors(creators, interceptor_pos); - return &rpc_info_; - } - - uint32_t initial_metadata_flags() const { - return (idempotent_ ? GRPC_INITIAL_METADATA_IDEMPOTENT_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) | - (initial_metadata_corked_ ? GRPC_INITIAL_METADATA_CORKED : 0); - } - - grpc::string authority() { return authority_; } - - void SendCancelToInterceptors(); - - bool initial_metadata_received_; - bool wait_for_ready_; - bool wait_for_ready_explicitly_set_; - bool idempotent_; - bool cacheable_; - std::shared_ptr<::grpc_impl::Channel> channel_; - grpc::internal::Mutex mu_; - grpc_call* call_; - bool call_canceled_; - gpr_timespec deadline_; - grpc::string authority_; - std::shared_ptr creds_; - mutable std::shared_ptr auth_context_; - struct census_context* census_context_; - std::multimap send_initial_metadata_; - mutable internal::MetadataMap recv_initial_metadata_; - mutable internal::MetadataMap trailing_metadata_; - - grpc_call* propagate_from_call_; - PropagationOptions propagation_options_; - - grpc_compression_algorithm compression_algorithm_; - bool initial_metadata_corked_; - - grpc::string debug_error_string_; - - experimental::ClientRpcInfo rpc_info_; -}; +typedef ::grpc_impl::ClientContext ClientContext; +typedef ::grpc_impl::PropagationOptions PropagationOptions; } // namespace grpc diff --git a/include/grpcpp/impl/codegen/client_context_impl.h b/include/grpcpp/impl/codegen/client_context_impl.h new file mode 100644 index 00000000000..8491215cf0e --- /dev/null +++ b/include/grpcpp/impl/codegen/client_context_impl.h @@ -0,0 +1,491 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/// A ClientContext allows the person implementing a service client to: +/// +/// - Add custom metadata key-value pairs that will propagated to the server +/// side. +/// - Control call settings such as compression and authentication. +/// - Initial and trailing metadata coming from the server. +/// - Get performance metrics (ie, census). +/// +/// Context settings are only relevant to the call they are invoked with, that +/// is to say, they aren't sticky. Some of these settings, such as the +/// compression options, can be made persistent at channel construction time +/// (see \a grpc::CreateCustomChannel). +/// +/// \warning ClientContext instances should \em not be reused across rpcs. + +#ifndef GRPCPP_IMPL_CODEGEN_CLIENT_CONTEXT_IMPL_H +#define GRPCPP_IMPL_CODEGEN_CLIENT_CONTEXT_IMPL_H + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct census_context; +struct grpc_call; + +namespace grpc { + +class ChannelInterface; + +namespace internal { +class RpcMethod; +class CallOpClientRecvStatus; +class CallOpRecvInitialMetadata; +template +class BlockingUnaryCallImpl; +template +class CallbackUnaryCallImpl; +template +class ClientCallbackReaderWriterImpl; +template +class ClientCallbackReaderImpl; +template +class ClientCallbackWriterImpl; +class ClientCallbackUnaryImpl; +} // namespace internal + +template +class ClientReader; +template +class ClientWriter; +template +class ClientReaderWriter; +template +class ClientAsyncReader; +template +class ClientAsyncWriter; +template +class ClientAsyncReaderWriter; +template +class ClientAsyncResponseReader; + +namespace testing { +class InteropClientContextInspector; +} // namespace testing +} // namespace grpc +namespace grpc_impl { + +class CallCredentials; +class Channel; +class CompletionQueue; +class ServerContext; + +/// Options for \a ClientContext::FromServerContext specifying which traits from +/// the \a ServerContext to propagate (copy) from it into a new \a +/// ClientContext. +/// +/// \see ClientContext::FromServerContext +class PropagationOptions { + public: + PropagationOptions() : propagate_(GRPC_PROPAGATE_DEFAULTS) {} + + PropagationOptions& enable_deadline_propagation() { + propagate_ |= GRPC_PROPAGATE_DEADLINE; + return *this; + } + + PropagationOptions& disable_deadline_propagation() { + propagate_ &= ~GRPC_PROPAGATE_DEADLINE; + return *this; + } + + PropagationOptions& enable_census_stats_propagation() { + propagate_ |= GRPC_PROPAGATE_CENSUS_STATS_CONTEXT; + return *this; + } + + PropagationOptions& disable_census_stats_propagation() { + propagate_ &= ~GRPC_PROPAGATE_CENSUS_STATS_CONTEXT; + return *this; + } + + PropagationOptions& enable_census_tracing_propagation() { + propagate_ |= GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT; + return *this; + } + + PropagationOptions& disable_census_tracing_propagation() { + propagate_ &= ~GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT; + return *this; + } + + PropagationOptions& enable_cancellation_propagation() { + propagate_ |= GRPC_PROPAGATE_CANCELLATION; + return *this; + } + + PropagationOptions& disable_cancellation_propagation() { + propagate_ &= ~GRPC_PROPAGATE_CANCELLATION; + return *this; + } + + uint32_t c_bitmask() const { return propagate_; } + + private: + uint32_t propagate_; +}; + +/// A ClientContext allows the person implementing a service client to: +/// +/// - Add custom metadata key-value pairs that will propagated to the server +/// side. +/// - Control call settings such as compression and authentication. +/// - Initial and trailing metadata coming from the server. +/// - Get performance metrics (ie, census). +/// +/// Context settings are only relevant to the call they are invoked with, that +/// is to say, they aren't sticky. Some of these settings, such as the +/// compression options, can be made persistent at channel construction time +/// (see \a grpc::CreateCustomChannel). +/// +/// \warning ClientContext instances should \em not be reused across rpcs. +/// \warning The ClientContext instance used for creating an rpc must remain +/// alive and valid for the lifetime of the rpc. +class ClientContext { + public: + ClientContext(); + ~ClientContext(); + + /// Create a new \a ClientContext as a child of an incoming server call, + /// according to \a options (\see PropagationOptions). + /// + /// \param server_context The source server context to use as the basis for + /// constructing the client context. + /// \param options The options controlling what to copy from the \a + /// server_context. + /// + /// \return A newly constructed \a ClientContext instance based on \a + /// server_context, with traits propagated (copied) according to \a options. + static std::unique_ptr FromServerContext( + const grpc_impl::ServerContext& server_context, + PropagationOptions options = PropagationOptions()); + + /// Add the (\a meta_key, \a meta_value) pair to the metadata associated with + /// a client call. These are made available at the server side by the \a + /// grpc::ServerContext::client_metadata() method. + /// + /// \warning This method should only be called before invoking the rpc. + /// + /// \param meta_key The metadata key. If \a meta_value is binary data, it must + /// end in "-bin". + /// \param meta_value The metadata value. If its value is binary, the key name + /// must end in "-bin". + /// + /// Metadata must conform to the following format: + /// Custom-Metadata -> Binary-Header / ASCII-Header + /// Binary-Header -> {Header-Name "-bin" } {binary value} + /// ASCII-Header -> Header-Name ASCII-Value + /// Header-Name -> 1*( %x30-39 / %x61-7A / "_" / "-" / ".") ; 0-9 a-z _ - . + /// ASCII-Value -> 1*( %x20-%x7E ) ; space and printable ASCII + void AddMetadata(const grpc::string& meta_key, + const grpc::string& meta_value); + + /// Return a collection of initial metadata key-value pairs. Note that keys + /// may happen more than once (ie, a \a std::multimap is returned). + /// + /// \warning This method should only be called after initial metadata has been + /// received. For streaming calls, see \a + /// ClientReaderInterface::WaitForInitialMetadata(). + /// + /// \return A multimap of initial metadata key-value pairs from the server. + const std::multimap& + GetServerInitialMetadata() const { + GPR_CODEGEN_ASSERT(initial_metadata_received_); + return *recv_initial_metadata_.map(); + } + + /// Return a collection of trailing metadata key-value pairs. Note that keys + /// may happen more than once (ie, a \a std::multimap is returned). + /// + /// \warning This method is only callable once the stream has finished. + /// + /// \return A multimap of metadata trailing key-value pairs from the server. + const std::multimap& + GetServerTrailingMetadata() const { + // TODO(yangg) check finished + return *trailing_metadata_.map(); + } + + /// Set the deadline for the client call. + /// + /// \warning This method should only be called before invoking the rpc. + /// + /// \param deadline the deadline for the client call. Units are determined by + /// the type used. The deadline is an absolute (not relative) time. + template + void set_deadline(const T& deadline) { + grpc::TimePoint deadline_tp(deadline); + deadline_ = deadline_tp.raw_time(); + } + + /// EXPERIMENTAL: Indicate that this request is idempotent. + /// By default, RPCs are assumed to not be idempotent. + /// + /// If true, the gRPC library assumes that it's safe to initiate + /// this RPC multiple times. + void set_idempotent(bool idempotent) { idempotent_ = idempotent; } + + /// EXPERIMENTAL: Set this request to be cacheable. + /// If set, grpc is free to use the HTTP GET verb for sending the request, + /// with the possibility of receiving a cached response. + void set_cacheable(bool cacheable) { cacheable_ = cacheable; } + + /// EXPERIMENTAL: Trigger wait-for-ready or not on this request. + /// See https://github.com/grpc/grpc/blob/master/doc/wait-for-ready.md. + /// If set, if an RPC is made when a channel's connectivity state is + /// TRANSIENT_FAILURE or CONNECTING, the call will not "fail fast", + /// and the channel will wait until the channel is READY before making the + /// call. + 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); } + + /// Return the deadline for the client call. + std::chrono::system_clock::time_point deadline() const { + return grpc::Timespec2Timepoint(deadline_); + } + + /// Return a \a gpr_timespec representation of the client call's deadline. + gpr_timespec raw_deadline() const { return deadline_; } + + /// Set the per call authority header (see + /// https://tools.ietf.org/html/rfc7540#section-8.1.2.3). + void set_authority(const grpc::string& authority) { authority_ = authority; } + + /// Return the authentication context for this client call. + /// + /// \see grpc::AuthContext. + std::shared_ptr auth_context() const { + if (auth_context_.get() == nullptr) { + auth_context_ = grpc::CreateAuthContext(call_); + } + return auth_context_; + } + + /// Set credentials for the client call. + /// + /// A credentials object encapsulates all the state needed by a client to + /// authenticate with a server and make various assertions, e.g., about the + /// client’s identity, role, or whether it is authorized to make a particular + /// call. + /// + /// \see https://grpc.io/docs/guides/auth.html + void set_credentials( + const std::shared_ptr& creds) { + creds_ = creds; + } + + /// Return the compression algorithm the client call will request be used. + /// Note that the gRPC runtime may decide to ignore this request, for example, + /// due to resource constraints. + grpc_compression_algorithm compression_algorithm() const { + return compression_algorithm_; + } + + /// Set \a algorithm to be the compression algorithm used for the client call. + /// + /// \param algorithm The compression algorithm used for the client call. + void set_compression_algorithm(grpc_compression_algorithm algorithm); + + /// Flag whether the initial metadata should be \a corked + /// + /// If \a corked is true, then the initial metadata will be coalesced with the + /// write of first message in the stream. As a result, any tag set for the + /// initial metadata operation (starting a client-streaming or bidi-streaming + /// RPC) will not actually be sent to the completion queue or delivered + /// via Next. + /// + /// \param corked The flag indicating whether the initial metadata is to be + /// corked or not. + void set_initial_metadata_corked(bool corked) { + initial_metadata_corked_ = corked; + } + + /// Return the peer uri in a string. + /// + /// \warning This value is never authenticated or subject to any security + /// related code. It must not be used for any authentication related + /// functionality. Instead, use auth_context. + /// + /// \return The call's peer URI. + grpc::string peer() const; + + /// Get and set census context. + void set_census_context(struct census_context* ccp) { census_context_ = ccp; } + struct census_context* census_context() const { + return census_context_; + } + + /// Send a best-effort out-of-band cancel on the call associated with + /// this client context. The call could be in any stage; e.g., if it is + /// already finished, it may still return success. + /// + /// There is no guarantee the call will be cancelled. + /// + /// Note that TryCancel() does not change any of the tags that are pending + /// on the completion queue. All pending tags will still be delivered + /// (though their ok result may reflect the effect of cancellation). + void TryCancel(); + + /// Global Callbacks + /// + /// Can be set exactly once per application to install hooks whenever + /// a client context is constructed and destructed. + class GlobalCallbacks { + public: + virtual ~GlobalCallbacks() {} + virtual void DefaultConstructor(ClientContext* context) = 0; + virtual void Destructor(ClientContext* context) = 0; + }; + static void SetGlobalCallbacks(GlobalCallbacks* callbacks); + + /// Should be used for framework-level extensions only. + /// Applications never need to call this method. + grpc_call* c_call() { return call_; } + + /// EXPERIMENTAL debugging API + /// + /// if status is not ok() for an RPC, this will return a detailed string + /// of the gRPC Core error that led to the failure. It should not be relied + /// upon for anything other than gaining more debug data in failure cases. + grpc::string debug_error_string() const { return debug_error_string_; } + + private: + // Disallow copy and assign. + ClientContext(const ClientContext&); + ClientContext& operator=(const ClientContext&); + + friend class ::grpc::testing::InteropClientContextInspector; + friend class ::grpc::internal::CallOpClientRecvStatus; + friend class ::grpc::internal::CallOpRecvInitialMetadata; + friend class ::grpc_impl::Channel; + template + friend class ::grpc::ClientReader; + template + friend class ::grpc::ClientWriter; + template + friend class ::grpc::ClientReaderWriter; + template + friend class ::grpc::ClientAsyncReader; + template + friend class ::grpc::ClientAsyncWriter; + template + friend class ::grpc::ClientAsyncReaderWriter; + template + friend class ::grpc::ClientAsyncResponseReader; + template + friend class ::grpc::internal::BlockingUnaryCallImpl; + template + friend class ::grpc::internal::CallbackUnaryCallImpl; + template + friend class ::grpc::internal::ClientCallbackReaderWriterImpl; + template + friend class ::grpc::internal::ClientCallbackReaderImpl; + template + friend class ::grpc::internal::ClientCallbackWriterImpl; + friend class ::grpc::internal::ClientCallbackUnaryImpl; + + // Used by friend class CallOpClientRecvStatus + void set_debug_error_string(const grpc::string& debug_error_string) { + debug_error_string_ = debug_error_string; + } + + grpc_call* call() const { return call_; } + void set_call(grpc_call* call, + const std::shared_ptr<::grpc_impl::Channel>& channel); + + grpc::experimental::ClientRpcInfo* set_client_rpc_info( + const char* method, grpc::internal::RpcMethod::RpcType type, + grpc::ChannelInterface* channel, + const std::vector>& creators, + size_t interceptor_pos) { + rpc_info_ = grpc::experimental::ClientRpcInfo(this, type, method, channel); + rpc_info_.RegisterInterceptors(creators, interceptor_pos); + return &rpc_info_; + } + + uint32_t initial_metadata_flags() const { + return (idempotent_ ? GRPC_INITIAL_METADATA_IDEMPOTENT_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) | + (initial_metadata_corked_ ? GRPC_INITIAL_METADATA_CORKED : 0); + } + + grpc::string authority() { return authority_; } + + void SendCancelToInterceptors(); + + bool initial_metadata_received_; + bool wait_for_ready_; + bool wait_for_ready_explicitly_set_; + bool idempotent_; + bool cacheable_; + std::shared_ptr<::grpc_impl::Channel> channel_; + grpc::internal::Mutex mu_; + grpc_call* call_; + bool call_canceled_; + gpr_timespec deadline_; + grpc::string authority_; + std::shared_ptr creds_; + mutable std::shared_ptr auth_context_; + struct census_context* census_context_; + std::multimap send_initial_metadata_; + mutable grpc::internal::MetadataMap recv_initial_metadata_; + mutable grpc::internal::MetadataMap trailing_metadata_; + + grpc_call* propagate_from_call_; + PropagationOptions propagation_options_; + + grpc_compression_algorithm compression_algorithm_; + bool initial_metadata_corked_; + + grpc::string debug_error_string_; + + grpc::experimental::ClientRpcInfo rpc_info_; +}; + +} // namespace grpc_impl + +#endif // GRPCPP_IMPL_CODEGEN_CLIENT_CONTEXT_IMPL_H diff --git a/include/grpcpp/impl/codegen/client_interceptor.h b/include/grpcpp/impl/codegen/client_interceptor.h index a4c85a76da5..9e978b6a53e 100644 --- a/include/grpcpp/impl/codegen/client_interceptor.h +++ b/include/grpcpp/impl/codegen/client_interceptor.h @@ -29,12 +29,11 @@ namespace grpc_impl { class Channel; -} +class ClientContext; +} // namespace grpc_impl namespace grpc { -class ClientContext; - namespace internal { class InterceptorBatchMethodsImpl; } @@ -96,7 +95,7 @@ class ClientRpcInfo { /// Return a pointer to the underlying ClientContext structure associated /// with the RPC to support features that apply to it - grpc::ClientContext* client_context() { return ctx_; } + grpc_impl::ClientContext* client_context() { return ctx_; } /// Return the type of the RPC (unary or a streaming flavor) Type type() const { return type_; } @@ -119,8 +118,9 @@ class ClientRpcInfo { ClientRpcInfo() = default; // Constructor will only be called from ClientContext - ClientRpcInfo(grpc::ClientContext* ctx, internal::RpcMethod::RpcType type, - const char* method, grpc::ChannelInterface* channel) + ClientRpcInfo(grpc_impl::ClientContext* ctx, + internal::RpcMethod::RpcType type, const char* method, + grpc::ChannelInterface* channel) : ctx_(ctx), type_(static_cast(type)), method_(method), @@ -160,7 +160,7 @@ class ClientRpcInfo { } } - grpc::ClientContext* ctx_ = nullptr; + grpc_impl::ClientContext* ctx_ = nullptr; // TODO(yashykt): make type_ const once move-assignment is deleted Type type_{Type::UNKNOWN}; const char* method_ = nullptr; @@ -170,7 +170,7 @@ class ClientRpcInfo { size_t hijacked_interceptor_ = 0; friend class internal::InterceptorBatchMethodsImpl; - friend class grpc::ClientContext; + friend class grpc_impl::ClientContext; }; // PLEASE DO NOT USE THIS. ALWAYS PREFER PER CHANNEL INTERCEPTORS OVER A GLOBAL diff --git a/include/grpcpp/impl/codegen/client_unary_call.h b/include/grpcpp/impl/codegen/client_unary_call.h index e0f692b1783..599dd1ecac9 100644 --- a/include/grpcpp/impl/codegen/client_unary_call.h +++ b/include/grpcpp/impl/codegen/client_unary_call.h @@ -25,17 +25,19 @@ #include #include -namespace grpc { +namespace grpc_impl { class ClientContext; +} // namespace grpc_impl +namespace grpc { namespace internal { class RpcMethod; /// Wrapper that performs a blocking unary call template Status BlockingUnaryCall(ChannelInterface* channel, const RpcMethod& method, - ClientContext* context, const InputMessage& request, - OutputMessage* result) { + grpc_impl::ClientContext* context, + const InputMessage& request, OutputMessage* result) { return BlockingUnaryCallImpl( channel, method, context, request, result) .status(); @@ -45,8 +47,8 @@ template class BlockingUnaryCallImpl { public: BlockingUnaryCallImpl(ChannelInterface* channel, const RpcMethod& method, - ClientContext* context, const InputMessage& request, - OutputMessage* result) { + grpc_impl::ClientContext* context, + const InputMessage& request, OutputMessage* result) { CompletionQueue cq(grpc_completion_queue_attributes{ GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING, nullptr}); // Pluckable completion queue diff --git a/include/grpcpp/impl/codegen/completion_queue_impl.h b/include/grpcpp/impl/codegen/completion_queue_impl.h index d5c4bb0f201..0a6b0b0977b 100644 --- a/include/grpcpp/impl/codegen/completion_queue_impl.h +++ b/include/grpcpp/impl/codegen/completion_queue_impl.h @@ -46,6 +46,7 @@ namespace grpc_impl { class Channel; class Server; class ServerBuilder; +class ServerContext; } // namespace grpc_impl namespace grpc { @@ -65,8 +66,6 @@ class ServerReaderWriterBody; } // namespace internal class ChannelInterface; -class ClientContext; -class ServerContext; class ServerInterface; namespace internal { @@ -278,7 +277,7 @@ class CompletionQueue : private ::grpc::GrpcLibraryCodegen { template <::grpc::StatusCode code> friend class ::grpc::internal::ErrorMethodHandler; friend class ::grpc_impl::Server; - friend class ::grpc::ServerContext; + friend class ::grpc_impl::ServerContext; friend class ::grpc::ServerInterface; template friend class ::grpc::internal::BlockingUnaryCallImpl; diff --git a/include/grpcpp/impl/codegen/interceptor.h b/include/grpcpp/impl/codegen/interceptor.h index b0f57f71196..18c7cf33e2f 100644 --- a/include/grpcpp/impl/codegen/interceptor.h +++ b/include/grpcpp/impl/codegen/interceptor.h @@ -174,20 +174,22 @@ class InterceptorBatchMethods { /// Returns a pointer to the modifiable received message. Note that the /// message is already deserialized but the type is not set; the interceptor /// should static_cast to the appropriate type before using it. This is valid - /// for POST_RECV_MESSAGE interceptions; nullptr for not valid + /// for PRE_RECV_MESSAGE and POST_RECV_MESSAGE interceptions; nullptr for not + /// valid virtual void* GetRecvMessage() = 0; /// Returns a modifiable multimap of the received initial metadata. - /// Valid for POST_RECV_INITIAL_METADATA interceptions; nullptr if not valid + /// Valid for PRE_RECV_INITIAL_METADATA and POST_RECV_INITIAL_METADATA + /// interceptions; nullptr if not valid virtual std::multimap* GetRecvInitialMetadata() = 0; - /// Returns a modifiable view of the received status on POST_RECV_STATUS - /// interceptions; nullptr if not valid. + /// Returns a modifiable view of the received status on PRE_RECV_STATUS and + /// POST_RECV_STATUS interceptions; nullptr if not valid. virtual Status* GetRecvStatus() = 0; /// Returns a modifiable multimap of the received trailing metadata on - /// POST_RECV_STATUS interceptions; nullptr if not valid + /// PRE_RECV_STATUS and POST_RECV_STATUS interceptions; nullptr if not valid virtual std::multimap* GetRecvTrailingMetadata() = 0; diff --git a/include/grpcpp/impl/codegen/rpc_service_method.h b/include/grpcpp/impl/codegen/rpc_service_method.h index 21fb2ac2130..0b16feed820 100644 --- a/include/grpcpp/impl/codegen/rpc_service_method.h +++ b/include/grpcpp/impl/codegen/rpc_service_method.h @@ -31,9 +31,11 @@ #include #include -namespace grpc { +namespace grpc_impl { class ServerContext; +} +namespace grpc { namespace internal { /// Base class for running an RPC handler. class MethodHandler { @@ -50,7 +52,7 @@ class MethodHandler { /// \param requester : used only by the callback API. It is a function /// called by the RPC Controller to request another RPC (and also /// to set up the state required to make that request possible) - HandlerParameter(Call* c, ServerContext* context, void* req, + HandlerParameter(Call* c, ::grpc_impl::ServerContext* context, void* req, Status req_status, void* handler_data, std::function requester) : call(c), @@ -61,7 +63,7 @@ class MethodHandler { call_requester(std::move(requester)) {} ~HandlerParameter() {} Call* call; - ServerContext* server_context; + ::grpc_impl::ServerContext* server_context; void* request; Status status; void* internal_data; diff --git a/include/grpcpp/impl/codegen/server_callback.h b/include/grpcpp/impl/codegen/server_callback.h index 9254518b605..da08ec963e4 100644 --- a/include/grpcpp/impl/codegen/server_callback.h +++ b/include/grpcpp/impl/codegen/server_callback.h @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include @@ -53,7 +53,7 @@ class ServerReactor { virtual void OnCancel() = 0; private: - friend class ::grpc::ServerContext; + friend class ::grpc_impl::ServerContext; template friend class CallbackClientStreamingHandler; template @@ -313,7 +313,7 @@ class ServerBidiReactor : public internal::ServerReactor { /// is a result of the client calling StartCall(). /// /// \param[in] context The context object now associated with this RPC - virtual void OnStarted(ServerContext* context) {} + virtual void OnStarted(::grpc_impl::ServerContext* context) {} /// Notifies the application that an explicit StartSendInitialMetadata /// operation completed. Not used when the sending of initial metadata @@ -372,7 +372,7 @@ class ServerReadReactor : public internal::ServerReactor { /// /// \param[in] context The context object now associated with this RPC /// \param[in] resp The response object to be used by this RPC - virtual void OnStarted(ServerContext* context, Response* resp) {} + virtual void OnStarted(::grpc_impl::ServerContext* context, Response* resp) {} /// The following notifications are exactly like ServerBidiReactor. virtual void OnSendInitialMetadataDone(bool ok) {} @@ -413,7 +413,8 @@ class ServerWriteReactor : public internal::ServerReactor { /// /// \param[in] context The context object now associated with this RPC /// \param[in] req The request object sent by the client - virtual void OnStarted(ServerContext* context, const Request* req) {} + virtual void OnStarted(::grpc_impl::ServerContext* context, + const Request* req) {} /// The following notifications are exactly like ServerBidiReactor. virtual void OnSendInitialMetadataDone(bool ok) {} @@ -437,7 +438,7 @@ class UnimplementedReadReactor : public experimental::ServerReadReactor { public: void OnDone() override { delete this; } - void OnStarted(ServerContext*, Response*) override { + void OnStarted(::grpc_impl::ServerContext*, Response*) override { this->Finish(Status(StatusCode::UNIMPLEMENTED, "")); } }; @@ -447,7 +448,7 @@ class UnimplementedWriteReactor : public experimental::ServerWriteReactor { public: void OnDone() override { delete this; } - void OnStarted(ServerContext*, const Request*) override { + void OnStarted(::grpc_impl::ServerContext*, const Request*) override { this->Finish(Status(StatusCode::UNIMPLEMENTED, "")); } }; @@ -457,7 +458,7 @@ class UnimplementedBidiReactor : public experimental::ServerBidiReactor { public: void OnDone() override { delete this; } - void OnStarted(ServerContext*) override { + void OnStarted(::grpc_impl::ServerContext*) override { this->Finish(Status(StatusCode::UNIMPLEMENTED, "")); } }; @@ -466,7 +467,8 @@ template class CallbackUnaryHandler : public MethodHandler { public: CallbackUnaryHandler( - std::function func) : func_(func) {} @@ -525,8 +527,8 @@ class CallbackUnaryHandler : public MethodHandler { } private: - std::function + std::function func_; experimental::MessageAllocator* allocator_ = nullptr; @@ -597,7 +599,7 @@ class CallbackUnaryHandler : public MethodHandler { friend class CallbackUnaryHandler; ServerCallbackRpcControllerImpl( - ServerContext* ctx, Call* call, + ::grpc_impl::ServerContext* ctx, Call* call, experimental::MessageHolder* allocator_state, std::function call_requester) : ctx_(ctx), @@ -628,7 +630,7 @@ class CallbackUnaryHandler : public MethodHandler { finish_ops_; CallbackWithSuccessTag finish_tag_; - ServerContext* ctx_; + ::grpc_impl::ServerContext* ctx_; Call call_; experimental::MessageHolder* const allocator_state_; @@ -732,7 +734,8 @@ class CallbackClientStreamingHandler : public MethodHandler { friend class CallbackClientStreamingHandler; ServerCallbackReaderImpl( - ServerContext* ctx, Call* call, std::function call_requester, + ::grpc_impl::ServerContext* ctx, Call* call, + std::function call_requester, experimental::ServerReadReactor* reactor) : ctx_(ctx), call_(*call), @@ -772,7 +775,7 @@ class CallbackClientStreamingHandler : public MethodHandler { CallOpSet> read_ops_; CallbackWithSuccessTag read_tag_; - ServerContext* ctx_; + ::grpc_impl::ServerContext* ctx_; Call call_; ResponseType resp_; std::function call_requester_; @@ -909,7 +912,7 @@ class CallbackServerStreamingHandler : public MethodHandler { friend class CallbackServerStreamingHandler; ServerCallbackWriterImpl( - ServerContext* ctx, Call* call, const RequestType* req, + ::grpc_impl::ServerContext* ctx, Call* call, const RequestType* req, std::function call_requester, experimental::ServerWriteReactor* reactor) : ctx_(ctx), @@ -950,7 +953,7 @@ class CallbackServerStreamingHandler : public MethodHandler { CallOpSet write_ops_; CallbackWithSuccessTag write_tag_; - ServerContext* ctx_; + ::grpc_impl::ServerContext* ctx_; Call call_; const RequestType* req_; std::function call_requester_; @@ -1078,7 +1081,8 @@ class CallbackBidiHandler : public MethodHandler { friend class CallbackBidiHandler; ServerCallbackReaderWriterImpl( - ServerContext* ctx, Call* call, std::function call_requester, + ::grpc_impl::ServerContext* ctx, Call* call, + std::function call_requester, experimental::ServerBidiReactor* reactor) : ctx_(ctx), call_(*call), @@ -1124,7 +1128,7 @@ class CallbackBidiHandler : public MethodHandler { CallOpSet> read_ops_; CallbackWithSuccessTag read_tag_; - ServerContext* ctx_; + ::grpc_impl::ServerContext* ctx_; Call call_; std::function call_requester_; experimental::ServerBidiReactor* reactor_; diff --git a/include/grpcpp/impl/codegen/server_context.h b/include/grpcpp/impl/codegen/server_context.h index c6903743938..7ae12755a1c 100644 --- a/include/grpcpp/impl/codegen/server_context.h +++ b/include/grpcpp/impl/codegen/server_context.h @@ -19,361 +19,10 @@ #ifndef GRPCPP_IMPL_CODEGEN_SERVER_CONTEXT_H #define GRPCPP_IMPL_CODEGEN_SERVER_CONTEXT_H -#include -#include -#include +#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct grpc_metadata; -struct grpc_call; -struct census_context; - -namespace grpc_impl { - -class CompletionQueue; -class Server; -} // namespace grpc_impl namespace grpc { -class ClientContext; -class GenericServerContext; -class ServerInterface; -template -class ServerAsyncReader; -template -class ServerAsyncWriter; -template -class ServerAsyncResponseWriter; -template -class ServerAsyncReaderWriter; -template -class ServerReader; -template -class ServerWriter; - -namespace internal { -template -class ServerReaderWriterBody; -template -class RpcMethodHandler; -template -class ClientStreamingHandler; -template -class ServerStreamingHandler; -template -class BidiStreamingHandler; -template -class CallbackUnaryHandler; -template -class CallbackClientStreamingHandler; -template -class CallbackServerStreamingHandler; -template -class CallbackBidiHandler; -template -class TemplatedBidiStreamingHandler; -template -class ErrorMethodHandler; -class Call; -class ServerReactor; -} // namespace internal - -class ServerInterface; -namespace testing { -class InteropServerContextInspector; -class ServerContextTestSpouse; -} // namespace testing - -/// A ServerContext allows the person implementing a service handler to: -/// -/// - Add custom initial and trailing metadata key-value pairs that will -/// propagated to the client side. -/// - Control call settings such as compression and authentication. -/// - Access metadata coming from the client. -/// - Get performance metrics (ie, census). -/// -/// Context settings are only relevant to the call handler they are supplied to, -/// that is to say, they aren't sticky across multiple calls. Some of these -/// settings, such as the compression options, can be made persistent at server -/// construction time by specifying the appropriate \a ChannelArguments -/// to a \a grpc::ServerBuilder, via \a ServerBuilder::AddChannelArgument. -/// -/// \warning ServerContext instances should \em not be reused across rpcs. -class ServerContext { - public: - ServerContext(); // for async calls - ~ServerContext(); - - /// Return the deadline for the server call. - std::chrono::system_clock::time_point deadline() const { - return Timespec2Timepoint(deadline_); - } - - /// Return a \a gpr_timespec representation of the server call's deadline. - gpr_timespec raw_deadline() const { return deadline_; } - - /// Add the (\a key, \a value) pair to the initial metadata - /// associated with a server call. These are made available at the client side - /// by the \a grpc::ClientContext::GetServerInitialMetadata() method. - /// - /// \warning This method should only be called before sending initial metadata - /// to the client (which can happen explicitly, or implicitly when sending a - /// a response message or status to the client). - /// - /// \param key The metadata key. If \a value is binary data, it must - /// end in "-bin". - /// \param value The metadata value. If its value is binary, the key name - /// must end in "-bin". - /// - /// Metadata must conform to the following format: - /// Custom-Metadata -> Binary-Header / ASCII-Header - /// Binary-Header -> {Header-Name "-bin" } {binary value} - /// ASCII-Header -> Header-Name ASCII-Value - /// Header-Name -> 1*( %x30-39 / %x61-7A / "_" / "-" / ".") ; 0-9 a-z _ - . - /// ASCII-Value -> 1*( %x20-%x7E ) ; space and printable ASCII - void AddInitialMetadata(const grpc::string& key, const grpc::string& value); - - /// Add the (\a key, \a value) pair to the initial metadata - /// associated with a server call. These are made available at the client - /// side by the \a grpc::ClientContext::GetServerTrailingMetadata() method. - /// - /// \warning This method should only be called before sending trailing - /// metadata to the client (which happens when the call is finished and a - /// status is sent to the client). - /// - /// \param key The metadata key. If \a value is binary data, - /// it must end in "-bin". - /// \param value The metadata value. If its value is binary, the key name - /// must end in "-bin". - /// - /// Metadata must conform to the following format: - /// Custom-Metadata -> Binary-Header / ASCII-Header - /// Binary-Header -> {Header-Name "-bin" } {binary value} - /// ASCII-Header -> Header-Name ASCII-Value - /// Header-Name -> 1*( %x30-39 / %x61-7A / "_" / "-" / ".") ; 0-9 a-z _ - . - /// ASCII-Value -> 1*( %x20-%x7E ) ; space and printable ASCII - void AddTrailingMetadata(const grpc::string& key, const grpc::string& value); - - /// IsCancelled is always safe to call when using sync or callback API. - /// When using async API, it is only safe to call IsCancelled after - /// the AsyncNotifyWhenDone tag has been delivered. - bool IsCancelled() const; - - /// Cancel the Call from the server. This is a best-effort API and - /// depending on when it is called, the RPC may still appear successful to - /// the client. - /// For example, if TryCancel() is called on a separate thread, it might race - /// with the server handler which might return success to the client before - /// TryCancel() was even started by the thread. - /// - /// It is the caller's responsibility to prevent such races and ensure that if - /// TryCancel() is called, the serverhandler must return Status::CANCELLED. - /// The only exception is that if the serverhandler is already returning an - /// error status code, it is ok to not return Status::CANCELLED even if - /// TryCancel() was called. - /// - /// Note that TryCancel() does not change any of the tags that are pending - /// on the completion queue. All pending tags will still be delivered - /// (though their ok result may reflect the effect of cancellation). - void TryCancel() const; - - /// Return a collection of initial metadata key-value pairs sent from the - /// client. Note that keys may happen more than - /// once (ie, a \a std::multimap is returned). - /// - /// It is safe to use this method after initial metadata has been received, - /// Calls always begin with the client sending initial metadata, so this is - /// safe to access as soon as the call has begun on the server side. - /// - /// \return A multimap of initial metadata key-value pairs from the server. - const std::multimap& client_metadata() - const { - return *client_metadata_.map(); - } - - /// Return the compression algorithm to be used by the server call. - grpc_compression_level compression_level() const { - return compression_level_; - } - - /// Set \a level to be the compression level used for the server call. - /// - /// \param level The compression level used for the server call. - void set_compression_level(grpc_compression_level level) { - compression_level_set_ = true; - compression_level_ = level; - } - - /// Return a bool indicating whether the compression level for this call - /// has been set (either implicitly or through a previous call to - /// \a set_compression_level. - bool compression_level_set() const { return compression_level_set_; } - - /// Return the compression algorithm the server call will request be used. - /// Note that the gRPC runtime may decide to ignore this request, for example, - /// due to resource constraints, or if the server is aware the client doesn't - /// support the requested algorithm. - grpc_compression_algorithm compression_algorithm() const { - return compression_algorithm_; - } - /// Set \a algorithm to be the compression algorithm used for the server call. - /// - /// \param algorithm The compression algorithm used for the server call. - void set_compression_algorithm(grpc_compression_algorithm algorithm); - - /// Set the serialized load reporting costs in \a cost_data for the call. - void SetLoadReportingCosts(const std::vector& cost_data); - - /// Return the authentication context for this server call. - /// - /// \see grpc::AuthContext. - std::shared_ptr auth_context() const { - if (auth_context_.get() == nullptr) { - auth_context_ = CreateAuthContext(call_); - } - return auth_context_; - } - - /// Return the peer uri in a string. - /// WARNING: this value is never authenticated or subject to any security - /// related code. It must not be used for any authentication related - /// functionality. Instead, use auth_context. - grpc::string peer() const; - - /// Get the census context associated with this server call. - const struct census_context* census_context() const; - - /// Async only. Has to be called before the rpc starts. - /// Returns the tag in completion queue when the rpc finishes. - /// IsCancelled() can then be called to check whether the rpc was cancelled. - /// TODO(vjpai): Fix this so that the tag is returned even if the call never - /// starts (https://github.com/grpc/grpc/issues/10136). - void AsyncNotifyWhenDone(void* tag) { - has_notify_when_done_tag_ = true; - async_notify_when_done_tag_ = tag; - } - - /// Should be used for framework-level extensions only. - /// Applications never need to call this method. - grpc_call* c_call() { return call_; } - - private: - friend class ::grpc::testing::InteropServerContextInspector; - friend class ::grpc::testing::ServerContextTestSpouse; - friend class ::grpc::ServerInterface; - friend class ::grpc_impl::Server; - template - friend class ::grpc::ServerAsyncReader; - template - friend class ::grpc::ServerAsyncWriter; - template - friend class ::grpc::ServerAsyncResponseWriter; - template - friend class ::grpc::ServerAsyncReaderWriter; - template - friend class ::grpc::ServerReader; - template - friend class ::grpc::ServerWriter; - template - friend class ::grpc::internal::ServerReaderWriterBody; - template - friend class ::grpc::internal::RpcMethodHandler; - template - friend class ::grpc::internal::ClientStreamingHandler; - template - friend class ::grpc::internal::ServerStreamingHandler; - template - friend class ::grpc::internal::TemplatedBidiStreamingHandler; - template - friend class ::grpc::internal::CallbackUnaryHandler; - template - friend class ::grpc::internal::CallbackClientStreamingHandler; - template - friend class ::grpc::internal::CallbackServerStreamingHandler; - template - friend class ::grpc::internal::CallbackBidiHandler; - template - friend class internal::ErrorMethodHandler; - friend class ::grpc::ClientContext; - friend class ::grpc::GenericServerContext; - - /// Prevent copying. - ServerContext(const ServerContext&); - ServerContext& operator=(const ServerContext&); - - class CompletionOp; - - void BeginCompletionOp(internal::Call* call, - std::function callback, - internal::ServerReactor* reactor); - /// Return the tag queued by BeginCompletionOp() - internal::CompletionQueueTag* GetCompletionOpTag(); - - ServerContext(gpr_timespec deadline, grpc_metadata_array* arr); - - void set_call(grpc_call* call) { call_ = call; } - - void BindDeadlineAndMetadata(gpr_timespec deadline, grpc_metadata_array* arr); - - void Clear(); - - void Setup(gpr_timespec deadline); - - uint32_t initial_metadata_flags() const { return 0; } - - void SetCancelCallback(std::function callback); - void ClearCancelCallback(); - - experimental::ServerRpcInfo* set_server_rpc_info( - const char* method, internal::RpcMethod::RpcType type, - const std::vector< - std::unique_ptr>& - creators) { - if (creators.size() != 0) { - rpc_info_ = new experimental::ServerRpcInfo(this, method, type); - rpc_info_->RegisterInterceptors(creators); - } - return rpc_info_; - } - - CompletionOp* completion_op_; - bool has_notify_when_done_tag_; - void* async_notify_when_done_tag_; - internal::CallbackWithSuccessTag completion_tag_; - - gpr_timespec deadline_; - grpc_call* call_; - ::grpc_impl::CompletionQueue* cq_; - bool sent_initial_metadata_; - mutable std::shared_ptr auth_context_; - mutable internal::MetadataMap client_metadata_; - std::multimap initial_metadata_; - std::multimap trailing_metadata_; - - bool compression_level_set_; - grpc_compression_level compression_level_; - grpc_compression_algorithm compression_algorithm_; - - internal::CallOpSet - pending_ops_; - bool has_pending_ops_; - - experimental::ServerRpcInfo* rpc_info_; -}; - +typedef ::grpc_impl::ServerContext ServerContext; } // namespace grpc #endif // GRPCPP_IMPL_CODEGEN_SERVER_CONTEXT_H diff --git a/include/grpcpp/impl/codegen/server_context_impl.h b/include/grpcpp/impl/codegen/server_context_impl.h new file mode 100644 index 00000000000..9497735eacc --- /dev/null +++ b/include/grpcpp/impl/codegen/server_context_impl.h @@ -0,0 +1,376 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPCPP_IMPL_CODEGEN_SERVER_CONTEXT_IMPL_H +#define GRPCPP_IMPL_CODEGEN_SERVER_CONTEXT_IMPL_H +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct grpc_metadata; +struct grpc_call; +struct census_context; + +namespace grpc_impl { +class ClientContext; +class CompletionQueue; +class Server; +} // namespace grpc_impl +namespace grpc { +class GenericServerContext; +class ServerInterface; +template +class ServerAsyncReader; +template +class ServerAsyncWriter; +template +class ServerAsyncResponseWriter; +template +class ServerAsyncReaderWriter; +template +class ServerReader; +template +class ServerWriter; + +namespace internal { +template +class ServerReaderWriterBody; +template +class RpcMethodHandler; +template +class ClientStreamingHandler; +template +class ServerStreamingHandler; +template +class BidiStreamingHandler; +template +class CallbackUnaryHandler; +template +class CallbackClientStreamingHandler; +template +class CallbackServerStreamingHandler; +template +class CallbackBidiHandler; +template +class TemplatedBidiStreamingHandler; +template +class ErrorMethodHandler; +class Call; +class ServerReactor; +} // namespace internal + +class ServerInterface; +namespace testing { +class InteropServerContextInspector; +class ServerContextTestSpouse; +} // namespace testing +} // namespace grpc + +namespace grpc_impl { +/// A ServerContext allows the person implementing a service handler to: +/// +/// - Add custom initial and trailing metadata key-value pairs that will +/// propagated to the client side. +/// - Control call settings such as compression and authentication. +/// - Access metadata coming from the client. +/// - Get performance metrics (ie, census). +/// +/// Context settings are only relevant to the call handler they are supplied to, +/// that is to say, they aren't sticky across multiple calls. Some of these +/// settings, such as the compression options, can be made persistent at server +/// construction time by specifying the appropriate \a ChannelArguments +/// to a \a grpc::ServerBuilder, via \a ServerBuilder::AddChannelArgument. +/// +/// \warning ServerContext instances should \em not be reused across rpcs. +class ServerContext { + public: + ServerContext(); // for async calls + ~ServerContext(); + + /// Return the deadline for the server call. + std::chrono::system_clock::time_point deadline() const { + return ::grpc::Timespec2Timepoint(deadline_); + } + + /// Return a \a gpr_timespec representation of the server call's deadline. + gpr_timespec raw_deadline() const { return deadline_; } + + /// Add the (\a key, \a value) pair to the initial metadata + /// associated with a server call. These are made available at the client side + /// by the \a grpc::ClientContext::GetServerInitialMetadata() method. + /// + /// \warning This method should only be called before sending initial metadata + /// to the client (which can happen explicitly, or implicitly when sending a + /// a response message or status to the client). + /// + /// \param key The metadata key. If \a value is binary data, it must + /// end in "-bin". + /// \param value The metadata value. If its value is binary, the key name + /// must end in "-bin". + /// + /// Metadata must conform to the following format: + /// Custom-Metadata -> Binary-Header / ASCII-Header + /// Binary-Header -> {Header-Name "-bin" } {binary value} + /// ASCII-Header -> Header-Name ASCII-Value + /// Header-Name -> 1*( %x30-39 / %x61-7A / "_" / "-" / ".") ; 0-9 a-z _ - . + /// ASCII-Value -> 1*( %x20-%x7E ) ; space and printable ASCII + void AddInitialMetadata(const grpc::string& key, const grpc::string& value); + + /// Add the (\a key, \a value) pair to the initial metadata + /// associated with a server call. These are made available at the client + /// side by the \a grpc::ClientContext::GetServerTrailingMetadata() method. + /// + /// \warning This method should only be called before sending trailing + /// metadata to the client (which happens when the call is finished and a + /// status is sent to the client). + /// + /// \param key The metadata key. If \a value is binary data, + /// it must end in "-bin". + /// \param value The metadata value. If its value is binary, the key name + /// must end in "-bin". + /// + /// Metadata must conform to the following format: + /// Custom-Metadata -> Binary-Header / ASCII-Header + /// Binary-Header -> {Header-Name "-bin" } {binary value} + /// ASCII-Header -> Header-Name ASCII-Value + /// Header-Name -> 1*( %x30-39 / %x61-7A / "_" / "-" / ".") ; 0-9 a-z _ - . + /// ASCII-Value -> 1*( %x20-%x7E ) ; space and printable ASCII + void AddTrailingMetadata(const grpc::string& key, const grpc::string& value); + + /// IsCancelled is always safe to call when using sync or callback API. + /// When using async API, it is only safe to call IsCancelled after + /// the AsyncNotifyWhenDone tag has been delivered. + bool IsCancelled() const; + + /// Cancel the Call from the server. This is a best-effort API and + /// depending on when it is called, the RPC may still appear successful to + /// the client. + /// For example, if TryCancel() is called on a separate thread, it might race + /// with the server handler which might return success to the client before + /// TryCancel() was even started by the thread. + /// + /// It is the caller's responsibility to prevent such races and ensure that if + /// TryCancel() is called, the serverhandler must return Status::CANCELLED. + /// The only exception is that if the serverhandler is already returning an + /// error status code, it is ok to not return Status::CANCELLED even if + /// TryCancel() was called. + /// + /// Note that TryCancel() does not change any of the tags that are pending + /// on the completion queue. All pending tags will still be delivered + /// (though their ok result may reflect the effect of cancellation). + void TryCancel() const; + + /// Return a collection of initial metadata key-value pairs sent from the + /// client. Note that keys may happen more than + /// once (ie, a \a std::multimap is returned). + /// + /// It is safe to use this method after initial metadata has been received, + /// Calls always begin with the client sending initial metadata, so this is + /// safe to access as soon as the call has begun on the server side. + /// + /// \return A multimap of initial metadata key-value pairs from the server. + const std::multimap& client_metadata() + const { + return *client_metadata_.map(); + } + + /// Return the compression algorithm to be used by the server call. + grpc_compression_level compression_level() const { + return compression_level_; + } + + /// Set \a level to be the compression level used for the server call. + /// + /// \param level The compression level used for the server call. + void set_compression_level(grpc_compression_level level) { + compression_level_set_ = true; + compression_level_ = level; + } + + /// Return a bool indicating whether the compression level for this call + /// has been set (either implicitly or through a previous call to + /// \a set_compression_level. + bool compression_level_set() const { return compression_level_set_; } + + /// Return the compression algorithm the server call will request be used. + /// Note that the gRPC runtime may decide to ignore this request, for example, + /// due to resource constraints, or if the server is aware the client doesn't + /// support the requested algorithm. + grpc_compression_algorithm compression_algorithm() const { + return compression_algorithm_; + } + /// Set \a algorithm to be the compression algorithm used for the server call. + /// + /// \param algorithm The compression algorithm used for the server call. + void set_compression_algorithm(grpc_compression_algorithm algorithm); + + /// Set the serialized load reporting costs in \a cost_data for the call. + void SetLoadReportingCosts(const std::vector& cost_data); + + /// Return the authentication context for this server call. + /// + /// \see grpc::AuthContext. + std::shared_ptr auth_context() const { + if (auth_context_.get() == nullptr) { + auth_context_ = ::grpc::CreateAuthContext(call_); + } + return auth_context_; + } + + /// Return the peer uri in a string. + /// WARNING: this value is never authenticated or subject to any security + /// related code. It must not be used for any authentication related + /// functionality. Instead, use auth_context. + grpc::string peer() const; + + /// Get the census context associated with this server call. + const struct census_context* census_context() const; + + /// Async only. Has to be called before the rpc starts. + /// Returns the tag in completion queue when the rpc finishes. + /// IsCancelled() can then be called to check whether the rpc was cancelled. + /// TODO(vjpai): Fix this so that the tag is returned even if the call never + /// starts (https://github.com/grpc/grpc/issues/10136). + void AsyncNotifyWhenDone(void* tag) { + has_notify_when_done_tag_ = true; + async_notify_when_done_tag_ = tag; + } + + /// Should be used for framework-level extensions only. + /// Applications never need to call this method. + grpc_call* c_call() { return call_; } + + private: + friend class ::grpc::testing::InteropServerContextInspector; + friend class ::grpc::testing::ServerContextTestSpouse; + friend class ::grpc::ServerInterface; + friend class ::grpc_impl::Server; + template + friend class ::grpc::ServerAsyncReader; + template + friend class ::grpc::ServerAsyncWriter; + template + friend class ::grpc::ServerAsyncResponseWriter; + template + friend class ::grpc::ServerAsyncReaderWriter; + template + friend class ::grpc::ServerReader; + template + friend class ::grpc::ServerWriter; + template + friend class ::grpc::internal::ServerReaderWriterBody; + template + friend class ::grpc::internal::RpcMethodHandler; + template + friend class ::grpc::internal::ClientStreamingHandler; + template + friend class ::grpc::internal::ServerStreamingHandler; + template + friend class ::grpc::internal::TemplatedBidiStreamingHandler; + template + friend class ::grpc::internal::CallbackUnaryHandler; + template + friend class ::grpc::internal::CallbackClientStreamingHandler; + template + friend class ::grpc::internal::CallbackServerStreamingHandler; + template + friend class ::grpc::internal::CallbackBidiHandler; + template <::grpc::StatusCode code> + friend class ::grpc::internal::ErrorMethodHandler; + friend class ::grpc_impl::ClientContext; + friend class ::grpc::GenericServerContext; + + /// Prevent copying. + ServerContext(const ServerContext&); + ServerContext& operator=(const ServerContext&); + + class CompletionOp; + + void BeginCompletionOp(::grpc::internal::Call* call, + std::function callback, + ::grpc::internal::ServerReactor* reactor); + /// Return the tag queued by BeginCompletionOp() + ::grpc::internal::CompletionQueueTag* GetCompletionOpTag(); + + ServerContext(gpr_timespec deadline, grpc_metadata_array* arr); + + void set_call(grpc_call* call) { call_ = call; } + + void BindDeadlineAndMetadata(gpr_timespec deadline, grpc_metadata_array* arr); + + void Clear(); + + void Setup(gpr_timespec deadline); + + uint32_t initial_metadata_flags() const { return 0; } + + void SetCancelCallback(std::function callback); + void ClearCancelCallback(); + + ::grpc::experimental::ServerRpcInfo* set_server_rpc_info( + const char* method, ::grpc::internal::RpcMethod::RpcType type, + const std::vector>& creators) { + if (creators.size() != 0) { + rpc_info_ = new ::grpc::experimental::ServerRpcInfo(this, method, type); + rpc_info_->RegisterInterceptors(creators); + } + return rpc_info_; + } + + CompletionOp* completion_op_; + bool has_notify_when_done_tag_; + void* async_notify_when_done_tag_; + ::grpc::internal::CallbackWithSuccessTag completion_tag_; + + gpr_timespec deadline_; + grpc_call* call_; + ::grpc_impl::CompletionQueue* cq_; + bool sent_initial_metadata_; + mutable std::shared_ptr auth_context_; + mutable ::grpc::internal::MetadataMap client_metadata_; + std::multimap initial_metadata_; + std::multimap trailing_metadata_; + + bool compression_level_set_; + grpc_compression_level compression_level_; + grpc_compression_algorithm compression_algorithm_; + + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage> + pending_ops_; + bool has_pending_ops_; + + ::grpc::experimental::ServerRpcInfo* rpc_info_; +}; +} // namespace grpc_impl +#endif // GRPCPP_IMPL_CODEGEN_SERVER_CONTEXT_IMPL_H diff --git a/include/grpcpp/impl/codegen/server_interceptor.h b/include/grpcpp/impl/codegen/server_interceptor.h index 8875a28bf32..28fdc27ec68 100644 --- a/include/grpcpp/impl/codegen/server_interceptor.h +++ b/include/grpcpp/impl/codegen/server_interceptor.h @@ -26,9 +26,11 @@ #include #include -namespace grpc { - +namespace grpc_impl { class ServerContext; +} + +namespace grpc { namespace internal { class InterceptorBatchMethodsImpl; @@ -78,7 +80,7 @@ class ServerRpcInfo { /// Return a pointer to the underlying ServerContext structure associated /// with the RPC to support features that apply to it - grpc::ServerContext* server_context() { return ctx_; } + grpc_impl::ServerContext* server_context() { return ctx_; } private: static_assert(Type::UNARY == @@ -94,7 +96,7 @@ class ServerRpcInfo { static_cast(internal::RpcMethod::BIDI_STREAMING), "violated expectation about Type enum"); - ServerRpcInfo(grpc::ServerContext* ctx, const char* method, + ServerRpcInfo(grpc_impl::ServerContext* ctx, const char* method, internal::RpcMethod::RpcType type) : ctx_(ctx), method_(method), type_(static_cast(type)) { ref_.store(1); @@ -127,14 +129,14 @@ class ServerRpcInfo { } } - grpc::ServerContext* ctx_ = nullptr; + grpc_impl::ServerContext* ctx_ = nullptr; const char* method_ = nullptr; const Type type_; std::atomic_int ref_; std::vector> interceptors_; friend class internal::InterceptorBatchMethodsImpl; - friend class grpc::ServerContext; + friend class grpc_impl::ServerContext; }; } // namespace experimental diff --git a/include/grpcpp/impl/codegen/server_interface.h b/include/grpcpp/impl/codegen/server_interface.h index d8d49344965..9600e5f053d 100644 --- a/include/grpcpp/impl/codegen/server_interface.h +++ b/include/grpcpp/impl/codegen/server_interface.h @@ -34,12 +34,12 @@ class Channel; class CompletionQueue; class ServerCompletionQueue; class ServerCredentials; +class ServerContext; } // namespace grpc_impl namespace grpc { class AsyncGenericService; class GenericServerContext; -class ServerContext; class Service; extern CoreCodegenInterface* g_core_codegen_interface; @@ -176,7 +176,8 @@ class ServerInterface : public internal::CallHook { class BaseAsyncRequest : public internal::CompletionQueueTag { public: - BaseAsyncRequest(ServerInterface* server, ServerContext* context, + BaseAsyncRequest(ServerInterface* server, + ::grpc_impl::ServerContext* context, internal::ServerAsyncStreamingInterface* stream, ::grpc_impl::CompletionQueue* call_cq, ::grpc_impl::ServerCompletionQueue* notification_cq, @@ -190,7 +191,7 @@ class ServerInterface : public internal::CallHook { protected: ServerInterface* const server_; - ServerContext* const context_; + ::grpc_impl::ServerContext* const context_; internal::ServerAsyncStreamingInterface* const stream_; ::grpc_impl::CompletionQueue* const call_cq_; ::grpc_impl::ServerCompletionQueue* const notification_cq_; @@ -205,7 +206,8 @@ class ServerInterface : public internal::CallHook { /// RegisteredAsyncRequest is not part of the C++ API class RegisteredAsyncRequest : public BaseAsyncRequest { public: - RegisteredAsyncRequest(ServerInterface* server, ServerContext* context, + RegisteredAsyncRequest(ServerInterface* server, + ::grpc_impl::ServerContext* context, internal::ServerAsyncStreamingInterface* stream, ::grpc_impl::CompletionQueue* call_cq, ::grpc_impl::ServerCompletionQueue* notification_cq, @@ -234,7 +236,8 @@ class ServerInterface : public internal::CallHook { class NoPayloadAsyncRequest final : public RegisteredAsyncRequest { public: NoPayloadAsyncRequest(internal::RpcServiceMethod* registered_method, - ServerInterface* server, ServerContext* context, + ServerInterface* server, + ::grpc_impl::ServerContext* context, internal::ServerAsyncStreamingInterface* stream, ::grpc_impl::CompletionQueue* call_cq, ::grpc_impl::ServerCompletionQueue* notification_cq, @@ -252,7 +255,8 @@ class ServerInterface : public internal::CallHook { class PayloadAsyncRequest final : public RegisteredAsyncRequest { public: PayloadAsyncRequest(internal::RpcServiceMethod* registered_method, - ServerInterface* server, ServerContext* context, + ServerInterface* server, + ::grpc_impl::ServerContext* context, internal::ServerAsyncStreamingInterface* stream, ::grpc_impl::CompletionQueue* call_cq, ::grpc_impl::ServerCompletionQueue* notification_cq, @@ -309,7 +313,7 @@ class ServerInterface : public internal::CallHook { private: internal::RpcServiceMethod* const registered_method_; ServerInterface* const server_; - ServerContext* const context_; + ::grpc_impl::ServerContext* const context_; internal::ServerAsyncStreamingInterface* const stream_; ::grpc_impl::CompletionQueue* const call_cq_; @@ -335,7 +339,7 @@ class ServerInterface : public internal::CallHook { template void RequestAsyncCall(internal::RpcServiceMethod* method, - ServerContext* context, + ::grpc_impl::ServerContext* context, internal::ServerAsyncStreamingInterface* stream, ::grpc_impl::CompletionQueue* call_cq, ::grpc_impl::ServerCompletionQueue* notification_cq, @@ -346,7 +350,7 @@ class ServerInterface : public internal::CallHook { } void RequestAsyncCall(internal::RpcServiceMethod* method, - ServerContext* context, + ::grpc_impl::ServerContext* context, internal::ServerAsyncStreamingInterface* stream, ::grpc_impl::CompletionQueue* call_cq, ::grpc_impl::ServerCompletionQueue* notification_cq, diff --git a/include/grpcpp/impl/codegen/service_type.h b/include/grpcpp/impl/codegen/service_type.h index f1d1272dc20..4109ee1b504 100644 --- a/include/grpcpp/impl/codegen/service_type.h +++ b/include/grpcpp/impl/codegen/service_type.h @@ -30,11 +30,11 @@ namespace grpc_impl { class Server; class CompletionQueue; +class ServerContext; } // namespace grpc_impl namespace grpc { class ServerInterface; -class ServerContext; namespace internal { class Call; @@ -146,7 +146,8 @@ class Service { experimental_type experimental() { return experimental_type(this); } template - void RequestAsyncUnary(int index, ServerContext* context, Message* request, + void RequestAsyncUnary(int index, ::grpc_impl::ServerContext* context, + Message* request, internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, ServerCompletionQueue* notification_cq, void* tag) { @@ -158,7 +159,7 @@ class Service { notification_cq, tag, request); } void RequestAsyncClientStreaming( - int index, ServerContext* context, + int index, ::grpc_impl::ServerContext* context, internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, ServerCompletionQueue* notification_cq, void* tag) { size_t idx = static_cast(index); @@ -167,7 +168,7 @@ class Service { } template void RequestAsyncServerStreaming( - int index, ServerContext* context, Message* request, + int index, ::grpc_impl::ServerContext* context, Message* request, internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, ServerCompletionQueue* notification_cq, void* tag) { size_t idx = static_cast(index); @@ -175,7 +176,7 @@ class Service { notification_cq, tag, request); } void RequestAsyncBidiStreaming( - int index, ServerContext* context, + int index, ::grpc_impl::ServerContext* context, internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, ServerCompletionQueue* notification_cq, void* tag) { size_t idx = static_cast(index); diff --git a/include/grpcpp/opencensus.h b/include/grpcpp/opencensus.h index 14c6add1d9e..39bac6bc28c 100644 --- a/include/grpcpp/opencensus.h +++ b/include/grpcpp/opencensus.h @@ -30,7 +30,7 @@ static inline void RegisterOpenCensusViewsForExport() { ::grpc_impl::RegisterOpenCensusViewsForExport(); } static inline ::opencensus::trace::Span GetSpanFromServerContext( - ServerContext* context) { + ::grpc_impl::ServerContext* context) { return ::grpc_impl::GetSpanFromServerContext(context); } diff --git a/include/grpcpp/opencensus_impl.h b/include/grpcpp/opencensus_impl.h index 631d2b861fd..dbcb7c9caeb 100644 --- a/include/grpcpp/opencensus_impl.h +++ b/include/grpcpp/opencensus_impl.h @@ -21,11 +21,8 @@ #include "opencensus/trace/span.h" -namespace grpc { - -class ServerContext; -} namespace grpc_impl { +class ServerContext; // These symbols in this file will not be included in the binary unless // grpc_opencensus_plugin build target was added as a dependency. At the moment // it is only setup to be built with Bazel. @@ -43,8 +40,7 @@ void RegisterOpenCensusPlugin(); void RegisterOpenCensusViewsForExport(); // Returns the tracing Span for the current RPC. -::opencensus::trace::Span GetSpanFromServerContext( - grpc::ServerContext* context); +::opencensus::trace::Span GetSpanFromServerContext(ServerContext* context); } // namespace grpc_impl diff --git a/include/grpcpp/server_impl.h b/include/grpcpp/server_impl.h index 59a780276e0..90019e25032 100644 --- a/include/grpcpp/server_impl.h +++ b/include/grpcpp/server_impl.h @@ -44,7 +44,6 @@ struct grpc_server; namespace grpc { class AsyncGenericService; -class ServerContext; namespace internal { class ExternalConnectionAcceptorImpl; @@ -54,6 +53,7 @@ class ExternalConnectionAcceptorImpl; namespace grpc_impl { class HealthCheckServiceInterface; +class ServerContext; class ServerInitializer; /// Represents a gRPC server. @@ -82,9 +82,9 @@ class Server : public grpc::ServerInterface, private grpc::GrpcLibraryCodegen { /// Called before server is created. virtual void UpdateArguments(grpc::ChannelArguments* args) {} /// Called before application callback for each synchronous server request - virtual void PreSynchronousRequest(grpc::ServerContext* context) = 0; + virtual void PreSynchronousRequest(grpc_impl::ServerContext* context) = 0; /// Called after application callback for each synchronous server request - virtual void PostSynchronousRequest(grpc::ServerContext* context) = 0; + virtual void PostSynchronousRequest(grpc_impl::ServerContext* context) = 0; /// Called before server is started. virtual void PreServerStart(Server* server) {} /// Called after a server port is added. diff --git a/requirements.bazel.txt b/requirements.bazel.txt index e97843794e4..4d52beb9e11 100644 --- a/requirements.bazel.txt +++ b/requirements.bazel.txt @@ -1,6 +1,6 @@ # GRPC Python setup requirements coverage>=4.0 -cython==0.28.3 +cython>=0.29.8 enum34>=1.0.4 protobuf>=3.5.0.post1 six>=1.10 diff --git a/requirements.txt b/requirements.txt index 6c978246214..27dd7d9f63b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ # GRPC Python setup requirements coverage>=4.0 -cython==0.28.3 +cython>=0.29.8 enum34>=1.0.4 protobuf>=3.5.0.post1 six>=1.10 diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc index bcc849035c6..23e3bd50eff 100644 --- a/src/compiler/cpp_generator.cc +++ b/src/compiler/cpp_generator.cc @@ -157,13 +157,13 @@ grpc::string GetHeaderIncludes(grpc_generator::File* file, printer->Print(vars, "namespace grpc_impl {\n"); printer->Print(vars, "class CompletionQueue;\n"); printer->Print(vars, "class ServerCompletionQueue;\n"); + printer->Print(vars, "class ServerContext;\n"); printer->Print(vars, "} // namespace grpc_impl\n\n"); printer->Print(vars, "namespace grpc {\n"); printer->Print(vars, "namespace experimental {\n"); printer->Print(vars, "template \n"); printer->Print(vars, "class MessageAllocator;\n"); printer->Print(vars, "} // namespace experimental\n"); - printer->Print(vars, "class ServerContext;\n"); printer->Print(vars, "} // namespace grpc\n\n"); vars["message_header_ext"] = params.message_header_extension.empty() diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc index 6b6045c98f6..40f8cef522b 100644 --- a/src/core/ext/filters/client_channel/client_channel.cc +++ b/src/core/ext/filters/client_channel/client_channel.cc @@ -118,18 +118,6 @@ class ChannelData { static void GetChannelInfo(grpc_channel_element* elem, const grpc_channel_info* info); - void set_channelz_node(channelz::ClientChannelNode* node) { - channelz_node_ = node; - resolving_lb_policy_->set_channelz_node(node->Ref()); - } - void FillChildRefsForChannelz(channelz::ChildRefsList* child_subchannels, - channelz::ChildRefsList* child_channels) { - if (resolving_lb_policy_ != nullptr) { - resolving_lb_policy_->FillChildRefsForChannelz(child_subchannels, - child_channels); - } - } - bool deadline_checking_enabled() const { return deadline_checking_enabled_; } bool enable_retries() const { return enable_retries_; } size_t per_rpc_retry_buffer_size() const { @@ -159,6 +147,9 @@ class ChannelData { return service_config_; } + RefCountedPtr GetConnectedSubchannelInDataPlane( + SubchannelInterface* subchannel) const; + grpc_connectivity_state CheckConnectivityState(bool try_to_connect); void AddExternalConnectivityWatcher(grpc_polling_entity pollent, grpc_connectivity_state* state, @@ -173,9 +164,9 @@ class ChannelData { } private: + class SubchannelWrapper; class ConnectivityStateAndPickerSetter; class ServiceConfigSetter; - class GrpcSubchannel; class ClientChannelControlHelper; class ExternalConnectivityWatcher { @@ -249,8 +240,7 @@ class ChannelData { ClientChannelFactory* client_channel_factory_; UniquePtr server_name_; RefCountedPtr default_service_config_; - // Initialized shortly after construction. - channelz::ClientChannelNode* channelz_node_ = nullptr; + channelz::ChannelNode* channelz_node_; // // Fields used in the data plane. Guarded by data_plane_combiner. @@ -269,12 +259,20 @@ class ChannelData { grpc_combiner* combiner_; grpc_pollset_set* interested_parties_; RefCountedPtr subchannel_pool_; - OrphanablePtr resolving_lb_policy_; + OrphanablePtr resolving_lb_policy_; grpc_connectivity_state_tracker state_tracker_; ExternalConnectivityWatcher::WatcherList external_connectivity_watcher_list_; UniquePtr health_check_service_name_; RefCountedPtr saved_service_config_; bool received_first_resolver_result_ = false; + // The number of SubchannelWrapper instances referencing a given Subchannel. + Map subchannel_refcount_map_; + // Pending ConnectedSubchannel updates for each SubchannelWrapper. + // Updates are queued here in the control plane combiner and then applied + // in the data plane combiner when the picker is updated. + Map, RefCountedPtr, + RefCountedPtrLess> + pending_subchannel_updates_; // // Fields accessed from both data plane and control plane combiners. @@ -718,6 +716,247 @@ class CallData { grpc_metadata_batch send_trailing_metadata_; }; +// +// ChannelData::SubchannelWrapper +// + +// This class is a wrapper for Subchannel that hides details of the +// channel's implementation (such as the health check service name and +// connected subchannel) from the LB policy API. +// +// Note that no synchronization is needed here, because even if the +// underlying subchannel is shared between channels, this wrapper will only +// be used within one channel, so it will always be synchronized by the +// control plane combiner. +class ChannelData::SubchannelWrapper : public SubchannelInterface { + public: + SubchannelWrapper(ChannelData* chand, Subchannel* subchannel, + UniquePtr health_check_service_name) + : SubchannelInterface(&grpc_client_channel_routing_trace), + chand_(chand), + subchannel_(subchannel), + health_check_service_name_(std::move(health_check_service_name)) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) { + gpr_log(GPR_INFO, + "chand=%p: creating subchannel wrapper %p for subchannel %p", + chand, this, subchannel_); + } + GRPC_CHANNEL_STACK_REF(chand_->owning_stack_, "SubchannelWrapper"); + auto* subchannel_node = subchannel_->channelz_node(); + if (subchannel_node != nullptr) { + intptr_t subchannel_uuid = subchannel_node->uuid(); + auto it = chand_->subchannel_refcount_map_.find(subchannel_); + if (it == chand_->subchannel_refcount_map_.end()) { + chand_->channelz_node_->AddChildSubchannel(subchannel_uuid); + it = chand_->subchannel_refcount_map_.emplace(subchannel_, 0).first; + } + ++it->second; + } + } + + ~SubchannelWrapper() { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) { + gpr_log(GPR_INFO, + "chand=%p: destroying subchannel wrapper %p for subchannel %p", + chand_, this, subchannel_); + } + auto* subchannel_node = subchannel_->channelz_node(); + if (subchannel_node != nullptr) { + intptr_t subchannel_uuid = subchannel_node->uuid(); + auto it = chand_->subchannel_refcount_map_.find(subchannel_); + GPR_ASSERT(it != chand_->subchannel_refcount_map_.end()); + --it->second; + if (it->second == 0) { + chand_->channelz_node_->RemoveChildSubchannel(subchannel_uuid); + chand_->subchannel_refcount_map_.erase(it); + } + } + GRPC_SUBCHANNEL_UNREF(subchannel_, "unref from LB"); + GRPC_CHANNEL_STACK_UNREF(chand_->owning_stack_, "SubchannelWrapper"); + } + + grpc_connectivity_state CheckConnectivityState() override { + RefCountedPtr connected_subchannel; + grpc_connectivity_state connectivity_state = + subchannel_->CheckConnectivityState(health_check_service_name_.get(), + &connected_subchannel); + MaybeUpdateConnectedSubchannel(std::move(connected_subchannel)); + return connectivity_state; + } + + void WatchConnectivityState( + grpc_connectivity_state initial_state, + UniquePtr watcher) override { + auto& watcher_wrapper = watcher_map_[watcher.get()]; + GPR_ASSERT(watcher_wrapper == nullptr); + watcher_wrapper = New( + std::move(watcher), Ref(DEBUG_LOCATION, "WatcherWrapper")); + subchannel_->WatchConnectivityState( + initial_state, + UniquePtr(gpr_strdup(health_check_service_name_.get())), + OrphanablePtr( + watcher_wrapper)); + } + + void CancelConnectivityStateWatch( + ConnectivityStateWatcherInterface* watcher) override { + auto it = watcher_map_.find(watcher); + GPR_ASSERT(it != watcher_map_.end()); + subchannel_->CancelConnectivityStateWatch(health_check_service_name_.get(), + it->second); + watcher_map_.erase(it); + } + + void AttemptToConnect() override { subchannel_->AttemptToConnect(); } + + void ResetBackoff() override { subchannel_->ResetBackoff(); } + + const grpc_channel_args* channel_args() override { + return subchannel_->channel_args(); + } + + // Caller must be holding the control-plane combiner. + ConnectedSubchannel* connected_subchannel() const { + return connected_subchannel_.get(); + } + + // Caller must be holding the data-plane combiner. + ConnectedSubchannel* connected_subchannel_in_data_plane() const { + return connected_subchannel_in_data_plane_.get(); + } + void set_connected_subchannel_in_data_plane( + RefCountedPtr connected_subchannel) { + connected_subchannel_in_data_plane_ = std::move(connected_subchannel); + } + + private: + // Subchannel and SubchannelInterface have different interfaces for + // their respective ConnectivityStateWatcherInterface classes. + // The one in Subchannel updates the ConnectedSubchannel along with + // the state, whereas the one in SubchannelInterface does not expose + // the ConnectedSubchannel. + // + // This wrapper provides a bridge between the two. It implements + // Subchannel::ConnectivityStateWatcherInterface and wraps + // the instance of SubchannelInterface::ConnectivityStateWatcherInterface + // that was passed in by the LB policy. We pass an instance of this + // class to the underlying Subchannel, and when we get updates from + // the subchannel, we pass those on to the wrapped watcher to return + // the update to the LB policy. This allows us to set the connected + // subchannel before passing the result back to the LB policy. + class WatcherWrapper : public Subchannel::ConnectivityStateWatcherInterface { + public: + WatcherWrapper( + UniquePtr + watcher, + RefCountedPtr parent) + : watcher_(std::move(watcher)), parent_(std::move(parent)) {} + + ~WatcherWrapper() { parent_.reset(DEBUG_LOCATION, "WatcherWrapper"); } + + void Orphan() override { Unref(); } + + void OnConnectivityStateChange( + grpc_connectivity_state new_state, + RefCountedPtr connected_subchannel) override { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) { + gpr_log(GPR_INFO, + "chand=%p: connectivity change for subchannel wrapper %p " + "subchannel %p (connected_subchannel=%p state=%s); " + "hopping into combiner", + parent_->chand_, parent_.get(), parent_->subchannel_, + connected_subchannel.get(), + grpc_connectivity_state_name(new_state)); + } + // Will delete itself. + New(Ref(), new_state, std::move(connected_subchannel)); + } + + grpc_pollset_set* interested_parties() override { + return watcher_->interested_parties(); + } + + private: + class Updater { + public: + Updater(RefCountedPtr parent, + grpc_connectivity_state new_state, + RefCountedPtr connected_subchannel) + : parent_(std::move(parent)), + state_(new_state), + connected_subchannel_(std::move(connected_subchannel)) { + GRPC_CLOSURE_INIT( + &closure_, ApplyUpdateInControlPlaneCombiner, this, + grpc_combiner_scheduler(parent_->parent_->chand_->combiner_)); + GRPC_CLOSURE_SCHED(&closure_, GRPC_ERROR_NONE); + } + + private: + static void ApplyUpdateInControlPlaneCombiner(void* arg, + grpc_error* error) { + Updater* self = static_cast(arg); + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) { + gpr_log(GPR_INFO, + "chand=%p: processing connectivity change in combiner " + "for subchannel wrapper %p subchannel %p " + "(connected_subchannel=%p state=%s)", + self->parent_->parent_->chand_, self->parent_->parent_.get(), + self->parent_->parent_->subchannel_, + self->connected_subchannel_.get(), + grpc_connectivity_state_name(self->state_)); + } + self->parent_->parent_->MaybeUpdateConnectedSubchannel( + std::move(self->connected_subchannel_)); + self->parent_->watcher_->OnConnectivityStateChange(self->state_); + Delete(self); + } + + RefCountedPtr parent_; + grpc_connectivity_state state_; + RefCountedPtr connected_subchannel_; + grpc_closure closure_; + }; + + UniquePtr watcher_; + RefCountedPtr parent_; + }; + + void MaybeUpdateConnectedSubchannel( + RefCountedPtr connected_subchannel) { + // Update the connected subchannel only if the channel is not shutting + // down. This is because once the channel is shutting down, we + // ignore picker updates from the LB policy, which means that + // ConnectivityStateAndPickerSetter will never process the entries + // in chand_->pending_subchannel_updates_. So we don't want to add + // entries there that will never be processed, since that would + // leave dangling refs to the channel and prevent its destruction. + grpc_error* disconnect_error = chand_->disconnect_error(); + if (disconnect_error != GRPC_ERROR_NONE) return; + // Not shutting down, so do the update. + if (connected_subchannel_ != connected_subchannel) { + connected_subchannel_ = std::move(connected_subchannel); + // Record the new connected subchannel so that it can be updated + // in the data plane combiner the next time the picker is updated. + chand_->pending_subchannel_updates_[Ref( + DEBUG_LOCATION, "ConnectedSubchannelUpdate")] = connected_subchannel_; + } + } + + ChannelData* chand_; + Subchannel* subchannel_; + UniquePtr health_check_service_name_; + // Maps from the address of the watcher passed to us by the LB policy + // to the address of the WrapperWatcher that we passed to the underlying + // subchannel. This is needed so that when the LB policy calls + // CancelConnectivityStateWatch() with its watcher, we know the + // corresponding WrapperWatcher to cancel on the underlying subchannel. + Map watcher_map_; + // To be accessed only in the control plane combiner. + RefCountedPtr connected_subchannel_; + // To be accessed only in the data plane combiner. + RefCountedPtr connected_subchannel_in_data_plane_; +}; + // // ChannelData::ConnectivityStateAndPickerSetter // @@ -735,15 +974,19 @@ class ChannelData::ConnectivityStateAndPickerSetter { // Update connectivity state here, while holding control plane combiner. grpc_connectivity_state_set(&chand->state_tracker_, state, reason); if (chand->channelz_node_ != nullptr) { + chand->channelz_node_->SetConnectivityState(state); chand->channelz_node_->AddTraceEvent( channelz::ChannelTrace::Severity::Info, grpc_slice_from_static_string( GetChannelConnectivityStateChangeString(state))); } + // Grab any pending subchannel updates. + pending_subchannel_updates_ = + std::move(chand_->pending_subchannel_updates_); // Bounce into the data plane combiner to reset the picker. GRPC_CHANNEL_STACK_REF(chand->owning_stack_, "ConnectivityStateAndPickerSetter"); - GRPC_CLOSURE_INIT(&closure_, SetPicker, this, + GRPC_CLOSURE_INIT(&closure_, SetPickerInDataPlane, this, grpc_combiner_scheduler(chand->data_plane_combiner_)); GRPC_CLOSURE_SCHED(&closure_, GRPC_ERROR_NONE); } @@ -766,16 +1009,38 @@ class ChannelData::ConnectivityStateAndPickerSetter { GPR_UNREACHABLE_CODE(return "UNKNOWN"); } - static void SetPicker(void* arg, grpc_error* ignored) { + static void SetPickerInDataPlane(void* arg, grpc_error* ignored) { auto* self = static_cast(arg); - // Update picker. - self->chand_->picker_ = std::move(self->picker_); + // Handle subchannel updates. + for (auto& p : self->pending_subchannel_updates_) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) { + gpr_log(GPR_INFO, + "chand=%p: updating subchannel wrapper %p data plane " + "connected_subchannel to %p", + self->chand_, p.first.get(), p.second.get()); + } + p.first->set_connected_subchannel_in_data_plane(std::move(p.second)); + } + // Swap out the picker. We hang on to the old picker so that it can + // be deleted in the control-plane combiner, since that's where we need + // to unref the subchannel wrappers that are reffed by the picker. + self->picker_.swap(self->chand_->picker_); // Re-process queued picks. for (QueuedPick* pick = self->chand_->queued_picks_; pick != nullptr; pick = pick->next) { CallData::StartPickLocked(pick->elem, GRPC_ERROR_NONE); } - // Clean up. + // Pop back into the control plane combiner to delete ourself, so + // that we make sure to unref subchannel wrappers there. This + // includes both the ones reffed by the old picker (now stored in + // self->picker_) and the ones in self->pending_subchannel_updates_. + GRPC_CLOSURE_INIT(&self->closure_, CleanUpInControlPlane, self, + grpc_combiner_scheduler(self->chand_->combiner_)); + GRPC_CLOSURE_SCHED(&self->closure_, GRPC_ERROR_NONE); + } + + static void CleanUpInControlPlane(void* arg, grpc_error* ignored) { + auto* self = static_cast(arg); GRPC_CHANNEL_STACK_UNREF(self->chand_->owning_stack_, "ConnectivityStateAndPickerSetter"); Delete(self); @@ -783,6 +1048,9 @@ class ChannelData::ConnectivityStateAndPickerSetter { ChannelData* chand_; UniquePtr picker_; + Map, RefCountedPtr, + RefCountedPtrLess> + pending_subchannel_updates_; grpc_closure closure_; }; @@ -957,65 +1225,6 @@ void ChannelData::ExternalConnectivityWatcher::WatchConnectivityStateLocked( &self->chand_->state_tracker_, self->state_, &self->my_closure_); } -// -// ChannelData::GrpcSubchannel -// - -// This class is a wrapper for Subchannel that hides details of the -// channel's implementation (such as the health check service name) from -// the LB policy API. -// -// Note that no synchronization is needed here, because even if the -// underlying subchannel is shared between channels, this wrapper will only -// be used within one channel, so it will always be synchronized by the -// control plane combiner. -class ChannelData::GrpcSubchannel : public SubchannelInterface { - public: - GrpcSubchannel(Subchannel* subchannel, - UniquePtr health_check_service_name) - : subchannel_(subchannel), - health_check_service_name_(std::move(health_check_service_name)) {} - - ~GrpcSubchannel() { GRPC_SUBCHANNEL_UNREF(subchannel_, "unref from LB"); } - - grpc_connectivity_state CheckConnectivityState( - RefCountedPtr* connected_subchannel) - override { - RefCountedPtr tmp; - auto retval = subchannel_->CheckConnectivityState( - health_check_service_name_.get(), &tmp); - *connected_subchannel = std::move(tmp); - return retval; - } - - void WatchConnectivityState( - grpc_connectivity_state initial_state, - UniquePtr watcher) override { - subchannel_->WatchConnectivityState( - initial_state, - UniquePtr(gpr_strdup(health_check_service_name_.get())), - std::move(watcher)); - } - - void CancelConnectivityStateWatch( - ConnectivityStateWatcher* watcher) override { - subchannel_->CancelConnectivityStateWatch(health_check_service_name_.get(), - watcher); - } - - void AttemptToConnect() override { subchannel_->AttemptToConnect(); } - - channelz::SubchannelNode* channelz_node() override { - return subchannel_->channelz_node(); - } - - void ResetBackoff() override { subchannel_->ResetBackoff(); } - - private: - Subchannel* subchannel_; - UniquePtr health_check_service_name_; -}; - // // ChannelData::ClientChannelControlHelper // @@ -1041,7 +1250,10 @@ class ChannelData::ClientChannelControlHelper health_check_service_name.reset( gpr_strdup(chand_->health_check_service_name_.get())); } - static const char* args_to_remove[] = {GRPC_ARG_INHIBIT_HEALTH_CHECKING}; + static const char* args_to_remove[] = { + GRPC_ARG_INHIBIT_HEALTH_CHECKING, + GRPC_ARG_CHANNELZ_CHANNEL_NODE, + }; grpc_arg arg = SubchannelPoolInterface::CreateChannelArg( chand_->subchannel_pool_.get()); grpc_channel_args* new_args = grpc_channel_args_copy_and_add_and_remove( @@ -1050,8 +1262,8 @@ class ChannelData::ClientChannelControlHelper chand_->client_channel_factory_->CreateSubchannel(new_args); grpc_channel_args_destroy(new_args); if (subchannel == nullptr) return nullptr; - return MakeRefCounted(subchannel, - std::move(health_check_service_name)); + return MakeRefCounted( + chand_, subchannel, std::move(health_check_service_name)); } grpc_channel* CreateChannel(const char* target, @@ -1062,8 +1274,7 @@ class ChannelData::ClientChannelControlHelper void UpdateState( grpc_connectivity_state state, UniquePtr picker) override { - grpc_error* disconnect_error = - chand_->disconnect_error_.Load(MemoryOrder::ACQUIRE); + grpc_error* disconnect_error = chand_->disconnect_error(); if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) { const char* extra = disconnect_error == GRPC_ERROR_NONE ? "" @@ -1082,7 +1293,22 @@ class ChannelData::ClientChannelControlHelper // No-op -- we should never get this from ResolvingLoadBalancingPolicy. void RequestReresolution() override {} + void AddTraceEvent(TraceSeverity severity, const char* message) override { + if (chand_->channelz_node_ != nullptr) { + chand_->channelz_node_->AddTraceEvent( + ConvertSeverityEnum(severity), + grpc_slice_from_copied_string(message)); + } + } + private: + static channelz::ChannelTrace::Severity ConvertSeverityEnum( + TraceSeverity severity) { + if (severity == TRACE_INFO) return channelz::ChannelTrace::Info; + if (severity == TRACE_WARNING) return channelz::ChannelTrace::Warning; + return channelz::ChannelTrace::Error; + } + ChannelData* chand_; }; @@ -1125,6 +1351,15 @@ RefCountedPtr GetSubchannelPool( return GlobalSubchannelPool::instance(); } +channelz::ChannelNode* GetChannelzNode(const grpc_channel_args* args) { + const grpc_arg* arg = + grpc_channel_args_find(args, GRPC_ARG_CHANNELZ_CHANNEL_NODE); + if (arg != nullptr && arg->type == GRPC_ARG_POINTER) { + return static_cast(arg->value.pointer.p); + } + return nullptr; +} + ChannelData::ChannelData(grpc_channel_element_args* args, grpc_error** error) : deadline_checking_enabled_( grpc_deadline_checking_enabled(args->channel_args)), @@ -1134,11 +1369,16 @@ ChannelData::ChannelData(grpc_channel_element_args* args, grpc_error** error) owning_stack_(args->channel_stack), client_channel_factory_( ClientChannelFactory::GetFromChannelArgs(args->channel_args)), + channelz_node_(GetChannelzNode(args->channel_args)), data_plane_combiner_(grpc_combiner_create()), combiner_(grpc_combiner_create()), interested_parties_(grpc_pollset_set_create()), subchannel_pool_(GetSubchannelPool(args->channel_args)), disconnect_error_(GRPC_ERROR_NONE) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) { + gpr_log(GPR_INFO, "chand=%p: creating client_channel for channel stack %p", + this, owning_stack_); + } // Initialize data members. grpc_connectivity_state_init(&state_tracker_, GRPC_CHANNEL_IDLE, "client_channel"); @@ -1195,10 +1435,8 @@ ChannelData::ChannelData(grpc_channel_element_args* args, grpc_error** error) std::move(target_uri), ProcessResolverResultLocked, this, error)); grpc_channel_args_destroy(new_args); if (*error != GRPC_ERROR_NONE) { - // Orphan the resolving LB policy and flush the exec_ctx to ensure - // that it finishes shutting down. This ensures that if we are - // failing, we destroy the ClientChannelControlHelper (and thus - // unref the channel stack) before we return. + // Before we return, shut down the resolving LB policy, which destroys + // the ClientChannelControlHelper and therefore unrefs the channel stack. // TODO(roth): This is not a complete solution, because it only // catches the case where channel stack initialization fails in this // particular filter. If there is a failure in a different filter, we @@ -1206,7 +1444,6 @@ ChannelData::ChannelData(grpc_channel_element_args* args, grpc_error** error) // in practice, there are no other filters that can cause failures in // channel stack initialization, so this works for now. resolving_lb_policy_.reset(); - ExecCtx::Get()->Flush(); } else { grpc_pollset_set_add_pollset_set(resolving_lb_policy_->interested_parties(), interested_parties_); @@ -1218,6 +1455,9 @@ ChannelData::ChannelData(grpc_channel_element_args* args, grpc_error** error) } ChannelData::~ChannelData() { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) { + gpr_log(GPR_INFO, "chand=%p: destroying channel", this); + } if (resolving_lb_policy_ != nullptr) { grpc_pollset_set_del_pollset_set(resolving_lb_policy_->interested_parties(), interested_parties_); @@ -1403,9 +1643,13 @@ grpc_error* ChannelData::DoPingLocked(grpc_transport_op* op) { } LoadBalancingPolicy::PickResult result = picker_->Pick(LoadBalancingPolicy::PickArgs()); - if (result.connected_subchannel != nullptr) { - ConnectedSubchannel* connected_subchannel = - static_cast(result.connected_subchannel.get()); + ConnectedSubchannel* connected_subchannel = nullptr; + if (result.subchannel != nullptr) { + SubchannelWrapper* subchannel = + static_cast(result.subchannel.get()); + connected_subchannel = subchannel->connected_subchannel(); + } + if (connected_subchannel != nullptr) { connected_subchannel->Ping(op->send_ping.on_initiate, op->send_ping.on_ack); } else { if (result.error == GRPC_ERROR_NONE) { @@ -1448,6 +1692,10 @@ void ChannelData::StartTransportOpLocked(void* arg, grpc_error* ignored) { } // Disconnect. if (op->disconnect_with_error != GRPC_ERROR_NONE) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { + gpr_log(GPR_INFO, "chand=%p: channel shut down from API: %s", chand, + grpc_error_string(op->disconnect_with_error)); + } grpc_error* error = GRPC_ERROR_NONE; GPR_ASSERT(chand->disconnect_error_.CompareExchangeStrong( &error, op->disconnect_with_error, MemoryOrder::ACQ_REL, @@ -1522,6 +1770,17 @@ void ChannelData::RemoveQueuedPick(QueuedPick* to_remove, } } +RefCountedPtr +ChannelData::GetConnectedSubchannelInDataPlane( + SubchannelInterface* subchannel) const { + SubchannelWrapper* subchannel_wrapper = + static_cast(subchannel); + ConnectedSubchannel* connected_subchannel = + subchannel_wrapper->connected_subchannel_in_data_plane(); + if (connected_subchannel == nullptr) return nullptr; + return connected_subchannel->Ref(); +} + void ChannelData::TryToConnectLocked(void* arg, grpc_error* error_ignored) { auto* chand = static_cast(arg); if (chand->resolving_lb_policy_ != nullptr) { @@ -3449,10 +3708,9 @@ void CallData::StartPickLocked(void* arg, grpc_error* error) { auto result = chand->picker()->Pick(pick_args); if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) { gpr_log(GPR_INFO, - "chand=%p calld=%p: LB pick returned %s (connected_subchannel=%p, " - "error=%s)", + "chand=%p calld=%p: LB pick returned %s (subchannel=%p, error=%s)", chand, calld, PickResultTypeName(result.type), - result.connected_subchannel.get(), grpc_error_string(result.error)); + result.subchannel.get(), grpc_error_string(result.error)); } switch (result.type) { case LoadBalancingPolicy::PickResult::PICK_TRANSIENT_FAILURE: { @@ -3494,11 +3752,16 @@ void CallData::StartPickLocked(void* arg, grpc_error* error) { break; default: // PICK_COMPLETE // Handle drops. - if (GPR_UNLIKELY(result.connected_subchannel == nullptr)) { + if (GPR_UNLIKELY(result.subchannel == nullptr)) { result.error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( "Call dropped by load balancing policy"); + } else { + // Grab a ref to the connected subchannel while we're still + // holding the data plane combiner. + calld->connected_subchannel_ = + chand->GetConnectedSubchannelInDataPlane(result.subchannel.get()); + GPR_ASSERT(calld->connected_subchannel_ != nullptr); } - calld->connected_subchannel_ = std::move(result.connected_subchannel); calld->lb_recv_trailing_metadata_ready_ = result.recv_trailing_metadata_ready; calld->lb_recv_trailing_metadata_ready_user_data_ = @@ -3532,20 +3795,6 @@ const grpc_channel_filter grpc_client_channel_filter = { "client-channel", }; -void grpc_client_channel_set_channelz_node( - grpc_channel_element* elem, grpc_core::channelz::ClientChannelNode* node) { - auto* chand = static_cast(elem->channel_data); - chand->set_channelz_node(node); -} - -void grpc_client_channel_populate_child_refs( - grpc_channel_element* elem, - grpc_core::channelz::ChildRefsList* child_subchannels, - grpc_core::channelz::ChildRefsList* child_channels) { - auto* chand = static_cast(elem->channel_data); - chand->FillChildRefsForChannelz(child_subchannels, child_channels); -} - grpc_connectivity_state grpc_client_channel_check_connectivity_state( grpc_channel_element* elem, int try_to_connect) { auto* chand = static_cast(elem->channel_data); diff --git a/src/core/ext/filters/client_channel/client_channel.h b/src/core/ext/filters/client_channel/client_channel.h index 5bfff4df9cd..caaa079dd9b 100644 --- a/src/core/ext/filters/client_channel/client_channel.h +++ b/src/core/ext/filters/client_channel/client_channel.h @@ -40,14 +40,6 @@ extern grpc_core::TraceFlag grpc_client_channel_trace; extern const grpc_channel_filter grpc_client_channel_filter; -void grpc_client_channel_set_channelz_node( - grpc_channel_element* elem, grpc_core::channelz::ClientChannelNode* node); - -void grpc_client_channel_populate_child_refs( - grpc_channel_element* elem, - grpc_core::channelz::ChildRefsList* child_subchannels, - grpc_core::channelz::ChildRefsList* child_channels); - grpc_connectivity_state grpc_client_channel_check_connectivity_state( grpc_channel_element* elem, int try_to_connect); diff --git a/src/core/ext/filters/client_channel/client_channel_channelz.cc b/src/core/ext/filters/client_channel/client_channel_channelz.cc index de61819ef54..e068d11dc41 100644 --- a/src/core/ext/filters/client_channel/client_channel_channelz.cc +++ b/src/core/ext/filters/client_channel/client_channel_channelz.cc @@ -29,89 +29,6 @@ namespace grpc_core { namespace channelz { -namespace { - -void* client_channel_channelz_copy(void* p) { return p; } - -void client_channel_channelz_destroy(void* p) {} - -int client_channel_channelz_cmp(void* a, void* b) { return GPR_ICMP(a, b); } - -} // namespace - -static const grpc_arg_pointer_vtable client_channel_channelz_vtable = { - client_channel_channelz_copy, client_channel_channelz_destroy, - client_channel_channelz_cmp}; - -ClientChannelNode::ClientChannelNode(grpc_channel* channel, - size_t channel_tracer_max_nodes, - bool is_top_level_channel) - : ChannelNode(channel, channel_tracer_max_nodes, is_top_level_channel) { - client_channel_ = - grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel)); - GPR_ASSERT(client_channel_->filter == &grpc_client_channel_filter); - grpc_client_channel_set_channelz_node(client_channel_, this); -} - -void ClientChannelNode::PopulateConnectivityState(grpc_json* json) { - grpc_connectivity_state state; - if (ChannelIsDestroyed()) { - state = GRPC_CHANNEL_SHUTDOWN; - } else { - state = - grpc_client_channel_check_connectivity_state(client_channel_, false); - } - json = grpc_json_create_child(nullptr, json, "state", nullptr, - GRPC_JSON_OBJECT, false); - grpc_json_create_child(nullptr, json, "state", - grpc_connectivity_state_name(state), GRPC_JSON_STRING, - false); -} - -void ClientChannelNode::PopulateChildRefs(grpc_json* json) { - ChildRefsList child_subchannels; - ChildRefsList child_channels; - grpc_json* json_iterator = nullptr; - grpc_client_channel_populate_child_refs(client_channel_, &child_subchannels, - &child_channels); - if (!child_subchannels.empty()) { - grpc_json* array_parent = grpc_json_create_child( - nullptr, json, "subchannelRef", nullptr, GRPC_JSON_ARRAY, false); - for (size_t i = 0; i < child_subchannels.size(); ++i) { - json_iterator = - grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr, - GRPC_JSON_OBJECT, false); - grpc_json_add_number_string_child(json_iterator, nullptr, "subchannelId", - child_subchannels[i]); - } - } - if (!child_channels.empty()) { - grpc_json* array_parent = grpc_json_create_child( - nullptr, json, "channelRef", nullptr, GRPC_JSON_ARRAY, false); - json_iterator = nullptr; - for (size_t i = 0; i < child_channels.size(); ++i) { - json_iterator = - grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr, - GRPC_JSON_OBJECT, false); - grpc_json_add_number_string_child(json_iterator, nullptr, "channelId", - child_channels[i]); - } - } -} - -grpc_arg ClientChannelNode::CreateChannelArg() { - return grpc_channel_arg_pointer_create( - const_cast(GRPC_ARG_CHANNELZ_CHANNEL_NODE_CREATION_FUNC), - reinterpret_cast(MakeClientChannelNode), - &client_channel_channelz_vtable); -} - -RefCountedPtr ClientChannelNode::MakeClientChannelNode( - grpc_channel* channel, size_t channel_tracer_max_nodes, - bool is_top_level_channel) { - return MakeRefCounted(channel, channel_tracer_max_nodes, - is_top_level_channel); -} SubchannelNode::SubchannelNode(Subchannel* subchannel, size_t channel_tracer_max_nodes) diff --git a/src/core/ext/filters/client_channel/client_channel_channelz.h b/src/core/ext/filters/client_channel/client_channel_channelz.h index 9272116882e..9f11e928998 100644 --- a/src/core/ext/filters/client_channel/client_channel_channelz.h +++ b/src/core/ext/filters/client_channel/client_channel_channelz.h @@ -32,32 +32,6 @@ class Subchannel; namespace channelz { -// Subtype of ChannelNode that overrides and provides client_channel specific -// functionality like querying for connectivity_state and subchannel data. -class ClientChannelNode : public ChannelNode { - public: - static RefCountedPtr MakeClientChannelNode( - grpc_channel* channel, size_t channel_tracer_max_nodes, - bool is_top_level_channel); - - ClientChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes, - bool is_top_level_channel); - virtual ~ClientChannelNode() {} - - // Overriding template methods from ChannelNode to render information that - // only ClientChannelNode knows about. - void PopulateConnectivityState(grpc_json* json) override; - void PopulateChildRefs(grpc_json* json) override; - - // Helper to create a channel arg to ensure this type of ChannelNode is - // created. - static grpc_arg CreateChannelArg(); - - private: - grpc_channel_element* client_channel_; -}; - -// Handles channelz bookkeeping for sockets class SubchannelNode : public BaseNode { public: SubchannelNode(Subchannel* subchannel, size_t channel_tracer_max_nodes); @@ -85,12 +59,12 @@ class SubchannelNode : public BaseNode { void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); } private: + void PopulateConnectivityState(grpc_json* json); + Subchannel* subchannel_; UniquePtr target_; CallCountingHelper call_counter_; ChannelTrace trace_; - - void PopulateConnectivityState(grpc_json* json); }; } // namespace channelz diff --git a/src/core/ext/filters/client_channel/client_channel_plugin.cc b/src/core/ext/filters/client_channel/client_channel_plugin.cc index 3a7492d82d9..c5662e22a20 100644 --- a/src/core/ext/filters/client_channel/client_channel_plugin.cc +++ b/src/core/ext/filters/client_channel/client_channel_plugin.cc @@ -38,14 +38,6 @@ #include "src/core/lib/surface/channel_init.h" static bool append_filter(grpc_channel_stack_builder* builder, void* arg) { - const grpc_channel_args* args = - grpc_channel_stack_builder_get_channel_arguments(builder); - grpc_arg args_to_add[] = { - grpc_core::channelz::ClientChannelNode::CreateChannelArg()}; - grpc_channel_args* new_args = grpc_channel_args_copy_and_add( - args, args_to_add, GPR_ARRAY_SIZE(args_to_add)); - grpc_channel_stack_builder_set_channel_arguments(builder, new_args); - grpc_channel_args_destroy(new_args); return grpc_channel_stack_builder_append_filter( builder, static_cast(arg), nullptr, nullptr); } diff --git a/src/core/ext/filters/client_channel/lb_policy.cc b/src/core/ext/filters/client_channel/lb_policy.cc index 3e4d3703c82..3207f888044 100644 --- a/src/core/ext/filters/client_channel/lb_policy.cc +++ b/src/core/ext/filters/client_channel/lb_policy.cc @@ -43,23 +43,8 @@ LoadBalancingPolicy::~LoadBalancingPolicy() { } void LoadBalancingPolicy::Orphan() { - // Invoke ShutdownAndUnrefLocked() inside of the combiner. - // TODO(roth): Is this actually needed? We should already be in the - // combiner here. Note that if we directly call ShutdownLocked(), - // then we can probably remove the hack whereby the helper is - // destroyed at shutdown instead of at destruction. - GRPC_CLOSURE_SCHED( - GRPC_CLOSURE_CREATE(&LoadBalancingPolicy::ShutdownAndUnrefLocked, this, - grpc_combiner_scheduler(combiner_)), - GRPC_ERROR_NONE); -} - -void LoadBalancingPolicy::ShutdownAndUnrefLocked(void* arg, - grpc_error* ignored) { - LoadBalancingPolicy* policy = static_cast(arg); - policy->ShutdownLocked(); - policy->channel_control_helper_.reset(); - policy->Unref(); + ShutdownLocked(); + Unref(); } // diff --git a/src/core/ext/filters/client_channel/lb_policy.h b/src/core/ext/filters/client_channel/lb_policy.h index 2cadcc31998..ecc235bb71b 100644 --- a/src/core/ext/filters/client_channel/lb_policy.h +++ b/src/core/ext/filters/client_channel/lb_policy.h @@ -21,7 +21,6 @@ #include -#include "src/core/ext/filters/client_channel/client_channel_channelz.h" #include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/ext/filters/client_channel/service_config.h" #include "src/core/ext/filters/client_channel/subchannel_interface.h" @@ -31,6 +30,7 @@ #include "src/core/lib/iomgr/combiner.h" #include "src/core/lib/iomgr/polling_entity.h" #include "src/core/lib/transport/connectivity_state.h" +#include "src/core/lib/transport/metadata_batch.h" namespace grpc_core { @@ -128,7 +128,7 @@ class LoadBalancingPolicy : public InternallyRefCounted { /// Used only if type is PICK_COMPLETE. Will be set to the selected /// subchannel, or nullptr if the LB policy decides to drop the call. - RefCountedPtr connected_subchannel; + RefCountedPtr subchannel; /// Used only if type is PICK_TRANSIENT_FAILURE. /// Error to be set when returning a transient failure. @@ -201,6 +201,12 @@ class LoadBalancingPolicy : public InternallyRefCounted { /// Requests that the resolver re-resolve. virtual void RequestReresolution() GRPC_ABSTRACT; + /// Adds a trace message associated with the channel. + /// Does NOT take ownership of \a message. + enum TraceSeverity { TRACE_INFO, TRACE_WARNING, TRACE_ERROR }; + virtual void AddTraceEvent(TraceSeverity severity, + const char* message) GRPC_ABSTRACT; + GRPC_ABSTRACT_BASE_CLASS }; @@ -274,22 +280,9 @@ class LoadBalancingPolicy : public InternallyRefCounted { /// Resets connection backoff. virtual void ResetBackoffLocked() GRPC_ABSTRACT; - /// Populates child_subchannels and child_channels with the uuids of this - /// LB policy's referenced children. - /// - /// This is not invoked from the client_channel's combiner. The - /// implementation is responsible for providing its own synchronization. - virtual void FillChildRefsForChannelz( - channelz::ChildRefsList* child_subchannels, - channelz::ChildRefsList* child_channels) GRPC_ABSTRACT; - - void set_channelz_node( - RefCountedPtr channelz_node) { - channelz_node_ = std::move(channelz_node); - } - grpc_pollset_set* interested_parties() const { return interested_parties_; } + // Note: This must be invoked while holding the combiner. void Orphan() override; // A picker that returns PICK_QUEUE for all picks. @@ -300,6 +293,8 @@ class LoadBalancingPolicy : public InternallyRefCounted { explicit QueuePicker(RefCountedPtr parent) : parent_(std::move(parent)) {} + ~QueuePicker() { parent_.reset(DEBUG_LOCATION, "QueuePicker"); } + PickResult Pick(PickArgs args) override; private: @@ -328,29 +323,20 @@ class LoadBalancingPolicy : public InternallyRefCounted { // Note: LB policies MUST NOT call any method on the helper from their // constructor. - // Note: This will return null after ShutdownLocked() has been called. ChannelControlHelper* channel_control_helper() const { return channel_control_helper_.get(); } - channelz::ClientChannelNode* channelz_node() const { - return channelz_node_.get(); - } - /// Shuts down the policy. virtual void ShutdownLocked() GRPC_ABSTRACT; private: - static void ShutdownAndUnrefLocked(void* arg, grpc_error* ignored); - /// Combiner under which LB policy actions take place. grpc_combiner* combiner_; /// Owned pointer to interested parties in load balancing decisions. grpc_pollset_set* interested_parties_; /// Channel control helper. UniquePtr channel_control_helper_; - /// Channelz node. - RefCountedPtr channelz_node_; }; } // namespace grpc_core diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc index a3a2a44eb0e..dad10f0ce86 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc @@ -141,9 +141,6 @@ class GrpcLb : public LoadBalancingPolicy { void UpdateLocked(UpdateArgs args) override; void ResetBackoffLocked() override; - void FillChildRefsForChannelz( - channelz::ChildRefsList* child_subchannels, - channelz::ChildRefsList* child_channels) override; private: /// Contains a call to the LB server and all the data related to the call. @@ -300,6 +297,7 @@ class GrpcLb : public LoadBalancingPolicy { void UpdateState(grpc_connectivity_state state, UniquePtr picker) override; void RequestReresolution() override; + void AddTraceEvent(TraceSeverity severity, const char* message) override; void set_child(LoadBalancingPolicy* child) { child_ = child; } @@ -349,8 +347,6 @@ class GrpcLb : public LoadBalancingPolicy { // The channel for communicating with the LB server. grpc_channel* lb_channel_ = nullptr; - // Uuid of the lb channel. Used for channelz. - gpr_atm lb_channel_uuid_ = 0; // Response generator to inject address updates into lb_channel_. RefCountedPtr response_generator_; @@ -386,9 +382,6 @@ class GrpcLb : public LoadBalancingPolicy { grpc_connectivity_state lb_channel_connectivity_ = GRPC_CHANNEL_IDLE; grpc_closure lb_channel_on_connectivity_changed_; - // Lock held when modifying the value of child_policy_ or - // pending_child_policy_. - gpr_mu child_policy_mu_; // The child policy to use for the backends. OrphanablePtr child_policy_; // When switching child policies, the new policy will be stored here @@ -582,13 +575,12 @@ GrpcLb::PickResult GrpcLb::Picker::Pick(PickArgs args) { result = child_picker_->Pick(args); // If pick succeeded, add LB token to initial metadata. if (result.type == PickResult::PICK_COMPLETE && - result.connected_subchannel != nullptr) { + result.subchannel != nullptr) { const grpc_arg* arg = grpc_channel_args_find( - result.connected_subchannel->args(), GRPC_ARG_GRPCLB_ADDRESS_LB_TOKEN); + result.subchannel->channel_args(), GRPC_ARG_GRPCLB_ADDRESS_LB_TOKEN); if (arg == nullptr) { - gpr_log(GPR_ERROR, - "[grpclb %p picker %p] No LB token for connected subchannel %p", - parent_, this, result.connected_subchannel.get()); + gpr_log(GPR_ERROR, "[grpclb %p picker %p] No LB token for subchannel %p", + parent_, this, result.subchannel.get()); abort(); } grpc_mdelem lb_token = {reinterpret_cast(arg->value.pointer.p)}; @@ -655,7 +647,6 @@ void GrpcLb::Helper::UpdateState(grpc_connectivity_state state, grpc_pollset_set_del_pollset_set( parent_->child_policy_->interested_parties(), parent_->interested_parties()); - MutexLock lock(&parent_->child_policy_mu_); parent_->child_policy_ = std::move(parent_->pending_child_policy_); } else if (!CalledByCurrentChild()) { // This request is from an outdated child, so ignore it. @@ -735,6 +726,15 @@ void GrpcLb::Helper::RequestReresolution() { } } +void GrpcLb::Helper::AddTraceEvent(TraceSeverity severity, + const char* message) { + if (parent_->shutting_down_ || + (!CalledByPendingChild() && !CalledByCurrentChild())) { + return; + } + parent_->channel_control_helper()->AddTraceEvent(severity, message); +} + // // GrpcLb::BalancerCallState // @@ -1244,25 +1244,34 @@ grpc_channel_args* BuildBalancerChannelArgs( // treated as a stand-alone channel and not inherit this argument from the // args of the parent channel. GRPC_SSL_TARGET_NAME_OVERRIDE_ARG, + // Don't want to pass down channelz node from parent; the balancer + // channel will get its own. + GRPC_ARG_CHANNELZ_CHANNEL_NODE, }; // Channel args to add. - const grpc_arg args_to_add[] = { - // The fake resolver response generator, which we use to inject - // address updates into the LB channel. + InlinedVector args_to_add; + // The fake resolver response generator, which we use to inject + // address updates into the LB channel. + args_to_add.emplace_back( grpc_core::FakeResolverResponseGenerator::MakeChannelArg( - response_generator), - // A channel arg indicating the target is a grpclb load balancer. - grpc_channel_arg_integer_create( - const_cast(GRPC_ARG_ADDRESS_IS_GRPCLB_LOAD_BALANCER), 1), - // A channel arg indicating this is an internal channels, aka it is - // owned by components in Core, not by the user application. - grpc_channel_arg_integer_create( - const_cast(GRPC_ARG_CHANNELZ_CHANNEL_IS_INTERNAL_CHANNEL), 1), - }; + response_generator)); + // A channel arg indicating the target is a grpclb load balancer. + args_to_add.emplace_back(grpc_channel_arg_integer_create( + const_cast(GRPC_ARG_ADDRESS_IS_GRPCLB_LOAD_BALANCER), 1)); + // The parent channel's channelz uuid. + channelz::ChannelNode* channelz_node = nullptr; + const grpc_arg* arg = + grpc_channel_args_find(args, GRPC_ARG_CHANNELZ_CHANNEL_NODE); + if (arg != nullptr && arg->type == GRPC_ARG_POINTER && + arg->value.pointer.p != nullptr) { + channelz_node = static_cast(arg->value.pointer.p); + args_to_add.emplace_back( + channelz::MakeParentUuidArg(channelz_node->uuid())); + } // Construct channel args. grpc_channel_args* new_args = grpc_channel_args_copy_and_add_and_remove( - args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), args_to_add, - GPR_ARRAY_SIZE(args_to_add)); + args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), args_to_add.data(), + args_to_add.size()); // Make any necessary modifications for security. return grpc_lb_policy_grpclb_modify_lb_channel_args(addresses, new_args); } @@ -1288,7 +1297,6 @@ GrpcLb::GrpcLb(Args args) GRPC_CLOSURE_INIT(&lb_channel_on_connectivity_changed_, &GrpcLb::OnBalancerChannelConnectivityChangedLocked, this, grpc_combiner_scheduler(args.combiner)); - gpr_mu_init(&child_policy_mu_); // Record server name. const grpc_arg* arg = grpc_channel_args_find(args.args, GRPC_ARG_SERVER_URI); const char* server_uri = grpc_channel_arg_get_string(arg); @@ -1314,7 +1322,6 @@ GrpcLb::GrpcLb(Args args) GrpcLb::~GrpcLb() { gpr_free((void*)server_name_); grpc_channel_args_destroy(args_); - gpr_mu_destroy(&child_policy_mu_); } void GrpcLb::ShutdownLocked() { @@ -1335,11 +1342,8 @@ void GrpcLb::ShutdownLocked() { grpc_pollset_set_del_pollset_set( pending_child_policy_->interested_parties(), interested_parties()); } - { - MutexLock lock(&child_policy_mu_); - child_policy_.reset(); - pending_child_policy_.reset(); - } + child_policy_.reset(); + pending_child_policy_.reset(); // We destroy the LB channel here instead of in our destructor because // destroying the channel triggers a last callback to // OnBalancerChannelConnectivityChangedLocked(), and we need to be @@ -1347,7 +1351,6 @@ void GrpcLb::ShutdownLocked() { if (lb_channel_ != nullptr) { grpc_channel_destroy(lb_channel_); lb_channel_ = nullptr; - gpr_atm_no_barrier_store(&lb_channel_uuid_, 0); } } @@ -1367,29 +1370,6 @@ void GrpcLb::ResetBackoffLocked() { } } -void GrpcLb::FillChildRefsForChannelz( - channelz::ChildRefsList* child_subchannels, - channelz::ChildRefsList* child_channels) { - { - // Delegate to the child policy to fill the children subchannels. - // This must be done holding child_policy_mu_, since this method - // does not run in the combiner. - MutexLock lock(&child_policy_mu_); - if (child_policy_ != nullptr) { - child_policy_->FillChildRefsForChannelz(child_subchannels, - child_channels); - } - if (pending_child_policy_ != nullptr) { - pending_child_policy_->FillChildRefsForChannelz(child_subchannels, - child_channels); - } - } - gpr_atm uuid = gpr_atm_no_barrier_load(&lb_channel_uuid_); - if (uuid != 0) { - child_channels->push_back(uuid); - } -} - void GrpcLb::UpdateLocked(UpdateArgs args) { const bool is_initial_update = lb_channel_ == nullptr; auto* grpclb_config = @@ -1472,11 +1452,6 @@ void GrpcLb::ProcessAddressesAndChannelArgsLocked( lb_channel_ = channel_control_helper()->CreateChannel(uri_str, *lb_channel_args); GPR_ASSERT(lb_channel_ != nullptr); - grpc_core::channelz::ChannelNode* channel_node = - grpc_channel_get_channelz_node(lb_channel_); - if (channel_node != nullptr) { - gpr_atm_no_barrier_store(&lb_channel_uuid_, channel_node->uuid()); - } gpr_free(uri_str); } // Propagate updates to the LB channel (pick_first) through the fake @@ -1764,15 +1739,10 @@ void GrpcLb::CreateOrUpdateChildPolicyLocked() { gpr_log(GPR_INFO, "[grpclb %p] Creating new %schild policy %s", this, child_policy_ == nullptr ? "" : "pending ", child_policy_name); } - auto new_policy = - CreateChildPolicyLocked(child_policy_name, update_args.args); // Swap the policy into place. auto& lb_policy = child_policy_ == nullptr ? child_policy_ : pending_child_policy_; - { - MutexLock lock(&child_policy_mu_); - lb_policy = std::move(new_policy); - } + lb_policy = CreateChildPolicyLocked(child_policy_name, update_args.args); policy_to_update = lb_policy.get(); } else { // Cases 2a and 3a: update an existing policy. diff --git a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc index 4680117fede..8bf3d825b23 100644 --- a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc +++ b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc @@ -28,7 +28,6 @@ #include "src/core/ext/filters/client_channel/subchannel.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gprpp/sync.h" -#include "src/core/lib/iomgr/combiner.h" #include "src/core/lib/iomgr/sockaddr_utils.h" #include "src/core/lib/transport/connectivity_state.h" @@ -53,8 +52,6 @@ class PickFirst : public LoadBalancingPolicy { void UpdateLocked(UpdateArgs args) override; void ExitIdleLocked() override; void ResetBackoffLocked() override; - void FillChildRefsForChannelz(channelz::ChildRefsList* child_subchannels, - channelz::ChildRefsList* ignored) override; private: ~PickFirst(); @@ -87,9 +84,8 @@ class PickFirst : public LoadBalancingPolicy { public: PickFirstSubchannelList(PickFirst* policy, TraceFlag* tracer, const ServerAddressList& addresses, - grpc_combiner* combiner, const grpc_channel_args& args) - : SubchannelList(policy, tracer, addresses, combiner, + : SubchannelList(policy, tracer, addresses, policy->channel_control_helper(), args) { // Need to maintain a ref to the LB policy as long as we maintain // any references to subchannels, since the subchannels' @@ -113,37 +109,22 @@ class PickFirst : public LoadBalancingPolicy { class Picker : public SubchannelPicker { public: - explicit Picker( - RefCountedPtr connected_subchannel) - : connected_subchannel_(std::move(connected_subchannel)) {} + explicit Picker(RefCountedPtr subchannel) + : subchannel_(std::move(subchannel)) {} PickResult Pick(PickArgs args) override { PickResult result; result.type = PickResult::PICK_COMPLETE; - result.connected_subchannel = connected_subchannel_; + result.subchannel = subchannel_; return result; } private: - RefCountedPtr connected_subchannel_; - }; - - // Helper class to ensure that any function that modifies the child refs - // data structures will update the channelz snapshot data structures before - // returning. - class AutoChildRefsUpdater { - public: - explicit AutoChildRefsUpdater(PickFirst* pf) : pf_(pf) {} - ~AutoChildRefsUpdater() { pf_->UpdateChildRefsLocked(); } - - private: - PickFirst* pf_; + RefCountedPtr subchannel_; }; void ShutdownLocked() override; - void UpdateChildRefsLocked(); - // All our subchannels. OrphanablePtr subchannel_list_; // Latest pending subchannel list. @@ -154,12 +135,6 @@ class PickFirst : public LoadBalancingPolicy { bool idle_ = false; // Are we shut down? bool shutdown_ = false; - - /// Lock and data used to capture snapshots of this channels child - /// channels and subchannels. This data is consumed by channelz. - Mutex child_refs_mu_; - channelz::ChildRefsList child_subchannels_; - channelz::ChildRefsList child_channels_; }; PickFirst::PickFirst(Args args) : LoadBalancingPolicy(std::move(args)) { @@ -177,7 +152,6 @@ PickFirst::~PickFirst() { } void PickFirst::ShutdownLocked() { - AutoChildRefsUpdater guard(this); if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace)) { gpr_log(GPR_INFO, "Pick First %p Shutting down", this); } @@ -189,6 +163,9 @@ void PickFirst::ShutdownLocked() { void PickFirst::ExitIdleLocked() { if (shutdown_) return; if (idle_) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace)) { + gpr_log(GPR_INFO, "Pick First %p exiting idle", this); + } idle_ = false; if (subchannel_list_ == nullptr || subchannel_list_->num_subchannels() == 0) { @@ -212,42 +189,7 @@ void PickFirst::ResetBackoffLocked() { } } -void PickFirst::FillChildRefsForChannelz( - channelz::ChildRefsList* child_subchannels_to_fill, - channelz::ChildRefsList* ignored) { - MutexLock lock(&child_refs_mu_); - for (size_t i = 0; i < child_subchannels_.size(); ++i) { - // TODO(ncteisen): implement a de dup loop that is not O(n^2). Might - // have to implement lightweight set. For now, we don't care about - // performance when channelz requests are made. - bool found = false; - for (size_t j = 0; j < child_subchannels_to_fill->size(); ++j) { - if ((*child_subchannels_to_fill)[j] == child_subchannels_[i]) { - found = true; - break; - } - } - if (!found) { - child_subchannels_to_fill->push_back(child_subchannels_[i]); - } - } -} - -void PickFirst::UpdateChildRefsLocked() { - channelz::ChildRefsList cs; - if (subchannel_list_ != nullptr) { - subchannel_list_->PopulateChildRefsList(&cs); - } - if (latest_pending_subchannel_list_ != nullptr) { - latest_pending_subchannel_list_->PopulateChildRefsList(&cs); - } - // atomically update the data that channelz will actually be looking at. - MutexLock lock(&child_refs_mu_); - child_subchannels_ = std::move(cs); -} - void PickFirst::UpdateLocked(UpdateArgs args) { - AutoChildRefsUpdater guard(this); if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace)) { gpr_log(GPR_INFO, "Pick First %p received update with %" PRIuPTR " addresses", this, @@ -258,7 +200,7 @@ void PickFirst::UpdateLocked(UpdateArgs args) { grpc_channel_args* new_args = grpc_channel_args_copy_and_add(args.args, &new_arg, 1); auto subchannel_list = MakeOrphanable( - this, &grpc_lb_pick_first_trace, args.addresses, combiner(), *new_args); + this, &grpc_lb_pick_first_trace, args.addresses, *new_args); grpc_channel_args_destroy(new_args); if (subchannel_list->num_subchannels() == 0) { // Empty update or no valid subchannels. Unsubscribe from all current @@ -348,7 +290,6 @@ void PickFirst::UpdateLocked(UpdateArgs args) { void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked( grpc_connectivity_state connectivity_state) { PickFirst* p = static_cast(subchannel_list()->policy()); - AutoChildRefsUpdater guard(p); // The notification must be for a subchannel in either the current or // latest pending subchannel lists. GPR_ASSERT(subchannel_list() == p->subchannel_list_.get() || @@ -388,7 +329,8 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked( } else { p->channel_control_helper()->UpdateState( GRPC_CHANNEL_CONNECTING, - UniquePtr(New(p->Ref()))); + UniquePtr( + New(p->Ref(DEBUG_LOCATION, "QueuePicker")))); } } else { if (connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) { @@ -401,20 +343,20 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked( p->selected_ = nullptr; CancelConnectivityWatchLocked("selected subchannel failed; going IDLE"); p->channel_control_helper()->UpdateState( - GRPC_CHANNEL_IDLE, - UniquePtr(New(p->Ref()))); + GRPC_CHANNEL_IDLE, UniquePtr(New( + p->Ref(DEBUG_LOCATION, "QueuePicker")))); } else { // This is unlikely but can happen when a subchannel has been asked // to reconnect by a different channel and this channel has dropped // some connectivity state notifications. if (connectivity_state == GRPC_CHANNEL_READY) { p->channel_control_helper()->UpdateState( - GRPC_CHANNEL_READY, UniquePtr(New( - connected_subchannel()->Ref()))); + GRPC_CHANNEL_READY, + UniquePtr(New(subchannel()->Ref()))); } else { // CONNECTING p->channel_control_helper()->UpdateState( - connectivity_state, - UniquePtr(New(p->Ref()))); + connectivity_state, UniquePtr(New( + p->Ref(DEBUG_LOCATION, "QueuePicker")))); } } } @@ -470,7 +412,8 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked( if (subchannel_list() == p->subchannel_list_.get()) { p->channel_control_helper()->UpdateState( GRPC_CHANNEL_CONNECTING, - UniquePtr(New(p->Ref()))); + UniquePtr( + New(p->Ref(DEBUG_LOCATION, "QueuePicker")))); } break; } @@ -504,13 +447,13 @@ void PickFirst::PickFirstSubchannelData::ProcessUnselectedReadyLocked() { p->subchannel_list_ = std::move(p->latest_pending_subchannel_list_); } // Cases 1 and 2. - p->selected_ = this; - p->channel_control_helper()->UpdateState( - GRPC_CHANNEL_READY, - UniquePtr(New(connected_subchannel()->Ref()))); if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace)) { gpr_log(GPR_INFO, "Pick First %p selected subchannel %p", p, subchannel()); } + p->selected_ = this; + p->channel_control_helper()->UpdateState( + GRPC_CHANNEL_READY, + UniquePtr(New(subchannel()->Ref()))); } void PickFirst::PickFirstSubchannelData:: diff --git a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc index 3b8ec4f2872..04308ee254c 100644 --- a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc +++ b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc @@ -38,7 +38,6 @@ #include "src/core/lib/debug/trace.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/gprpp/sync.h" -#include "src/core/lib/iomgr/combiner.h" #include "src/core/lib/iomgr/sockaddr_utils.h" #include "src/core/lib/transport/connectivity_state.h" #include "src/core/lib/transport/static_metadata.h" @@ -63,8 +62,6 @@ class RoundRobin : public LoadBalancingPolicy { void UpdateLocked(UpdateArgs args) override; void ResetBackoffLocked() override; - void FillChildRefsForChannelz(channelz::ChildRefsList* child_subchannels, - channelz::ChildRefsList* ignored) override; private: ~RoundRobin(); @@ -108,9 +105,8 @@ class RoundRobin : public LoadBalancingPolicy { public: RoundRobinSubchannelList(RoundRobin* policy, TraceFlag* tracer, const ServerAddressList& addresses, - grpc_combiner* combiner, const grpc_channel_args& args) - : SubchannelList(policy, tracer, addresses, combiner, + : SubchannelList(policy, tracer, addresses, policy->channel_control_helper(), args) { // Need to maintain a ref to the LB policy as long as we maintain // any references to subchannels, since the subchannels' @@ -157,25 +153,11 @@ class RoundRobin : public LoadBalancingPolicy { RoundRobin* parent_; size_t last_picked_index_; - InlinedVector, 10> subchannels_; - }; - - // Helper class to ensure that any function that modifies the child refs - // data structures will update the channelz snapshot data structures before - // returning. - class AutoChildRefsUpdater { - public: - explicit AutoChildRefsUpdater(RoundRobin* rr) : rr_(rr) {} - ~AutoChildRefsUpdater() { rr_->UpdateChildRefsLocked(); } - - private: - RoundRobin* rr_; + InlinedVector, 10> subchannels_; }; void ShutdownLocked() override; - void UpdateChildRefsLocked(); - /** list of subchannels */ OrphanablePtr subchannel_list_; /** Latest version of the subchannel list. @@ -186,11 +168,6 @@ class RoundRobin : public LoadBalancingPolicy { OrphanablePtr latest_pending_subchannel_list_; /** are we shutting down? */ bool shutdown_ = false; - /// Lock and data used to capture snapshots of this channel's child - /// channels and subchannels. This data is consumed by channelz. - Mutex child_refs_mu_; - channelz::ChildRefsList child_subchannels_; - channelz::ChildRefsList child_channels_; }; // @@ -201,10 +178,9 @@ RoundRobin::Picker::Picker(RoundRobin* parent, RoundRobinSubchannelList* subchannel_list) : parent_(parent) { for (size_t i = 0; i < subchannel_list->num_subchannels(); ++i) { - auto* connected_subchannel = - subchannel_list->subchannel(i)->connected_subchannel(); - if (connected_subchannel != nullptr) { - subchannels_.push_back(connected_subchannel->Ref()); + RoundRobinSubchannelData* sd = subchannel_list->subchannel(i); + if (sd->connectivity_state() == GRPC_CHANNEL_READY) { + subchannels_.push_back(sd->subchannel()->Ref()); } } // For discussion on why we generate a random starting index for @@ -225,14 +201,13 @@ RoundRobin::PickResult RoundRobin::Picker::Pick(PickArgs args) { last_picked_index_ = (last_picked_index_ + 1) % subchannels_.size(); if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_round_robin_trace)) { gpr_log(GPR_INFO, - "[RR %p picker %p] returning index %" PRIuPTR - ", connected_subchannel=%p", + "[RR %p picker %p] returning index %" PRIuPTR ", subchannel=%p", parent_, this, last_picked_index_, subchannels_[last_picked_index_].get()); } PickResult result; result.type = PickResult::PICK_COMPLETE; - result.connected_subchannel = subchannels_[last_picked_index_]; + result.subchannel = subchannels_[last_picked_index_]; return result; } @@ -255,7 +230,6 @@ RoundRobin::~RoundRobin() { } void RoundRobin::ShutdownLocked() { - AutoChildRefsUpdater guard(this); if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_round_robin_trace)) { gpr_log(GPR_INFO, "[RR %p] Shutting down", this); } @@ -271,40 +245,6 @@ void RoundRobin::ResetBackoffLocked() { } } -void RoundRobin::FillChildRefsForChannelz( - channelz::ChildRefsList* child_subchannels_to_fill, - channelz::ChildRefsList* ignored) { - MutexLock lock(&child_refs_mu_); - for (size_t i = 0; i < child_subchannels_.size(); ++i) { - // TODO(ncteisen): implement a de dup loop that is not O(n^2). Might - // have to implement lightweight set. For now, we don't care about - // performance when channelz requests are made. - bool found = false; - for (size_t j = 0; j < child_subchannels_to_fill->size(); ++j) { - if ((*child_subchannels_to_fill)[j] == child_subchannels_[i]) { - found = true; - break; - } - } - if (!found) { - child_subchannels_to_fill->push_back(child_subchannels_[i]); - } - } -} - -void RoundRobin::UpdateChildRefsLocked() { - channelz::ChildRefsList cs; - if (subchannel_list_ != nullptr) { - subchannel_list_->PopulateChildRefsList(&cs); - } - if (latest_pending_subchannel_list_ != nullptr) { - latest_pending_subchannel_list_->PopulateChildRefsList(&cs); - } - // atomically update the data that channelz will actually be looking at. - MutexLock lock(&child_refs_mu_); - child_subchannels_ = std::move(cs); -} - void RoundRobin::RoundRobinSubchannelList::StartWatchingLocked() { if (num_subchannels() == 0) return; // Check current state of each subchannel synchronously, since any @@ -379,8 +319,8 @@ void RoundRobin::RoundRobinSubchannelList:: } else if (num_connecting_ > 0) { /* 2) CONNECTING */ p->channel_control_helper()->UpdateState( - GRPC_CHANNEL_CONNECTING, - UniquePtr(New(p->Ref()))); + GRPC_CHANNEL_CONNECTING, UniquePtr(New( + p->Ref(DEBUG_LOCATION, "QueuePicker")))); } else if (num_transient_failure_ == num_subchannels()) { /* 3) TRANSIENT_FAILURE */ grpc_error* error = @@ -396,7 +336,6 @@ void RoundRobin::RoundRobinSubchannelList:: void RoundRobin::RoundRobinSubchannelList:: UpdateRoundRobinStateFromSubchannelStateCountsLocked() { RoundRobin* p = static_cast(policy()); - AutoChildRefsUpdater guard(p); if (num_ready_ > 0) { if (p->subchannel_list_.get() != this) { // Promote this list to p->subchannel_list_. @@ -468,7 +407,6 @@ void RoundRobin::RoundRobinSubchannelData::ProcessConnectivityChangeLocked( } void RoundRobin::UpdateLocked(UpdateArgs args) { - AutoChildRefsUpdater guard(this); if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_round_robin_trace)) { gpr_log(GPR_INFO, "[RR %p] received update with %" PRIuPTR " addresses", this, args.addresses.size()); @@ -482,7 +420,7 @@ void RoundRobin::UpdateLocked(UpdateArgs args) { } } latest_pending_subchannel_list_ = MakeOrphanable( - this, &grpc_lb_round_robin_trace, args.addresses, combiner(), *args.args); + this, &grpc_lb_round_robin_trace, args.addresses, *args.args); if (latest_pending_subchannel_list_->num_subchannels() == 0) { // If the new list is empty, immediately promote the new list to the // current list and transition to TRANSIENT_FAILURE. diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h index 8929bc4ab1e..34cd0f549fe 100644 --- a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h +++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h @@ -39,7 +39,6 @@ #include "src/core/lib/gprpp/ref_counted.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/iomgr/closure.h" -#include "src/core/lib/iomgr/combiner.h" #include "src/core/lib/iomgr/sockaddr_utils.h" #include "src/core/lib/transport/connectivity_state.h" @@ -64,8 +63,7 @@ class MySubchannelList }; */ -// All methods with a Locked() suffix must be called from within the -// client_channel combiner. +// All methods will be called from within the client_channel combiner. namespace grpc_core { @@ -93,20 +91,13 @@ class SubchannelData { // Returns a pointer to the subchannel. SubchannelInterface* subchannel() const { return subchannel_.get(); } - // Returns the connected subchannel. Will be null if the subchannel - // is not connected. - ConnectedSubchannelInterface* connected_subchannel() const { - return connected_subchannel_.get(); - } - // Synchronously checks the subchannel's connectivity state. // Must not be called while there is a connectivity notification // pending (i.e., between calling StartConnectivityWatchLocked() and // calling CancelConnectivityWatchLocked()). grpc_connectivity_state CheckConnectivityStateLocked() { GPR_ASSERT(pending_watcher_ == nullptr); - connectivity_state_ = - subchannel()->CheckConnectivityState(&connected_subchannel_); + connectivity_state_ = subchannel_->CheckConnectivityState(); return connectivity_state_; } @@ -144,7 +135,8 @@ class SubchannelData { private: // Watcher for subchannel connectivity state. - class Watcher : public SubchannelInterface::ConnectivityStateWatcher { + class Watcher + : public SubchannelInterface::ConnectivityStateWatcherInterface { public: Watcher( SubchannelData* subchannel_data, @@ -154,42 +146,13 @@ class SubchannelData { ~Watcher() { subchannel_list_.reset(DEBUG_LOCATION, "Watcher dtor"); } - void OnConnectivityStateChange(grpc_connectivity_state new_state, - RefCountedPtr - connected_subchannel) override; + void OnConnectivityStateChange(grpc_connectivity_state new_state) override; grpc_pollset_set* interested_parties() override { return subchannel_list_->policy()->interested_parties(); } private: - // A fire-and-forget class that bounces into the combiner to process - // a connectivity state update. - class Updater { - public: - Updater( - SubchannelData* - subchannel_data, - RefCountedPtr> - subchannel_list, - grpc_connectivity_state state, - RefCountedPtr connected_subchannel); - - ~Updater() { - subchannel_list_.reset(DEBUG_LOCATION, "Watcher::Updater dtor"); - } - - private: - static void OnUpdateLocked(void* arg, grpc_error* error); - - SubchannelData* subchannel_data_; - RefCountedPtr> - subchannel_list_; - const grpc_connectivity_state state_; - RefCountedPtr connected_subchannel_; - grpc_closure closure_; - }; - SubchannelData* subchannel_data_; RefCountedPtr subchannel_list_; }; @@ -202,10 +165,10 @@ class SubchannelData { // The subchannel. RefCountedPtr subchannel_; // Will be non-null when the subchannel's state is being watched. - SubchannelInterface::ConnectivityStateWatcher* pending_watcher_ = nullptr; + SubchannelInterface::ConnectivityStateWatcherInterface* pending_watcher_ = + nullptr; // Data updated by the watcher. grpc_connectivity_state connectivity_state_; - RefCountedPtr connected_subchannel_; }; // A list of subchannels. @@ -223,19 +186,6 @@ class SubchannelList : public InternallyRefCounted { // Returns true if the subchannel list is shutting down. bool shutting_down() const { return shutting_down_; } - // Populates refs_list with the uuids of this SubchannelLists's subchannels. - void PopulateChildRefsList(channelz::ChildRefsList* refs_list) { - for (size_t i = 0; i < subchannels_.size(); ++i) { - if (subchannels_[i].subchannel() != nullptr) { - grpc_core::channelz::SubchannelNode* subchannel_node = - subchannels_[i].subchannel()->channelz_node(); - if (subchannel_node != nullptr) { - refs_list->push_back(subchannel_node->uuid()); - } - } - } - } - // Accessors. LoadBalancingPolicy* policy() const { return policy_; } TraceFlag* tracer() const { return tracer_; } @@ -245,7 +195,6 @@ class SubchannelList : public InternallyRefCounted { // the backoff code out of subchannels and into LB policies. void ResetBackoffLocked(); - // Note: Caller must ensure that this is invoked inside of the combiner. void Orphan() override { ShutdownLocked(); InternallyRefCounted::Unref(DEBUG_LOCATION, "shutdown"); @@ -255,7 +204,7 @@ class SubchannelList : public InternallyRefCounted { protected: SubchannelList(LoadBalancingPolicy* policy, TraceFlag* tracer, - const ServerAddressList& addresses, grpc_combiner* combiner, + const ServerAddressList& addresses, LoadBalancingPolicy::ChannelControlHelper* helper, const grpc_channel_args& args); @@ -276,8 +225,6 @@ class SubchannelList : public InternallyRefCounted { TraceFlag* tracer_; - grpc_combiner* combiner_; - // The list of subchannels. SubchannelVector subchannels_; @@ -297,59 +244,26 @@ class SubchannelList : public InternallyRefCounted { template void SubchannelData::Watcher:: - OnConnectivityStateChange( - grpc_connectivity_state new_state, - RefCountedPtr connected_subchannel) { - // Will delete itself. - New(subchannel_data_, - subchannel_list_->Ref(DEBUG_LOCATION, "Watcher::Updater"), - new_state, std::move(connected_subchannel)); -} - -template -SubchannelData::Watcher::Updater:: - Updater( - SubchannelData* subchannel_data, - RefCountedPtr> - subchannel_list, - grpc_connectivity_state state, - RefCountedPtr connected_subchannel) - : subchannel_data_(subchannel_data), - subchannel_list_(std::move(subchannel_list)), - state_(state), - connected_subchannel_(std::move(connected_subchannel)) { - GRPC_CLOSURE_INIT(&closure_, &OnUpdateLocked, this, - grpc_combiner_scheduler(subchannel_list_->combiner_)); - GRPC_CLOSURE_SCHED(&closure_, GRPC_ERROR_NONE); -} - -template -void SubchannelData::Watcher::Updater:: - OnUpdateLocked(void* arg, grpc_error* error) { - Updater* self = static_cast(arg); - SubchannelData* sd = self->subchannel_data_; - if (GRPC_TRACE_FLAG_ENABLED(*sd->subchannel_list_->tracer())) { + OnConnectivityStateChange(grpc_connectivity_state new_state) { + if (GRPC_TRACE_FLAG_ENABLED(*subchannel_list_->tracer())) { gpr_log(GPR_INFO, "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR " (subchannel %p): connectivity changed: state=%s, " - "connected_subchannel=%p, shutting_down=%d, pending_watcher=%p", - sd->subchannel_list_->tracer()->name(), - sd->subchannel_list_->policy(), sd->subchannel_list_, sd->Index(), - sd->subchannel_list_->num_subchannels(), sd->subchannel_.get(), - grpc_connectivity_state_name(self->state_), - self->connected_subchannel_.get(), - sd->subchannel_list_->shutting_down(), sd->pending_watcher_); + "shutting_down=%d, pending_watcher=%p", + subchannel_list_->tracer()->name(), subchannel_list_->policy(), + subchannel_list_.get(), subchannel_data_->Index(), + subchannel_list_->num_subchannels(), + subchannel_data_->subchannel_.get(), + grpc_connectivity_state_name(new_state), + subchannel_list_->shutting_down(), + subchannel_data_->pending_watcher_); } - if (!sd->subchannel_list_->shutting_down() && - sd->pending_watcher_ != nullptr) { - sd->connectivity_state_ = self->state_; - // Get or release ref to connected subchannel. - sd->connected_subchannel_ = std::move(self->connected_subchannel_); + if (!subchannel_list_->shutting_down() && + subchannel_data_->pending_watcher_ != nullptr) { + subchannel_data_->connectivity_state_ = new_state; // Call the subclass's ProcessConnectivityChangeLocked() method. - sd->ProcessConnectivityChangeLocked(sd->connectivity_state_); + subchannel_data_->ProcessConnectivityChangeLocked(new_state); } - // Clean up. - Delete(self); } // @@ -384,7 +298,6 @@ void SubchannelData:: subchannel_.get()); } subchannel_.reset(); - connected_subchannel_.reset(); } } @@ -413,7 +326,7 @@ void SubchannelData(this, subchannel_list()->Ref(DEBUG_LOCATION, "Watcher")); subchannel_->WatchConnectivityState( connectivity_state_, - UniquePtr( + UniquePtr( pending_watcher_)); } @@ -447,13 +360,12 @@ void SubchannelData::ShutdownLocked() { template SubchannelList::SubchannelList( LoadBalancingPolicy* policy, TraceFlag* tracer, - const ServerAddressList& addresses, grpc_combiner* combiner, + const ServerAddressList& addresses, LoadBalancingPolicy::ChannelControlHelper* helper, const grpc_channel_args& args) : InternallyRefCounted(tracer), policy_(policy), - tracer_(tracer), - combiner_(GRPC_COMBINER_REF(combiner, "subchannel_list")) { + tracer_(tracer) { if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) { gpr_log(GPR_INFO, "[%s %p] Creating subchannel list %p for %" PRIuPTR " subchannels", @@ -522,7 +434,6 @@ SubchannelList::~SubchannelList() { gpr_log(GPR_INFO, "[%s %p] Destroying subchannel_list %p", tracer_->name(), policy_, this); } - GRPC_COMBINER_UNREF(combiner_, "subchannel_list"); } template diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc b/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc index b198e0e8637..ca6ab216515 100644 --- a/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc +++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc @@ -117,7 +117,9 @@ TraceFlag grpc_lb_xds_trace(false, "xds"); namespace { constexpr char kXds[] = "xds_experimental"; -constexpr char kDefaultLocalityName[] = "xds_default_locality"; +constexpr char kDefaultLocalityRegion[] = "xds_default_locality_region"; +constexpr char kDefaultLocalityZone[] = "xds_default_locality_zone"; +constexpr char kDefaultLocalitySubzone[] = "xds_default_locality_subzone"; constexpr uint32_t kDefaultLocalityWeight = 3; class ParsedXdsConfig : public LoadBalancingPolicy::Config { @@ -155,9 +157,6 @@ class XdsLb : public LoadBalancingPolicy { void UpdateLocked(UpdateArgs args) override; void ResetBackoffLocked() override; - void FillChildRefsForChannelz( - channelz::ChildRefsList* child_subchannels, - channelz::ChildRefsList* child_channels) override; private: struct LocalityServerlistEntry; @@ -334,6 +333,8 @@ class XdsLb : public LoadBalancingPolicy { explicit FallbackHelper(RefCountedPtr parent) : parent_(std::move(parent)) {} + ~FallbackHelper() { parent_.reset(DEBUG_LOCATION, "FallbackHelper"); } + RefCountedPtr CreateSubchannel( const grpc_channel_args& args) override; grpc_channel* CreateChannel(const char* target, @@ -341,6 +342,7 @@ class XdsLb : public LoadBalancingPolicy { void UpdateState(grpc_connectivity_state state, UniquePtr picker) override; void RequestReresolution() override; + void AddTraceEvent(TraceSeverity severity, const char* message) override; void set_child(LoadBalancingPolicy* child) { child_ = child; } @@ -352,21 +354,61 @@ class XdsLb : public LoadBalancingPolicy { LoadBalancingPolicy* child_ = nullptr; }; + class LocalityName : public RefCounted { + public: + struct Less { + bool operator()(const RefCountedPtr& lhs, + const RefCountedPtr& rhs) { + int cmp_result = strcmp(lhs->region_.get(), rhs->region_.get()); + if (cmp_result != 0) return cmp_result < 0; + cmp_result = strcmp(lhs->zone_.get(), rhs->zone_.get()); + if (cmp_result != 0) return cmp_result < 0; + return strcmp(lhs->subzone_.get(), rhs->subzone_.get()) < 0; + } + }; + + LocalityName(UniquePtr region, UniquePtr zone, + UniquePtr subzone) + : region_(std::move(region)), + zone_(std::move(zone)), + subzone_(std::move(subzone)) {} + + bool operator==(const LocalityName& other) const { + return strcmp(region_.get(), other.region_.get()) == 0 && + strcmp(zone_.get(), other.zone_.get()) == 0 && + strcmp(subzone_.get(), other.subzone_.get()) == 0; + } + + const char* AsHumanReadableString() { + if (human_readable_string_ == nullptr) { + char* tmp; + gpr_asprintf(&tmp, "{region=\"%s\", zone=\"%s\", subzone=\"%s\"}", + region_.get(), zone_.get(), subzone_.get()); + human_readable_string_.reset(tmp); + } + return human_readable_string_.get(); + } + + private: + UniquePtr region_; + UniquePtr zone_; + UniquePtr subzone_; + UniquePtr human_readable_string_; + }; + class LocalityMap { public: class LocalityEntry : public InternallyRefCounted { public: - LocalityEntry(RefCountedPtr parent, uint32_t locality_weight) - : parent_(std::move(parent)), locality_weight_(locality_weight) {} - ~LocalityEntry() = default; + LocalityEntry(RefCountedPtr parent, + RefCountedPtr name, uint32_t locality_weight); + ~LocalityEntry(); void UpdateLocked(xds_grpclb_serverlist* serverlist, LoadBalancingPolicy::Config* child_policy_config, const grpc_channel_args* args); void ShutdownLocked(); void ResetBackoffLocked(); - void FillChildRefsForChannelz(channelz::ChildRefsList* child_subchannels, - channelz::ChildRefsList* child_channels); void Orphan() override; private: @@ -375,6 +417,8 @@ class XdsLb : public LoadBalancingPolicy { explicit Helper(RefCountedPtr entry) : entry_(std::move(entry)) {} + ~Helper() { entry_.reset(DEBUG_LOCATION, "Helper"); } + RefCountedPtr CreateSubchannel( const grpc_channel_args& args) override; grpc_channel* CreateChannel(const char* target, @@ -382,6 +426,8 @@ class XdsLb : public LoadBalancingPolicy { void UpdateState(grpc_connectivity_state state, UniquePtr picker) override; void RequestReresolution() override; + void AddTraceEvent(TraceSeverity severity, + const char* message) override; void set_child(LoadBalancingPolicy* child) { child_ = child; } private: @@ -397,12 +443,10 @@ class XdsLb : public LoadBalancingPolicy { grpc_channel_args* CreateChildPolicyArgsLocked( const grpc_channel_args* args); + RefCountedPtr parent_; + RefCountedPtr name_; OrphanablePtr child_policy_; OrphanablePtr pending_child_policy_; - // Lock held when modifying the value of child_policy_ or - // pending_child_policy_. - Mutex child_policy_mu_; - RefCountedPtr parent_; RefCountedPtr picker_ref_; grpc_connectivity_state connectivity_state_; uint32_t locality_weight_; @@ -413,24 +457,18 @@ class XdsLb : public LoadBalancingPolicy { const grpc_channel_args* args, XdsLb* parent); void ShutdownLocked(); void ResetBackoffLocked(); - void FillChildRefsForChannelz(channelz::ChildRefsList* child_subchannels, - channelz::ChildRefsList* child_channels); private: void PruneLocalities(const LocalityList& locality_list); - Map, OrphanablePtr, StringLess> map_; - // Lock held while filling child refs for all localities - // inside the map - Mutex child_refs_mu_; + Map, OrphanablePtr, + LocalityName::Less> + map_; }; struct LocalityServerlistEntry { - ~LocalityServerlistEntry() { - gpr_free(locality_name); - xds_grpclb_destroy_serverlist(serverlist); - } + ~LocalityServerlistEntry() { xds_grpclb_destroy_serverlist(serverlist); } - char* locality_name; + RefCountedPtr locality_name; uint32_t locality_weight; // The deserialized response from the balancer. May be nullptr until one // such response has arrived. @@ -479,10 +517,6 @@ class XdsLb : public LoadBalancingPolicy { // The channel for communicating with the LB server. OrphanablePtr lb_chand_; OrphanablePtr pending_lb_chand_; - // Mutex to protect the channel to the LB server. This is used when - // processing a channelz request. - // TODO(juanlishen): Replace this with atomic. - Mutex lb_chand_mu_; // Timeout in milliseconds for the LB call. 0 means no deadline. int lb_call_timeout_ms_ = 0; @@ -506,9 +540,6 @@ class XdsLb : public LoadBalancingPolicy { // The policy to use for the fallback backends. RefCountedPtr fallback_policy_config_; - // Lock held when modifying the value of fallback_policy_ or - // pending_fallback_policy_. - Mutex fallback_policy_mu_; // Non-null iff we are in fallback mode. OrphanablePtr fallback_policy_; OrphanablePtr pending_fallback_policy_; @@ -539,7 +570,7 @@ XdsLb::PickResult XdsLb::Picker::Pick(PickArgs args) { PickResult result = PickFromLocality(key, args); // If pick succeeded, add client stats. if (result.type == PickResult::PICK_COMPLETE && - result.connected_subchannel != nullptr && client_stats_ != nullptr) { + result.subchannel != nullptr && client_stats_ != nullptr) { // TODO(roth): Add support for client stats. } return result; @@ -616,7 +647,6 @@ void XdsLb::FallbackHelper::UpdateState(grpc_connectivity_state state, grpc_pollset_set_del_pollset_set( parent_->fallback_policy_->interested_parties(), parent_->interested_parties()); - MutexLock lock(&parent_->fallback_policy_mu_); parent_->fallback_policy_ = std::move(parent_->pending_fallback_policy_); } else if (!CalledByCurrentFallback()) { // This request is from an outdated fallback policy, so ignore it. @@ -641,6 +671,15 @@ void XdsLb::FallbackHelper::RequestReresolution() { parent_->channel_control_helper()->RequestReresolution(); } +void XdsLb::FallbackHelper::AddTraceEvent(TraceSeverity severity, + const char* message) { + if (parent_->shutting_down_ || + (!CalledByPendingFallback() && !CalledByCurrentFallback())) { + return; + } + parent_->channel_control_helper()->AddTraceEvent(severity, message); +} + // // serverlist parsing code // @@ -720,7 +759,7 @@ ServerAddressList ProcessServerlist(const xds_grpclb_serverlist* serverlist) { XdsLb::BalancerChannelState::BalancerChannelState( const char* balancer_name, const grpc_channel_args& args, - grpc_core::RefCountedPtr parent_xdslb_policy) + RefCountedPtr parent_xdslb_policy) : InternallyRefCounted(&grpc_lb_xds_trace), xdslb_policy_(std::move(parent_xdslb_policy)), lb_call_backoff_( @@ -740,6 +779,7 @@ XdsLb::BalancerChannelState::BalancerChannelState( } XdsLb::BalancerChannelState::~BalancerChannelState() { + xdslb_policy_.reset(DEBUG_LOCATION, "BalancerChannelState"); grpc_channel_destroy(channel_); } @@ -1199,7 +1239,10 @@ void XdsLb::BalancerChannelState::BalancerCallState:: xdslb_policy->locality_serverlist_.emplace_back( MakeUnique()); xdslb_policy->locality_serverlist_[0]->locality_name = - static_cast(gpr_strdup(kDefaultLocalityName)); + MakeRefCounted( + UniquePtr(gpr_strdup(kDefaultLocalityRegion)), + UniquePtr(gpr_strdup(kDefaultLocalityZone)), + UniquePtr(gpr_strdup(kDefaultLocalitySubzone))); xdslb_policy->locality_serverlist_[0]->locality_weight = kDefaultLocalityWeight; } @@ -1330,21 +1373,29 @@ grpc_channel_args* BuildBalancerChannelArgs(const grpc_channel_args* args) { // treated as a stand-alone channel and not inherit this argument from the // args of the parent channel. GRPC_SSL_TARGET_NAME_OVERRIDE_ARG, + // Don't want to pass down channelz node from parent; the balancer + // channel will get its own. + GRPC_ARG_CHANNELZ_CHANNEL_NODE, }; // Channel args to add. - const grpc_arg args_to_add[] = { - // A channel arg indicating the target is a xds load balancer. - grpc_channel_arg_integer_create( - const_cast(GRPC_ARG_ADDRESS_IS_XDS_LOAD_BALANCER), 1), - // A channel arg indicating this is an internal channels, aka it is - // owned by components in Core, not by the user application. - grpc_channel_arg_integer_create( - const_cast(GRPC_ARG_CHANNELZ_CHANNEL_IS_INTERNAL_CHANNEL), 1), - }; + InlinedVector args_to_add; + // A channel arg indicating the target is a xds load balancer. + args_to_add.emplace_back(grpc_channel_arg_integer_create( + const_cast(GRPC_ARG_ADDRESS_IS_XDS_LOAD_BALANCER), 1)); + // The parent channel's channelz uuid. + channelz::ChannelNode* channelz_node = nullptr; + const grpc_arg* arg = + grpc_channel_args_find(args, GRPC_ARG_CHANNELZ_CHANNEL_NODE); + if (arg != nullptr && arg->type == GRPC_ARG_POINTER && + arg->value.pointer.p != nullptr) { + channelz_node = static_cast(arg->value.pointer.p); + args_to_add.emplace_back( + channelz::MakeParentUuidArg(channelz_node->uuid())); + } // Construct channel args. grpc_channel_args* new_args = grpc_channel_args_copy_and_add_and_remove( - args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), args_to_add, - GPR_ARRAY_SIZE(args_to_add)); + args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), args_to_add.data(), + args_to_add.size()); // Make any necessary modifications for security. return grpc_lb_policy_xds_modify_lb_channel_args(new_args); } @@ -1380,12 +1431,18 @@ XdsLb::XdsLb(Args args) } XdsLb::~XdsLb() { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { + gpr_log(GPR_INFO, "[xdslb %p] destroying xds LB policy", this); + } gpr_free((void*)server_name_); grpc_channel_args_destroy(args_); locality_serverlist_.clear(); } void XdsLb::ShutdownLocked() { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { + gpr_log(GPR_INFO, "[xdslb %p] shutting down", this); + } shutting_down_ = true; if (fallback_at_startup_checks_pending_) { grpc_timer_cancel(&lb_fallback_timer_); @@ -1399,18 +1456,12 @@ void XdsLb::ShutdownLocked() { grpc_pollset_set_del_pollset_set( pending_fallback_policy_->interested_parties(), interested_parties()); } - { - MutexLock lock(&fallback_policy_mu_); - fallback_policy_.reset(); - pending_fallback_policy_.reset(); - } + fallback_policy_.reset(); + pending_fallback_policy_.reset(); // We reset the LB channels here instead of in our destructor because they // hold refs to XdsLb. - { - MutexLock lock(&lb_chand_mu_); - lb_chand_.reset(); - pending_lb_chand_.reset(); - } + lb_chand_.reset(); + pending_lb_chand_.reset(); } // @@ -1433,40 +1484,6 @@ void XdsLb::ResetBackoffLocked() { } } -void XdsLb::FillChildRefsForChannelz(channelz::ChildRefsList* child_subchannels, - channelz::ChildRefsList* child_channels) { - // Delegate to the locality_map_ to fill the children subchannels. - locality_map_.FillChildRefsForChannelz(child_subchannels, child_channels); - { - // This must be done holding fallback_policy_mu_, since this method does not - // run in the combiner. - MutexLock lock(&fallback_policy_mu_); - if (fallback_policy_ != nullptr) { - fallback_policy_->FillChildRefsForChannelz(child_subchannels, - child_channels); - } - if (pending_fallback_policy_ != nullptr) { - pending_fallback_policy_->FillChildRefsForChannelz(child_subchannels, - child_channels); - } - } - MutexLock lock(&lb_chand_mu_); - if (lb_chand_ != nullptr) { - grpc_core::channelz::ChannelNode* channel_node = - grpc_channel_get_channelz_node(lb_chand_->channel()); - if (channel_node != nullptr) { - child_channels->push_back(channel_node->uuid()); - } - } - if (pending_lb_chand_ != nullptr) { - grpc_core::channelz::ChannelNode* channel_node = - grpc_channel_get_channelz_node(pending_lb_chand_->channel()); - if (channel_node != nullptr) { - child_channels->push_back(channel_node->uuid()); - } - } -} - void XdsLb::ProcessAddressesAndChannelArgsLocked( const ServerAddressList& addresses, const grpc_channel_args& args) { // Update fallback address list. @@ -1492,8 +1509,9 @@ void XdsLb::ProcessAddressesAndChannelArgsLocked( } if (create_lb_channel) { OrphanablePtr lb_chand = - MakeOrphanable(balancer_name_.get(), - *lb_channel_args, Ref()); + MakeOrphanable( + balancer_name_.get(), *lb_channel_args, + Ref(DEBUG_LOCATION, "BalancerChannelState")); if (lb_chand_ == nullptr || !lb_chand_->HasActiveCall()) { GPR_ASSERT(pending_lb_chand_ == nullptr); // If we do not have a working LB channel yet, use the newly created one. @@ -1656,14 +1674,10 @@ void XdsLb::UpdateFallbackPolicyLocked() { fallback_policy_ == nullptr ? "" : "pending ", fallback_policy_name); } - auto new_policy = - CreateFallbackPolicyLocked(fallback_policy_name, update_args.args); auto& lb_policy = fallback_policy_ == nullptr ? fallback_policy_ : pending_fallback_policy_; - { - MutexLock lock(&fallback_policy_mu_); - lb_policy = std::move(new_policy); - } + lb_policy = + CreateFallbackPolicyLocked(fallback_policy_name, update_args.args); policy_to_update = lb_policy.get(); } else { // Cases 2a and 3a: update an existing policy. @@ -1686,7 +1700,8 @@ void XdsLb::UpdateFallbackPolicyLocked() { OrphanablePtr XdsLb::CreateFallbackPolicyLocked( const char* name, const grpc_channel_args* args) { - FallbackHelper* helper = New(Ref()); + FallbackHelper* helper = + New(Ref(DEBUG_LOCATION, "FallbackHelper")); LoadBalancingPolicy::Args lb_policy_args; lb_policy_args.combiner = combiner(); lb_policy_args.args = args; @@ -1728,12 +1743,12 @@ void XdsLb::LocalityMap::PruneLocalities(const LocalityList& locality_list) { for (auto iter = map_.begin(); iter != map_.end();) { bool found = false; for (size_t i = 0; i < locality_list.size(); i++) { - if (!gpr_stricmp(locality_list[i]->locality_name, iter->first.get())) { + if (*locality_list[i]->locality_name == *iter->first) { found = true; + break; } } if (!found) { // Remove entries not present in the locality list - MutexLock lock(&child_refs_mu_); iter = map_.erase(iter); } else iter++; @@ -1746,14 +1761,15 @@ void XdsLb::LocalityMap::UpdateLocked( const grpc_channel_args* args, XdsLb* parent) { if (parent->shutting_down_) return; for (size_t i = 0; i < locality_serverlist.size(); i++) { - UniquePtr locality_name( - gpr_strdup(locality_serverlist[i]->locality_name)); - auto iter = map_.find(locality_name); + auto iter = map_.find(locality_serverlist[i]->locality_name); if (iter == map_.end()) { OrphanablePtr new_entry = MakeOrphanable( - parent->Ref(), locality_serverlist[i]->locality_weight); - MutexLock lock(&child_refs_mu_); - iter = map_.emplace(std::move(locality_name), std::move(new_entry)).first; + parent->Ref(DEBUG_LOCATION, "LocalityEntry"), + locality_serverlist[i]->locality_name, + locality_serverlist[i]->locality_weight); + iter = map_.emplace(locality_serverlist[i]->locality_name, + std::move(new_entry)) + .first; } // Don't create new child policies if not directed to xds_grpclb_serverlist* serverlist = @@ -1763,10 +1779,7 @@ void XdsLb::LocalityMap::UpdateLocked( PruneLocalities(locality_serverlist); } -void XdsLb::LocalityMap::ShutdownLocked() { - MutexLock lock(&child_refs_mu_); - map_.clear(); -} +void XdsLb::LocalityMap::ShutdownLocked() { map_.clear(); } void XdsLb::LocalityMap::ResetBackoffLocked() { for (auto& p : map_) { @@ -1774,19 +1787,31 @@ void XdsLb::LocalityMap::ResetBackoffLocked() { } } -void XdsLb::LocalityMap::FillChildRefsForChannelz( - channelz::ChildRefsList* child_subchannels, - channelz::ChildRefsList* child_channels) { - MutexLock lock(&child_refs_mu_); - for (auto& p : map_) { - p.second->FillChildRefsForChannelz(child_subchannels, child_channels); - } -} - // // XdsLb::LocalityMap::LocalityEntry // +XdsLb::LocalityMap::LocalityEntry::LocalityEntry( + RefCountedPtr parent, RefCountedPtr name, + uint32_t locality_weight) + : parent_(std::move(parent)), + name_(std::move(name)), + locality_weight_(locality_weight) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { + gpr_log(GPR_INFO, "[xdslb %p] created LocalityEntry %p for %s", + parent_.get(), this, name_->AsHumanReadableString()); + } +} + +XdsLb::LocalityMap::LocalityEntry::~LocalityEntry() { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { + gpr_log(GPR_INFO, + "[xdslb %p] LocalityEntry %p %s: destroying locality entry", + parent_.get(), this, name_->AsHumanReadableString()); + } + parent_.reset(DEBUG_LOCATION, "LocalityEntry"); +} + grpc_channel_args* XdsLb::LocalityMap::LocalityEntry::CreateChildPolicyArgsLocked( const grpc_channel_args* args_in) { @@ -1808,7 +1833,7 @@ XdsLb::LocalityMap::LocalityEntry::CreateChildPolicyArgsLocked( OrphanablePtr XdsLb::LocalityMap::LocalityEntry::CreateChildPolicyLocked( const char* name, const grpc_channel_args* args) { - Helper* helper = New(this->Ref()); + Helper* helper = New(this->Ref(DEBUG_LOCATION, "Helper")); LoadBalancingPolicy::Args lb_policy_args; lb_policy_args.combiner = parent_->combiner(); lb_policy_args.args = args; @@ -1818,13 +1843,16 @@ XdsLb::LocalityMap::LocalityEntry::CreateChildPolicyLocked( LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy( name, std::move(lb_policy_args)); if (GPR_UNLIKELY(lb_policy == nullptr)) { - gpr_log(GPR_ERROR, "[xdslb %p] Failure creating child policy %s", this, - name); + gpr_log(GPR_ERROR, + "[xdslb %p] LocalityEntry %p %s: failure creating child policy %s", + parent_.get(), this, name_->AsHumanReadableString(), name); return nullptr; } helper->set_child(lb_policy.get()); if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { - gpr_log(GPR_INFO, "[xdslb %p] Created new child policy %s (%p)", this, name, + gpr_log(GPR_INFO, + "[xdslb %p] LocalityEntry %p %s: Created new child policy %s (%p)", + parent_.get(), this, name_->AsHumanReadableString(), name, lb_policy.get()); } // Add the xDS's interested_parties pollset_set to that of the newly created @@ -1915,17 +1943,14 @@ void XdsLb::LocalityMap::LocalityEntry::UpdateLocked( // If child_policy_ is null, we set it (case 1), else we set // pending_child_policy_ (cases 2b and 3b). if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { - gpr_log(GPR_INFO, "[xdslb %p] Creating new %schild policy %s", this, + gpr_log(GPR_INFO, + "[xdslb %p] LocalityEntry %p %s: Creating new %schild policy %s", + parent_.get(), this, name_->AsHumanReadableString(), child_policy_ == nullptr ? "" : "pending ", child_policy_name); } - auto new_policy = - CreateChildPolicyLocked(child_policy_name, update_args.args); auto& lb_policy = child_policy_ == nullptr ? child_policy_ : pending_child_policy_; - { - MutexLock lock(&child_policy_mu_); - lb_policy = std::move(new_policy); - } + lb_policy = CreateChildPolicyLocked(child_policy_name, update_args.args); policy_to_update = lb_policy.get(); } else { // Cases 2a and 3a: update an existing policy. @@ -1938,7 +1963,9 @@ void XdsLb::LocalityMap::LocalityEntry::UpdateLocked( GPR_ASSERT(policy_to_update != nullptr); // Update the policy. if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { - gpr_log(GPR_INFO, "[xdslb %p] Updating %schild policy %p", this, + gpr_log(GPR_INFO, + "[xdslb %p] LocalityEntry %p %s: Updating %schild policy %p", + parent_.get(), this, name_->AsHumanReadableString(), policy_to_update == pending_child_policy_.get() ? "pending " : "", policy_to_update); } @@ -1946,20 +1973,25 @@ void XdsLb::LocalityMap::LocalityEntry::UpdateLocked( } void XdsLb::LocalityMap::LocalityEntry::ShutdownLocked() { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { + gpr_log(GPR_INFO, + "[xdslb %p] LocalityEntry %p %s: shutting down locality entry", + parent_.get(), this, name_->AsHumanReadableString()); + } // Remove the child policy's interested_parties pollset_set from the // xDS policy. grpc_pollset_set_del_pollset_set(child_policy_->interested_parties(), parent_->interested_parties()); + child_policy_.reset(); if (pending_child_policy_ != nullptr) { grpc_pollset_set_del_pollset_set( pending_child_policy_->interested_parties(), parent_->interested_parties()); - } - { - MutexLock lock(&child_policy_mu_); - child_policy_.reset(); pending_child_policy_.reset(); } + // Drop our ref to the child's picker, in case it's holding a ref to + // the child. + picker_ref_.reset(); } void XdsLb::LocalityMap::LocalityEntry::ResetBackoffLocked() { @@ -1969,17 +2001,6 @@ void XdsLb::LocalityMap::LocalityEntry::ResetBackoffLocked() { } } -void XdsLb::LocalityMap::LocalityEntry::FillChildRefsForChannelz( - channelz::ChildRefsList* child_subchannels, - channelz::ChildRefsList* child_channels) { - MutexLock lock(&child_policy_mu_); - child_policy_->FillChildRefsForChannelz(child_subchannels, child_channels); - if (pending_child_policy_ != nullptr) { - pending_child_policy_->FillChildRefsForChannelz(child_subchannels, - child_channels); - } -} - void XdsLb::LocalityMap::LocalityEntry::Orphan() { ShutdownLocked(); Unref(); @@ -2034,7 +2055,6 @@ void XdsLb::LocalityMap::LocalityEntry::Helper::UpdateState( grpc_pollset_set_del_pollset_set( entry_->child_policy_->interested_parties(), entry_->parent_->interested_parties()); - MutexLock lock(&entry_->child_policy_mu_); entry_->child_policy_ = std::move(entry_->pending_child_policy_); } else if (!CalledByCurrentChild()) { // This request is from an outdated child, so ignore it. @@ -2104,11 +2124,13 @@ void XdsLb::LocalityMap::LocalityEntry::Helper::UpdateState( } else if (num_connecting > 0) { entry_->parent_->channel_control_helper()->UpdateState( GRPC_CHANNEL_CONNECTING, - UniquePtr(New(this->entry_->parent_))); + UniquePtr(New( + this->entry_->parent_->Ref(DEBUG_LOCATION, "QueuePicker")))); } else if (num_idle > 0) { entry_->parent_->channel_control_helper()->UpdateState( GRPC_CHANNEL_IDLE, - UniquePtr(New(this->entry_->parent_))); + UniquePtr(New( + this->entry_->parent_->Ref(DEBUG_LOCATION, "QueuePicker")))); } else { GPR_ASSERT(num_transient_failures == locality_map.size()); grpc_error* error = @@ -2144,6 +2166,15 @@ void XdsLb::LocalityMap::LocalityEntry::Helper::RequestReresolution() { } } +void XdsLb::LocalityMap::LocalityEntry::Helper::AddTraceEvent( + TraceSeverity severity, const char* message) { + if (entry_->parent_->shutting_down_ || + (!CalledByPendingChild() && !CalledByCurrentChild())) { + return; + } + entry_->parent_->channel_control_helper()->AddTraceEvent(severity, message); +} + // // factory // diff --git a/src/core/ext/filters/client_channel/resolver.h b/src/core/ext/filters/client_channel/resolver.h index 9aa504225ad..829a860040a 100644 --- a/src/core/ext/filters/client_channel/resolver.h +++ b/src/core/ext/filters/client_channel/resolver.h @@ -117,18 +117,16 @@ class Resolver : public InternallyRefCounted { /// implementations. At that point, this method can go away. virtual void ResetBackoffLocked() {} + // Note: This must be invoked while holding the combiner. void Orphan() override { - // Invoke ShutdownAndUnrefLocked() inside of the combiner. - GRPC_CLOSURE_SCHED( - GRPC_CLOSURE_CREATE(&Resolver::ShutdownAndUnrefLocked, this, - grpc_combiner_scheduler(combiner_)), - GRPC_ERROR_NONE); + ShutdownLocked(); + Unref(); } GRPC_ABSTRACT_BASE_CLASS protected: - GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE + GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE /// Does NOT take ownership of the reference to \a combiner. // TODO(roth): Once we have a C++-like interface for combiners, this @@ -147,12 +145,6 @@ class Resolver : public InternallyRefCounted { ResultHandler* result_handler() const { return result_handler_.get(); } private: - static void ShutdownAndUnrefLocked(void* arg, grpc_error* ignored) { - Resolver* resolver = static_cast(arg); - resolver->ShutdownLocked(); - resolver->Unref(); - } - UniquePtr result_handler_; grpc_combiner* combiner_; }; diff --git a/src/core/ext/filters/client_channel/resolving_lb_policy.cc b/src/core/ext/filters/client_channel/resolving_lb_policy.cc index d23ac1f4e33..180b0fcbbf4 100644 --- a/src/core/ext/filters/client_channel/resolving_lb_policy.cc +++ b/src/core/ext/filters/client_channel/resolving_lb_policy.cc @@ -137,7 +137,6 @@ class ResolvingLoadBalancingPolicy::ResolvingControlHelper grpc_pollset_set_del_pollset_set( parent_->lb_policy_->interested_parties(), parent_->interested_parties()); - MutexLock lock(&parent_->lb_policy_mu_); parent_->lb_policy_ = std::move(parent_->pending_lb_policy_); } else if (!CalledByCurrentChild()) { // This request is from an outdated child, so ignore it. @@ -214,7 +213,6 @@ ResolvingLoadBalancingPolicy::ResolvingLoadBalancingPolicy( process_resolver_result_(process_resolver_result), process_resolver_result_user_data_(process_resolver_result_user_data) { GPR_ASSERT(process_resolver_result != nullptr); - gpr_mu_init(&lb_policy_mu_); *error = Init(*args.args); } @@ -234,13 +232,11 @@ grpc_error* ResolvingLoadBalancingPolicy::Init(const grpc_channel_args& args) { ResolvingLoadBalancingPolicy::~ResolvingLoadBalancingPolicy() { GPR_ASSERT(resolver_ == nullptr); GPR_ASSERT(lb_policy_ == nullptr); - gpr_mu_destroy(&lb_policy_mu_); } void ResolvingLoadBalancingPolicy::ShutdownLocked() { if (resolver_ != nullptr) { resolver_.reset(); - MutexLock lock(&lb_policy_mu_); if (lb_policy_ != nullptr) { if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) { gpr_log(GPR_INFO, "resolving_lb=%p: shutting down lb_policy=%p", this, @@ -282,22 +278,6 @@ void ResolvingLoadBalancingPolicy::ResetBackoffLocked() { if (pending_lb_policy_ != nullptr) pending_lb_policy_->ResetBackoffLocked(); } -void ResolvingLoadBalancingPolicy::FillChildRefsForChannelz( - channelz::ChildRefsList* child_subchannels, - channelz::ChildRefsList* child_channels) { - // Delegate to the lb_policy_ to fill the children subchannels. - // This must be done holding lb_policy_mu_, since this method does not - // run in the combiner. - MutexLock lock(&lb_policy_mu_); - if (lb_policy_ != nullptr) { - lb_policy_->FillChildRefsForChannelz(child_subchannels, child_channels); - } - if (pending_lb_policy_ != nullptr) { - pending_lb_policy_->FillChildRefsForChannelz(child_subchannels, - child_channels); - } -} - void ResolvingLoadBalancingPolicy::StartResolvingLocked() { if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) { gpr_log(GPR_INFO, "resolving_lb=%p: starting name resolution", this); @@ -403,13 +383,9 @@ void ResolvingLoadBalancingPolicy::CreateOrUpdateLbPolicyLocked( gpr_log(GPR_INFO, "resolving_lb=%p: Creating new %schild policy %s", this, lb_policy_ == nullptr ? "" : "pending ", lb_policy_name); } - auto new_policy = - CreateLbPolicyLocked(lb_policy_name, *result.args, trace_strings); auto& lb_policy = lb_policy_ == nullptr ? lb_policy_ : pending_lb_policy_; - { - MutexLock lock(&lb_policy_mu_); - lb_policy = std::move(new_policy); - } + lb_policy = + CreateLbPolicyLocked(lb_policy_name, *result.args, trace_strings); policy_to_update = lb_policy.get(); } else { // Cases 2a and 3a: update an existing policy. @@ -451,11 +427,9 @@ ResolvingLoadBalancingPolicy::CreateLbPolicyLocked( lb_policy_name, std::move(lb_policy_args)); if (GPR_UNLIKELY(lb_policy == nullptr)) { gpr_log(GPR_ERROR, "could not create LB policy \"%s\"", lb_policy_name); - if (channelz_node() != nullptr) { - char* str; - gpr_asprintf(&str, "Could not create LB policy \"%s\"", lb_policy_name); - trace_strings->push_back(str); - } + char* str; + gpr_asprintf(&str, "Could not create LB policy \"%s\"", lb_policy_name); + trace_strings->push_back(str); return nullptr; } helper->set_child(lb_policy.get()); @@ -463,16 +437,9 @@ ResolvingLoadBalancingPolicy::CreateLbPolicyLocked( gpr_log(GPR_INFO, "resolving_lb=%p: created new LB policy \"%s\" (%p)", this, lb_policy_name, lb_policy.get()); } - if (channelz_node() != nullptr) { - char* str; - gpr_asprintf(&str, "Created new LB policy \"%s\"", lb_policy_name); - trace_strings->push_back(str); - } - // Propagate channelz node. - auto* channelz = channelz_node(); - if (channelz != nullptr) { - lb_policy->set_channelz_node(channelz->Ref()); - } + char* str; + gpr_asprintf(&str, "Created new LB policy \"%s\"", lb_policy_name); + trace_strings->push_back(str); grpc_pollset_set_add_pollset_set(lb_policy->interested_parties(), interested_parties()); return lb_policy; @@ -502,11 +469,10 @@ void ResolvingLoadBalancingPolicy::ConcatenateAndAddChannelTraceLocked( is_first = false; gpr_strvec_add(&v, (*trace_strings)[i]); } - char* flat; - size_t flat_len = 0; - flat = gpr_strvec_flatten(&v, &flat_len); - channelz_node()->AddTraceEvent(channelz::ChannelTrace::Severity::Info, - grpc_slice_new(flat, flat_len, gpr_free)); + size_t len = 0; + UniquePtr message(gpr_strvec_flatten(&v, &len)); + channel_control_helper()->AddTraceEvent(ChannelControlHelper::TRACE_INFO, + message.get()); gpr_strvec_destroy(&v); } } @@ -560,21 +526,18 @@ void ResolvingLoadBalancingPolicy::OnResolverResultChangedLocked( std::move(result), &trace_strings); } // Add channel trace event. - if (channelz_node() != nullptr) { - if (service_config_changed) { - // TODO(ncteisen): might be worth somehow including a snippet of the - // config in the trace, at the risk of bloating the trace logs. - trace_strings.push_back(gpr_strdup("Service config changed")); - } - if (service_config_error_string != nullptr) { - trace_strings.push_back(service_config_error_string); - service_config_error_string = nullptr; - } - MaybeAddTraceMessagesForAddressChangesLocked(resolution_contains_addresses, - &trace_strings); - ConcatenateAndAddChannelTraceLocked(&trace_strings); + if (service_config_changed) { + // TODO(ncteisen): might be worth somehow including a snippet of the + // config in the trace, at the risk of bloating the trace logs. + trace_strings.push_back(gpr_strdup("Service config changed")); + } + if (service_config_error_string != nullptr) { + trace_strings.push_back(service_config_error_string); + service_config_error_string = nullptr; } - gpr_free(service_config_error_string); + MaybeAddTraceMessagesForAddressChangesLocked(resolution_contains_addresses, + &trace_strings); + ConcatenateAndAddChannelTraceLocked(&trace_strings); } } // namespace grpc_core diff --git a/src/core/ext/filters/client_channel/resolving_lb_policy.h b/src/core/ext/filters/client_channel/resolving_lb_policy.h index 679c8d0fba0..e91ea832661 100644 --- a/src/core/ext/filters/client_channel/resolving_lb_policy.h +++ b/src/core/ext/filters/client_channel/resolving_lb_policy.h @@ -21,7 +21,6 @@ #include -#include "src/core/ext/filters/client_channel/client_channel_channelz.h" #include "src/core/ext/filters/client_channel/lb_policy.h" #include "src/core/ext/filters/client_channel/lb_policy_factory.h" #include "src/core/ext/filters/client_channel/resolver.h" @@ -91,10 +90,6 @@ class ResolvingLoadBalancingPolicy : public LoadBalancingPolicy { void ResetBackoffLocked() override; - void FillChildRefsForChannelz( - channelz::ChildRefsList* child_subchannels, - channelz::ChildRefsList* child_channels) override; - private: using TraceStringVector = InlinedVector; @@ -137,9 +132,6 @@ class ResolvingLoadBalancingPolicy : public LoadBalancingPolicy { // Child LB policy. OrphanablePtr lb_policy_; OrphanablePtr pending_lb_policy_; - // Lock held when modifying the value of child_policy_ or - // pending_child_policy_. - gpr_mu lb_policy_mu_; }; } // namespace grpc_core diff --git a/src/core/ext/filters/client_channel/server_address.cc b/src/core/ext/filters/client_channel/server_address.cc index c2941afbcfd..31c0edaca17 100644 --- a/src/core/ext/filters/client_channel/server_address.cc +++ b/src/core/ext/filters/client_channel/server_address.cc @@ -39,12 +39,10 @@ ServerAddress::ServerAddress(const void* address, size_t address_len, address_.len = static_cast(address_len); } -int ServerAddress::Cmp(const ServerAddress& other) const { - if (address_.len > other.address_.len) return 1; - if (address_.len < other.address_.len) return -1; - int retval = memcmp(address_.addr, other.address_.addr, address_.len); - if (retval != 0) return retval; - return grpc_channel_args_compare(args_, other.args_); +bool ServerAddress::operator==(const grpc_core::ServerAddress& other) const { + return address_.len == other.address_.len && + memcmp(address_.addr, other.address_.addr, address_.len) == 0 && + grpc_channel_args_compare(args_, other.args_) == 0; } bool ServerAddress::IsBalancer() const { diff --git a/src/core/ext/filters/client_channel/server_address.h b/src/core/ext/filters/client_channel/server_address.h index 040cd2ee317..1b68a59ed85 100644 --- a/src/core/ext/filters/client_channel/server_address.h +++ b/src/core/ext/filters/client_channel/server_address.h @@ -73,9 +73,7 @@ class ServerAddress { return *this; } - bool operator==(const ServerAddress& other) const { return Cmp(other) == 0; } - - int Cmp(const ServerAddress& other) const; + bool operator==(const ServerAddress& other) const; const grpc_resolved_address& address() const { return address_; } const grpc_channel_args* args() const { return args_; } diff --git a/src/core/ext/filters/client_channel/subchannel.cc b/src/core/ext/filters/client_channel/subchannel.cc index cc3457e1e96..99c7721e5e5 100644 --- a/src/core/ext/filters/client_channel/subchannel.cc +++ b/src/core/ext/filters/client_channel/subchannel.cc @@ -75,6 +75,9 @@ namespace grpc_core { +TraceFlag grpc_trace_subchannel(false, "subchannel"); +DebugOnlyTraceFlag grpc_trace_subchannel_refcount(false, "subchannel_refcount"); + // // ConnectedSubchannel // @@ -83,7 +86,7 @@ ConnectedSubchannel::ConnectedSubchannel( grpc_channel_stack* channel_stack, const grpc_channel_args* args, RefCountedPtr channelz_subchannel, intptr_t socket_uuid) - : ConnectedSubchannelInterface(&grpc_trace_stream_refcount), + : RefCounted(&grpc_trace_subchannel_refcount), channel_stack_(channel_stack), args_(grpc_channel_args_copy(args)), channelz_subchannel_(std::move(channelz_subchannel)), @@ -332,7 +335,7 @@ class Subchannel::ConnectedSubchannelStateWatcher { case GRPC_CHANNEL_TRANSIENT_FAILURE: case GRPC_CHANNEL_SHUTDOWN: { if (!c->disconnected_ && c->connected_subchannel_ != nullptr) { - if (grpc_trace_stream_refcount.enabled()) { + if (grpc_trace_subchannel.enabled()) { gpr_log(GPR_INFO, "Connected subchannel %p of subchannel %p has gone into " "%s. Attempting to reconnect.", @@ -375,12 +378,12 @@ class Subchannel::ConnectedSubchannelStateWatcher { // void Subchannel::ConnectivityStateWatcherList::AddWatcherLocked( - UniquePtr watcher) { + OrphanablePtr watcher) { watchers_.insert(MakePair(watcher.get(), std::move(watcher))); } void Subchannel::ConnectivityStateWatcherList::RemoveWatcherLocked( - ConnectivityStateWatcher* watcher) { + ConnectivityStateWatcherInterface* watcher) { watchers_.erase(watcher); } @@ -435,8 +438,9 @@ class Subchannel::HealthWatcherMap::HealthWatcher grpc_connectivity_state state() const { return state_; } - void AddWatcherLocked(grpc_connectivity_state initial_state, - UniquePtr watcher) { + void AddWatcherLocked( + grpc_connectivity_state initial_state, + OrphanablePtr watcher) { if (state_ != initial_state) { RefCountedPtr connected_subchannel; if (state_ == GRPC_CHANNEL_READY) { @@ -448,7 +452,7 @@ class Subchannel::HealthWatcherMap::HealthWatcher watcher_list_.AddWatcherLocked(std::move(watcher)); } - void RemoveWatcherLocked(ConnectivityStateWatcher* watcher) { + void RemoveWatcherLocked(ConnectivityStateWatcherInterface* watcher) { watcher_list_.RemoveWatcherLocked(watcher); } @@ -524,7 +528,7 @@ class Subchannel::HealthWatcherMap::HealthWatcher void Subchannel::HealthWatcherMap::AddWatcherLocked( Subchannel* subchannel, grpc_connectivity_state initial_state, UniquePtr health_check_service_name, - UniquePtr watcher) { + OrphanablePtr watcher) { // If the health check service name is not already present in the map, // add it. auto it = map_.find(health_check_service_name.get()); @@ -543,7 +547,8 @@ void Subchannel::HealthWatcherMap::AddWatcherLocked( } void Subchannel::HealthWatcherMap::RemoveWatcherLocked( - const char* health_check_service_name, ConnectivityStateWatcher* watcher) { + const char* health_check_service_name, + ConnectivityStateWatcherInterface* watcher) { auto it = map_.find(health_check_service_name); GPR_ASSERT(it != map_.end()); it->second->RemoveWatcherLocked(watcher); @@ -815,7 +820,7 @@ grpc_connectivity_state Subchannel::CheckConnectivityState( void Subchannel::WatchConnectivityState( grpc_connectivity_state initial_state, UniquePtr health_check_service_name, - UniquePtr watcher) { + OrphanablePtr watcher) { MutexLock lock(&mu_); grpc_pollset_set* interested_parties = watcher->interested_parties(); if (interested_parties != nullptr) { @@ -834,7 +839,8 @@ void Subchannel::WatchConnectivityState( } void Subchannel::CancelConnectivityStateWatch( - const char* health_check_service_name, ConnectivityStateWatcher* watcher) { + const char* health_check_service_name, + ConnectivityStateWatcherInterface* watcher) { MutexLock lock(&mu_); grpc_pollset_set* interested_parties = watcher->interested_parties(); if (interested_parties != nullptr) { @@ -1106,7 +1112,7 @@ gpr_atm Subchannel::RefMutate( gpr_atm old_val = barrier ? gpr_atm_full_fetch_add(&ref_pair_, delta) : gpr_atm_no_barrier_fetch_add(&ref_pair_, delta); #ifndef NDEBUG - if (grpc_trace_stream_refcount.enabled()) { + if (grpc_trace_subchannel_refcount.enabled()) { gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "SUBCHANNEL: %p %12s 0x%" PRIxPTR " -> 0x%" PRIxPTR " [%s]", this, purpose, old_val, old_val + delta, reason); diff --git a/src/core/ext/filters/client_channel/subchannel.h b/src/core/ext/filters/client_channel/subchannel.h index 2f05792b872..9e8de767839 100644 --- a/src/core/ext/filters/client_channel/subchannel.h +++ b/src/core/ext/filters/client_channel/subchannel.h @@ -23,7 +23,6 @@ #include "src/core/ext/filters/client_channel/client_channel_channelz.h" #include "src/core/ext/filters/client_channel/connector.h" -#include "src/core/ext/filters/client_channel/subchannel_interface.h" #include "src/core/ext/filters/client_channel/subchannel_pool_interface.h" #include "src/core/lib/backoff/backoff.h" #include "src/core/lib/channel/channel_stack.h" @@ -70,7 +69,7 @@ namespace grpc_core { class SubchannelCall; -class ConnectedSubchannel : public ConnectedSubchannelInterface { +class ConnectedSubchannel : public RefCounted { public: struct CallArgs { grpc_polling_entity* pollent; @@ -97,7 +96,7 @@ class ConnectedSubchannel : public ConnectedSubchannelInterface { grpc_error** error); grpc_channel_stack* channel_stack() const { return channel_stack_; } - const grpc_channel_args* args() const override { return args_; } + const grpc_channel_args* args() const { return args_; } channelz::SubchannelNode* channelz_subchannel() const { return channelz_subchannel_.get(); } @@ -176,10 +175,35 @@ class SubchannelCall { // A subchannel that knows how to connect to exactly one target address. It // provides a target for load balancing. +// +// Note that this is the "real" subchannel implementation, whose API is +// different from the SubchannelInterface that is exposed to LB policy +// implementations. The client channel provides an adaptor class +// (SubchannelWrapper) that "converts" between the two. class Subchannel { public: - typedef SubchannelInterface::ConnectivityStateWatcher - ConnectivityStateWatcher; + class ConnectivityStateWatcherInterface + : public InternallyRefCounted { + public: + virtual ~ConnectivityStateWatcherInterface() = default; + + // Will be invoked whenever the subchannel's connectivity state + // changes. There will be only one invocation of this method on a + // given watcher instance at any given time. + // + // When the state changes to READY, connected_subchannel will + // contain a ref to the connected subchannel. When it changes from + // READY to some other state, the implementation must release its + // ref to the connected subchannel. + virtual void OnConnectivityStateChange( + grpc_connectivity_state new_state, + RefCountedPtr connected_subchannel) // NOLINT + GRPC_ABSTRACT; + + virtual grpc_pollset_set* interested_parties() GRPC_ABSTRACT; + + GRPC_ABSTRACT_BASE_CLASS + }; // The ctor and dtor are not intended to use directly. Subchannel(SubchannelKey* key, grpc_connector* connector, @@ -206,6 +230,8 @@ class Subchannel { // Caller doesn't take ownership. const char* GetTargetAddress(); + const grpc_channel_args* channel_args() const { return args_; } + channelz::SubchannelNode* channelz_node(); // Returns the current connectivity state of the subchannel. @@ -225,14 +251,15 @@ class Subchannel { // changes. // The watcher will be destroyed either when the subchannel is // destroyed or when CancelConnectivityStateWatch() is called. - void WatchConnectivityState(grpc_connectivity_state initial_state, - UniquePtr health_check_service_name, - UniquePtr watcher); + void WatchConnectivityState( + grpc_connectivity_state initial_state, + UniquePtr health_check_service_name, + OrphanablePtr watcher); // Cancels a connectivity state watch. // If the watcher has already been destroyed, this is a no-op. void CancelConnectivityStateWatch(const char* health_check_service_name, - ConnectivityStateWatcher* watcher); + ConnectivityStateWatcherInterface* watcher); // Attempt to connect to the backend. Has no effect if already connected. void AttemptToConnect(); @@ -257,14 +284,15 @@ class Subchannel { grpc_resolved_address* addr); private: - // A linked list of ConnectivityStateWatchers that are monitoring the - // subchannel's state. + // A linked list of ConnectivityStateWatcherInterfaces that are monitoring + // the subchannel's state. class ConnectivityStateWatcherList { public: ~ConnectivityStateWatcherList() { Clear(); } - void AddWatcherLocked(UniquePtr watcher); - void RemoveWatcherLocked(ConnectivityStateWatcher* watcher); + void AddWatcherLocked( + OrphanablePtr watcher); + void RemoveWatcherLocked(ConnectivityStateWatcherInterface* watcher); // Notifies all watchers in the list about a change to state. void NotifyLocked(Subchannel* subchannel, grpc_connectivity_state state); @@ -276,12 +304,13 @@ class Subchannel { private: // TODO(roth): This could be a set instead of a map if we had a set // implementation. - Map> + Map> watchers_; }; - // A map that tracks ConnectivityStateWatchers using a particular health - // check service name. + // A map that tracks ConnectivityStateWatcherInterfaces using a particular + // health check service name. // // There is one entry in the map for each health check service name. // Entries exist only as long as there are watchers using the @@ -291,12 +320,12 @@ class Subchannel { // state READY. class HealthWatcherMap { public: - void AddWatcherLocked(Subchannel* subchannel, - grpc_connectivity_state initial_state, - UniquePtr health_check_service_name, - UniquePtr watcher); + void AddWatcherLocked( + Subchannel* subchannel, grpc_connectivity_state initial_state, + UniquePtr health_check_service_name, + OrphanablePtr watcher); void RemoveWatcherLocked(const char* health_check_service_name, - ConnectivityStateWatcher* watcher); + ConnectivityStateWatcherInterface* watcher); // Notifies the watcher when the subchannel's state changes. void NotifyLocked(grpc_connectivity_state state); diff --git a/src/core/ext/filters/client_channel/subchannel_interface.h b/src/core/ext/filters/client_channel/subchannel_interface.h index 0a471045f03..2e448dc5a64 100644 --- a/src/core/ext/filters/client_channel/subchannel_interface.h +++ b/src/core/ext/filters/client_channel/subchannel_interface.h @@ -21,42 +21,22 @@ #include -#include "src/core/lib/debug/trace.h" #include "src/core/lib/gprpp/ref_counted.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" namespace grpc_core { -// TODO(roth): In a subsequent PR, remove this from this API. -class ConnectedSubchannelInterface - : public RefCounted { - public: - virtual const grpc_channel_args* args() const GRPC_ABSTRACT; - - protected: - template - explicit ConnectedSubchannelInterface(TraceFlagT* trace_flag = nullptr) - : RefCounted(trace_flag) {} -}; - +// The interface for subchannels that is exposed to LB policy implementations. class SubchannelInterface : public RefCounted { public: - class ConnectivityStateWatcher { + class ConnectivityStateWatcherInterface { public: - virtual ~ConnectivityStateWatcher() = default; + virtual ~ConnectivityStateWatcherInterface() = default; // Will be invoked whenever the subchannel's connectivity state // changes. There will be only one invocation of this method on a // given watcher instance at any given time. - // - // When the state changes to READY, connected_subchannel will - // contain a ref to the connected subchannel. When it changes from - // READY to some other state, the implementation must release its - // ref to the connected subchannel. - virtual void OnConnectivityStateChange( - grpc_connectivity_state new_state, - RefCountedPtr - connected_subchannel) // NOLINT + virtual void OnConnectivityStateChange(grpc_connectivity_state new_state) GRPC_ABSTRACT; // TODO(roth): Remove this as soon as we move to EventManager-based @@ -66,12 +46,14 @@ class SubchannelInterface : public RefCounted { GRPC_ABSTRACT_BASE_CLASS }; + template + explicit SubchannelInterface(TraceFlagT* trace_flag = nullptr) + : RefCounted(trace_flag) {} + virtual ~SubchannelInterface() = default; // Returns the current connectivity state of the subchannel. - virtual grpc_connectivity_state CheckConnectivityState( - RefCountedPtr* connected_subchannel) - GRPC_ABSTRACT; + virtual grpc_connectivity_state CheckConnectivityState() GRPC_ABSTRACT; // Starts watching the subchannel's connectivity state. // The first callback to the watcher will be delivered when the @@ -86,21 +68,28 @@ class SubchannelInterface : public RefCounted { // the previous watcher using CancelConnectivityStateWatch(). virtual void WatchConnectivityState( grpc_connectivity_state initial_state, - UniquePtr watcher) GRPC_ABSTRACT; + UniquePtr watcher) GRPC_ABSTRACT; // Cancels a connectivity state watch. // If the watcher has already been destroyed, this is a no-op. - virtual void CancelConnectivityStateWatch(ConnectivityStateWatcher* watcher) - GRPC_ABSTRACT; + virtual void CancelConnectivityStateWatch( + ConnectivityStateWatcherInterface* watcher) GRPC_ABSTRACT; // Attempt to connect to the backend. Has no effect if already connected. + // If the subchannel is currently in backoff delay due to a previously + // failed attempt, the new connection attempt will not start until the + // backoff delay has elapsed. virtual void AttemptToConnect() GRPC_ABSTRACT; - // TODO(roth): These methods should be removed from this interface to - // bettter hide grpc-specific functionality from the LB policy API. - virtual channelz::SubchannelNode* channelz_node() GRPC_ABSTRACT; + // Resets the subchannel's connection backoff state. If AttemptToConnect() + // has been called since the subchannel entered TRANSIENT_FAILURE state, + // starts a new connection attempt immediately; otherwise, a new connection + // attempt will be started as soon as AttemptToConnect() is called. virtual void ResetBackoff() GRPC_ABSTRACT; + // TODO(roth): Need a better non-grpc-specific abstraction here. + virtual const grpc_channel_args* channel_args() GRPC_ABSTRACT; + GRPC_ABSTRACT_BASE_CLASS }; diff --git a/src/core/ext/transport/chttp2/transport/frame_data.cc b/src/core/ext/transport/chttp2/transport/frame_data.cc index 3734c0150b7..74c305b820f 100644 --- a/src/core/ext/transport/chttp2/transport/frame_data.cc +++ b/src/core/ext/transport/chttp2/transport/frame_data.cc @@ -109,7 +109,6 @@ grpc_error* grpc_deframe_unprocessed_incoming_frames( end = GRPC_SLICE_END_PTR(*slice); cur = beg; uint32_t message_flags; - char* msg; if (cur == end) { grpc_slice_buffer_remove_first(slices); @@ -132,15 +131,16 @@ grpc_error* grpc_deframe_unprocessed_incoming_frames( p->is_frame_compressed = true; /* GPR_TRUE */ break; default: + char* msg; gpr_asprintf(&msg, "Bad GRPC frame type 0x%02x", p->frame_type); p->error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); p->error = grpc_error_set_int(p->error, GRPC_ERROR_INT_STREAM_ID, static_cast(s->id)); gpr_free(msg); - msg = grpc_dump_slice(*slice, GPR_DUMP_HEX | GPR_DUMP_ASCII); - p->error = grpc_error_set_str(p->error, GRPC_ERROR_STR_RAW_BYTES, - grpc_slice_from_copied_string(msg)); - gpr_free(msg); + p->error = + grpc_error_set_str(p->error, GRPC_ERROR_STR_RAW_BYTES, + grpc_dump_slice_to_slice( + *slice, GPR_DUMP_HEX | GPR_DUMP_ASCII)); p->error = grpc_error_set_int(p->error, GRPC_ERROR_INT_OFFSET, cur - beg); p->state = GRPC_CHTTP2_DATA_ERROR; diff --git a/src/core/ext/transport/chttp2/transport/frame_rst_stream.cc b/src/core/ext/transport/chttp2/transport/frame_rst_stream.cc index ccde36cbc48..cda09c3dea1 100644 --- a/src/core/ext/transport/chttp2/transport/frame_rst_stream.cc +++ b/src/core/ext/transport/chttp2/transport/frame_rst_stream.cc @@ -26,6 +26,7 @@ #include #include "src/core/ext/transport/chttp2/transport/frame.h" +#include "src/core/lib/gprpp/memory.h" #include "src/core/lib/transport/http2_errors.h" grpc_slice grpc_chttp2_rst_stream_create(uint32_t id, uint32_t code, @@ -102,9 +103,9 @@ grpc_error* grpc_chttp2_rst_stream_parser_parse(void* parser, error = grpc_error_set_int( grpc_error_set_str(GRPC_ERROR_CREATE_FROM_STATIC_STRING("RST_STREAM"), GRPC_ERROR_STR_GRPC_MESSAGE, - grpc_slice_from_copied_string(message)), + grpc_slice_from_moved_string( + grpc_core::UniquePtr(message))), GRPC_ERROR_INT_HTTP2_ERROR, static_cast(reason)); - gpr_free(message); } grpc_chttp2_mark_stream_closed(t, s, true, true, error); } diff --git a/src/core/lib/channel/channelz.cc b/src/core/lib/channel/channelz.cc index 0eed9a59fef..4b130372e46 100644 --- a/src/core/lib/channel/channelz.cc +++ b/src/core/lib/channel/channelz.cc @@ -40,12 +40,51 @@ #include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/surface/channel.h" #include "src/core/lib/surface/server.h" +#include "src/core/lib/transport/connectivity_state.h" #include "src/core/lib/transport/error_utils.h" #include "src/core/lib/uri/uri_parser.h" namespace grpc_core { namespace channelz { +// +// channel arg code +// + +namespace { + +void* parent_uuid_copy(void* p) { return p; } +void parent_uuid_destroy(void* p) {} +int parent_uuid_cmp(void* p1, void* p2) { return GPR_ICMP(p1, p2); } +const grpc_arg_pointer_vtable parent_uuid_vtable = { + parent_uuid_copy, parent_uuid_destroy, parent_uuid_cmp}; + +} // namespace + +grpc_arg MakeParentUuidArg(intptr_t parent_uuid) { + // We would ideally like to store the uuid in an integer argument. + // Unfortunately, that won't work, because intptr_t (the type used for + // uuids) doesn't fit in an int (the type used for integer args). + // So instead, we use a hack to store it as a pointer, because + // intptr_t should be the same size as void*. + static_assert(sizeof(intptr_t) <= sizeof(void*), + "can't fit intptr_t inside of void*"); + return grpc_channel_arg_pointer_create( + const_cast(GRPC_ARG_CHANNELZ_PARENT_UUID), + reinterpret_cast(parent_uuid), &parent_uuid_vtable); +} + +intptr_t GetParentUuidFromArgs(const grpc_channel_args& args) { + const grpc_arg* arg = + grpc_channel_args_find(&args, GRPC_ARG_CHANNELZ_PARENT_UUID); + if (arg == nullptr || arg->type != GRPC_ARG_POINTER) return 0; + return reinterpret_cast(arg->value.pointer.p); +} + +// +// BaseNode +// + BaseNode::BaseNode(EntityType type) : type_(type), uuid_(-1) { // The registry will set uuid_ under its lock. ChannelzRegistry::Register(this); @@ -61,6 +100,10 @@ char* BaseNode::RenderJsonString() { return json_str; } +// +// CallCountingHelper +// + CallCountingHelper::CallCountingHelper() { num_cores_ = GPR_MAX(1, gpr_cpu_num_cores()); per_cpu_counter_data_storage_ = static_cast( @@ -137,15 +180,17 @@ void CallCountingHelper::PopulateCallCounts(grpc_json* json) { } } -ChannelNode::ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes, - bool is_top_level_channel) - : BaseNode(is_top_level_channel ? EntityType::kTopLevelChannel - : EntityType::kInternalChannel), - channel_(channel), - target_(UniquePtr(grpc_channel_get_target(channel_))), - trace_(channel_tracer_max_nodes) {} +// +// ChannelNode +// -ChannelNode::~ChannelNode() {} +ChannelNode::ChannelNode(UniquePtr target, + size_t channel_tracer_max_nodes, intptr_t parent_uuid) + : BaseNode(parent_uuid == 0 ? EntityType::kTopLevelChannel + : EntityType::kInternalChannel), + target_(std::move(target)), + trace_(channel_tracer_max_nodes), + parent_uuid_(parent_uuid) {} grpc_json* ChannelNode::RenderJson() { // We need to track these three json objects to build our object @@ -167,9 +212,19 @@ grpc_json* ChannelNode::RenderJson() { GRPC_JSON_OBJECT, false); json = data; json_iterator = nullptr; - // template method. Child classes may override this to add their specific - // functionality. - PopulateConnectivityState(json); + // connectivity state + // If low-order bit is on, then the field is set. + int state_field = connectivity_state_.Load(MemoryOrder::RELAXED); + if ((state_field & 1) != 0) { + grpc_connectivity_state state = + static_cast(state_field >> 1); + json = grpc_json_create_child(nullptr, json, "state", nullptr, + GRPC_JSON_OBJECT, false); + grpc_json_create_child(nullptr, json, "state", + grpc_connectivity_state_name(state), + GRPC_JSON_STRING, false); + json = data; + } // populate the target. GPR_ASSERT(target_.get() != nullptr); grpc_json_create_child(nullptr, json, "target", target_.get(), @@ -189,13 +244,64 @@ grpc_json* ChannelNode::RenderJson() { return top_level_json; } -RefCountedPtr ChannelNode::MakeChannelNode( - grpc_channel* channel, size_t channel_tracer_max_nodes, - bool is_top_level_channel) { - return MakeRefCounted( - channel, channel_tracer_max_nodes, is_top_level_channel); +void ChannelNode::PopulateChildRefs(grpc_json* json) { + MutexLock lock(&child_mu_); + grpc_json* json_iterator = nullptr; + if (!child_subchannels_.empty()) { + grpc_json* array_parent = grpc_json_create_child( + nullptr, json, "subchannelRef", nullptr, GRPC_JSON_ARRAY, false); + for (const auto& p : child_subchannels_) { + json_iterator = + grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr, + GRPC_JSON_OBJECT, false); + grpc_json_add_number_string_child(json_iterator, nullptr, "subchannelId", + p.first); + } + } + if (!child_channels_.empty()) { + grpc_json* array_parent = grpc_json_create_child( + nullptr, json, "channelRef", nullptr, GRPC_JSON_ARRAY, false); + json_iterator = nullptr; + for (const auto& p : child_channels_) { + json_iterator = + grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr, + GRPC_JSON_OBJECT, false); + grpc_json_add_number_string_child(json_iterator, nullptr, "channelId", + p.first); + } + } +} + +void ChannelNode::SetConnectivityState(grpc_connectivity_state state) { + // Store with low-order bit set to indicate that the field is set. + int state_field = (state << 1) + 1; + connectivity_state_.Store(state_field, MemoryOrder::RELAXED); +} + +void ChannelNode::AddChildChannel(intptr_t child_uuid) { + MutexLock lock(&child_mu_); + child_channels_.insert(MakePair(child_uuid, true)); +} + +void ChannelNode::RemoveChildChannel(intptr_t child_uuid) { + MutexLock lock(&child_mu_); + child_channels_.erase(child_uuid); } +void ChannelNode::AddChildSubchannel(intptr_t child_uuid) { + MutexLock lock(&child_mu_); + child_subchannels_.insert(MakePair(child_uuid, true)); +} + +void ChannelNode::RemoveChildSubchannel(intptr_t child_uuid) { + MutexLock lock(&child_mu_); + child_subchannels_.erase(child_uuid); +} + +// +// ServerNode +// + ServerNode::ServerNode(grpc_server* server, size_t channel_tracer_max_nodes) : BaseNode(EntityType::kServer), server_(server), @@ -281,8 +387,14 @@ grpc_json* ServerNode::RenderJson() { return top_level_json; } -static void PopulateSocketAddressJson(grpc_json* json, const char* name, - const char* addr_str) { +// +// SocketNode +// + +namespace { + +void PopulateSocketAddressJson(grpc_json* json, const char* name, + const char* addr_str) { if (addr_str == nullptr) return; grpc_json* json_iterator = nullptr; json_iterator = grpc_json_create_child(json_iterator, json, name, nullptr, @@ -312,7 +424,6 @@ static void PopulateSocketAddressJson(grpc_json* json, const char* name, b64_host, GRPC_JSON_STRING, true); gpr_free(host); gpr_free(port); - } else if (uri != nullptr && strcmp(uri->scheme, "unix") == 0) { json_iterator = grpc_json_create_child(json_iterator, json, "uds_address", nullptr, GRPC_JSON_OBJECT, false); @@ -332,6 +443,8 @@ static void PopulateSocketAddressJson(grpc_json* json, const char* name, grpc_uri_destroy(uri); } +} // namespace + SocketNode::SocketNode(UniquePtr local, UniquePtr remote) : BaseNode(EntityType::kSocket), local_(std::move(local)), @@ -448,6 +561,10 @@ grpc_json* SocketNode::RenderJson() { return top_level_json; } +// +// ListenSocketNode +// + ListenSocketNode::ListenSocketNode(UniquePtr local_addr) : BaseNode(EntityType::kSocket), local_addr_(std::move(local_addr)) {} diff --git a/src/core/lib/channel/channelz.h b/src/core/lib/channel/channelz.h index e543cda1c2b..f8acb531e8a 100644 --- a/src/core/lib/channel/channelz.h +++ b/src/core/lib/channel/channelz.h @@ -26,19 +26,19 @@ #include "src/core/lib/channel/channel_trace.h" #include "src/core/lib/gprpp/inlined_vector.h" #include "src/core/lib/gprpp/manual_constructor.h" +#include "src/core/lib/gprpp/map.h" #include "src/core/lib/gprpp/ref_counted.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" +#include "src/core/lib/gprpp/sync.h" #include "src/core/lib/iomgr/error.h" #include "src/core/lib/iomgr/exec_ctx.h" #include "src/core/lib/json/json.h" -// Channel arg key for client channel factory. -#define GRPC_ARG_CHANNELZ_CHANNEL_NODE_CREATION_FUNC \ - "grpc.channelz_channel_node_creation_func" +// Channel arg key for channelz node. +#define GRPC_ARG_CHANNELZ_CHANNEL_NODE "grpc.channelz_channel_node" -// Channel arg key to signal that the channel is an internal channel. -#define GRPC_ARG_CHANNELZ_CHANNEL_IS_INTERNAL_CHANNEL \ - "grpc.channelz_channel_is_internal_channel" +// Channel arg key to encode the channelz uuid of the channel's parent. +#define GRPC_ARG_CHANNELZ_PARENT_UUID "grpc.channelz_parent_uuid" /** This is the default value for whether or not to enable channelz. If * GRPC_ARG_ENABLE_CHANNELZ is set, it will override this default value. */ @@ -54,6 +54,10 @@ namespace grpc_core { namespace channelz { +// Helpers for getting and setting GRPC_ARG_CHANNELZ_PARENT_UUID. +grpc_arg MakeParentUuidArg(intptr_t parent_uuid); +intptr_t GetParentUuidFromArgs(const grpc_channel_args& args); + // TODO(ncteisen), this only contains the uuids of the children for now, // since that is all that is strictly needed. In a future enhancement we will // add human readable names as in the channelz.proto @@ -147,38 +151,13 @@ class CallCountingHelper { // Handles channelz bookkeeping for channels class ChannelNode : public BaseNode { public: - static RefCountedPtr MakeChannelNode( - grpc_channel* channel, size_t channel_tracer_max_nodes, - bool is_top_level_channel); + ChannelNode(UniquePtr target, size_t channel_tracer_max_nodes, + intptr_t parent_uuid); - ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes, - bool is_top_level_channel); - ~ChannelNode() override; + intptr_t parent_uuid() const { return parent_uuid_; } grpc_json* RenderJson() override; - // template methods. RenderJSON uses these methods to render its JSON - // representation. These are virtual so that children classes may provide - // their specific mechanism for populating these parts of the channelz - // object. - // - // ChannelNode does not have a notion of connectivity state or child refs, - // so it leaves these implementations blank. - // - // This is utilizing the template method design pattern. - // - // TODO(ncteisen): remove these template methods in favor of manual traversal - // and mutation of the grpc_json object. - virtual void PopulateConnectivityState(grpc_json* json) {} - virtual void PopulateChildRefs(grpc_json* json) {} - - void MarkChannelDestroyed() { - GPR_ASSERT(channel_ != nullptr); - channel_ = nullptr; - } - - bool ChannelIsDestroyed() { return channel_ == nullptr; } - // proxy methods to composed classes. void AddTraceEvent(ChannelTrace::Severity severity, const grpc_slice& data) { trace_.AddTraceEvent(severity, data); @@ -193,13 +172,35 @@ class ChannelNode : public BaseNode { void RecordCallFailed() { call_counter_.RecordCallFailed(); } void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); } + void SetConnectivityState(grpc_connectivity_state state); + + void AddChildChannel(intptr_t child_uuid); + void RemoveChildChannel(intptr_t child_uuid); + + void AddChildSubchannel(intptr_t child_uuid); + void RemoveChildSubchannel(intptr_t child_uuid); + private: + void PopulateChildRefs(grpc_json* json); + // to allow the channel trace test to access trace_. friend class testing::ChannelNodePeer; - grpc_channel* channel_ = nullptr; + UniquePtr target_; CallCountingHelper call_counter_; ChannelTrace trace_; + const intptr_t parent_uuid_; + + // Least significant bit indicates whether the value is set. Remaining + // bits are a grpc_connectivity_state value. + Atomic connectivity_state_{0}; + + Mutex child_mu_; // Guards child maps below. + // TODO(roth): We don't actually use the values here, only the keys, so + // these should be sets instead of maps, but we don't currently have a set + // implementation. Change this if/when we have one. + Map child_channels_; + Map child_subchannels_; }; // Handles channelz bookkeeping for servers @@ -285,11 +286,6 @@ class ListenSocketNode : public BaseNode { UniquePtr local_addr_; }; -// Creation functions - -typedef RefCountedPtr (*ChannelNodeCreationFunc)(grpc_channel*, - size_t, bool); - } // namespace channelz } // namespace grpc_core diff --git a/src/core/lib/channel/channelz_registry.cc b/src/core/lib/channel/channelz_registry.cc index 0c033a14c60..553e1fe97b5 100644 --- a/src/core/lib/channel/channelz_registry.cc +++ b/src/core/lib/channel/channelz_registry.cc @@ -18,6 +18,9 @@ #include +#include +#include + #include "src/core/lib/channel/channel_trace.h" #include "src/core/lib/channel/channelz.h" #include "src/core/lib/channel/channelz_registry.h" @@ -29,8 +32,6 @@ #include #include -#include - namespace grpc_core { namespace channelz { namespace { @@ -51,70 +52,17 @@ ChannelzRegistry* ChannelzRegistry::Default() { return g_channelz_registry; } -ChannelzRegistry::ChannelzRegistry() { gpr_mu_init(&mu_); } - -ChannelzRegistry::~ChannelzRegistry() { gpr_mu_destroy(&mu_); } - void ChannelzRegistry::InternalRegister(BaseNode* node) { MutexLock lock(&mu_); - entities_.push_back(node); node->uuid_ = ++uuid_generator_; -} - -void ChannelzRegistry::MaybePerformCompactionLocked() { - constexpr double kEmptinessTheshold = 1. / 3; - double emptiness_ratio = - double(num_empty_slots_) / double(entities_.capacity()); - if (emptiness_ratio > kEmptinessTheshold) { - int front = 0; - for (size_t i = 0; i < entities_.size(); ++i) { - if (entities_[i] != nullptr) { - entities_[front++] = entities_[i]; - } - } - for (int i = 0; i < num_empty_slots_; ++i) { - entities_.pop_back(); - } - num_empty_slots_ = 0; - } -} - -int ChannelzRegistry::FindByUuidLocked(intptr_t target_uuid, - bool direct_hit_needed) { - int left = 0; - int right = int(entities_.size() - 1); - while (left <= right) { - int true_middle = left + (right - left) / 2; - int first_non_null = true_middle; - while (first_non_null < right && entities_[first_non_null] == nullptr) { - first_non_null++; - } - if (entities_[first_non_null] == nullptr) { - right = true_middle - 1; - continue; - } - intptr_t uuid = entities_[first_non_null]->uuid(); - if (uuid == target_uuid) { - return int(first_non_null); - } - if (uuid < target_uuid) { - left = first_non_null + 1; - } else { - right = true_middle - 1; - } - } - return direct_hit_needed ? -1 : left; + node_map_[node->uuid_] = node; } void ChannelzRegistry::InternalUnregister(intptr_t uuid) { GPR_ASSERT(uuid >= 1); MutexLock lock(&mu_); GPR_ASSERT(uuid <= uuid_generator_); - int idx = FindByUuidLocked(uuid, true); - GPR_ASSERT(idx >= 0); - entities_[idx] = nullptr; - num_empty_slots_++; - MaybePerformCompactionLocked(); + node_map_.erase(uuid); } RefCountedPtr ChannelzRegistry::InternalGet(intptr_t uuid) { @@ -122,12 +70,13 @@ RefCountedPtr ChannelzRegistry::InternalGet(intptr_t uuid) { if (uuid < 1 || uuid > uuid_generator_) { return nullptr; } - int idx = FindByUuidLocked(uuid, true); - if (idx < 0 || entities_[idx] == nullptr) return nullptr; + auto it = node_map_.find(uuid); + if (it == node_map_.end()) return nullptr; // Found node. Return only if its refcount is not zero (i.e., when we // know that there is no other thread about to destroy it). - if (!entities_[idx]->RefIfNonZero()) return nullptr; - return RefCountedPtr(entities_[idx]); + BaseNode* node = it->second; + if (!node->RefIfNonZero()) return nullptr; + return RefCountedPtr(node); } char* ChannelzRegistry::InternalGetTopChannels(intptr_t start_channel_id) { @@ -138,13 +87,11 @@ char* ChannelzRegistry::InternalGetTopChannels(intptr_t start_channel_id) { RefCountedPtr node_after_pagination_limit; { MutexLock lock(&mu_); - const int start_idx = GPR_MAX(FindByUuidLocked(start_channel_id, false), 0); - for (size_t i = start_idx; i < entities_.size(); ++i) { - if (entities_[i] != nullptr && - entities_[i]->type() == - grpc_core::channelz::BaseNode::EntityType::kTopLevelChannel && - entities_[i]->uuid() >= start_channel_id && - entities_[i]->RefIfNonZero()) { + for (auto it = node_map_.lower_bound(start_channel_id); + it != node_map_.end(); ++it) { + BaseNode* node = it->second; + if (node->type() == BaseNode::EntityType::kTopLevelChannel && + node->RefIfNonZero()) { // Check if we are over pagination limit to determine if we need to set // the "end" element. If we don't go through this block, we know that // when the loop terminates, we have <= to kPaginationLimit. @@ -152,10 +99,10 @@ char* ChannelzRegistry::InternalGetTopChannels(intptr_t start_channel_id) { // refcount, we need to decrease it, but we can't unref while // holding the lock, because this may lead to a deadlock. if (top_level_channels.size() == kPaginationLimit) { - node_after_pagination_limit.reset(entities_[i]); + node_after_pagination_limit.reset(node); break; } - top_level_channels.emplace_back(entities_[i]); + top_level_channels.emplace_back(node); } } } @@ -186,13 +133,11 @@ char* ChannelzRegistry::InternalGetServers(intptr_t start_server_id) { RefCountedPtr node_after_pagination_limit; { MutexLock lock(&mu_); - const int start_idx = GPR_MAX(FindByUuidLocked(start_server_id, false), 0); - for (size_t i = start_idx; i < entities_.size(); ++i) { - if (entities_[i] != nullptr && - entities_[i]->type() == - grpc_core::channelz::BaseNode::EntityType::kServer && - entities_[i]->uuid() >= start_server_id && - entities_[i]->RefIfNonZero()) { + for (auto it = node_map_.lower_bound(start_server_id); + it != node_map_.end(); ++it) { + BaseNode* node = it->second; + if (node->type() == BaseNode::EntityType::kServer && + node->RefIfNonZero()) { // Check if we are over pagination limit to determine if we need to set // the "end" element. If we don't go through this block, we know that // when the loop terminates, we have <= to kPaginationLimit. @@ -200,10 +145,10 @@ char* ChannelzRegistry::InternalGetServers(intptr_t start_server_id) { // refcount, we need to decrease it, but we can't unref while // holding the lock, because this may lead to a deadlock. if (servers.size() == kPaginationLimit) { - node_after_pagination_limit.reset(entities_[i]); + node_after_pagination_limit.reset(node); break; } - servers.emplace_back(entities_[i]); + servers.emplace_back(node); } } } @@ -230,9 +175,10 @@ void ChannelzRegistry::InternalLogAllEntities() { InlinedVector, 10> nodes; { MutexLock lock(&mu_); - for (size_t i = 0; i < entities_.size(); ++i) { - if (entities_[i] != nullptr && entities_[i]->RefIfNonZero()) { - nodes.emplace_back(entities_[i]); + for (auto& p : node_map_) { + BaseNode* node = p.second; + if (node->RefIfNonZero()) { + nodes.emplace_back(node); } } } diff --git a/src/core/lib/channel/channelz_registry.h b/src/core/lib/channel/channelz_registry.h index aa87b64e5b2..e04d7c44888 100644 --- a/src/core/lib/channel/channelz_registry.h +++ b/src/core/lib/channel/channelz_registry.h @@ -21,19 +21,16 @@ #include +#include + #include "src/core/lib/channel/channel_trace.h" #include "src/core/lib/channel/channelz.h" -#include "src/core/lib/gprpp/inlined_vector.h" - -#include +#include "src/core/lib/gprpp/map.h" +#include "src/core/lib/gprpp/sync.h" namespace grpc_core { namespace channelz { -namespace testing { -class ChannelzRegistryPeer; -} - // singleton registry object to track all objects that are needed to support // channelz bookkeeping. All objects share globally distributed uuids. class ChannelzRegistry { @@ -69,13 +66,6 @@ class ChannelzRegistry { static void LogAllEntities() { Default()->InternalLogAllEntities(); } private: - GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW - GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE - friend class testing::ChannelzRegistryPeer; - - ChannelzRegistry(); - ~ChannelzRegistry(); - // Returned the singleton instance of ChannelzRegistry; static ChannelzRegistry* Default(); @@ -93,22 +83,12 @@ class ChannelzRegistry { char* InternalGetTopChannels(intptr_t start_channel_id); char* InternalGetServers(intptr_t start_server_id); - // If entities_ has over a certain threshold of empty slots, it will - // compact the vector and move all used slots to the front. - void MaybePerformCompactionLocked(); - - // Performs binary search on entities_ to find the index with that uuid. - // If direct_hit_needed, then will return -1 in case of absence. - // Else, will return idx of the first uuid higher than the target. - int FindByUuidLocked(intptr_t uuid, bool direct_hit_needed); - void InternalLogAllEntities(); // protects members - gpr_mu mu_; - InlinedVector entities_; + Mutex mu_; + Map node_map_; intptr_t uuid_generator_ = 0; - int num_empty_slots_ = 0; }; } // namespace channelz diff --git a/src/core/lib/gpr/string.cc b/src/core/lib/gpr/string.cc index 31d5fdee5be..a39f56ef926 100644 --- a/src/core/lib/gpr/string.cc +++ b/src/core/lib/gpr/string.cc @@ -126,7 +126,8 @@ static void asciidump(dump_out* out, const char* buf, size_t len) { } } -char* gpr_dump(const char* buf, size_t len, uint32_t flags) { +char* gpr_dump_return_len(const char* buf, size_t len, uint32_t flags, + size_t* out_len) { dump_out out = dump_out_create(); if (flags & GPR_DUMP_HEX) { hexdump(&out, buf, len); @@ -135,9 +136,15 @@ char* gpr_dump(const char* buf, size_t len, uint32_t flags) { asciidump(&out, buf, len); } dump_out_append(&out, 0); + *out_len = out.length; return out.data; } +char* gpr_dump(const char* buf, size_t len, uint32_t flags) { + size_t unused; + return gpr_dump_return_len(buf, len, flags, &unused); +} + int gpr_parse_bytes_to_uint32(const char* buf, size_t len, uint32_t* result) { uint32_t out = 0; uint32_t new_val; diff --git a/src/core/lib/gpr/string.h b/src/core/lib/gpr/string.h index c5efcec3bb1..bf59db7abfe 100644 --- a/src/core/lib/gpr/string.h +++ b/src/core/lib/gpr/string.h @@ -32,9 +32,14 @@ #define GPR_DUMP_HEX 0x00000001 #define GPR_DUMP_ASCII 0x00000002 -/* Converts array buf, of length len, into a C string according to the flags. +/* Converts array buf, of length len, into a C string according to the flags. Result should be freed with gpr_free() */ char* gpr_dump(const char* buf, size_t len, uint32_t flags); +/* Converts array buf, of length len, into a C string according to the flags. + The length of the returned buffer is stored in out_len. + Result should be freed with gpr_free() */ +char* gpr_dump_return_len(const char* buf, size_t len, uint32_t flags, + size_t* out_len); /* Parses an array of bytes into an integer (base 10). Returns 1 on success, 0 on failure. */ diff --git a/src/core/lib/gprpp/inlined_vector.h b/src/core/lib/gprpp/inlined_vector.h index 66dc751a567..ffc37387ec3 100644 --- a/src/core/lib/gprpp/inlined_vector.h +++ b/src/core/lib/gprpp/inlined_vector.h @@ -97,6 +97,14 @@ class InlinedVector { return data()[offset]; } + bool operator==(const InlinedVector& other) const { + if (size_ != other.size_) return false; + for (size_t i = 0; i < size_; ++i) { + if (data()[i] != other.data()[i]) return false; + } + return true; + } + void reserve(size_t capacity) { if (capacity > capacity_) { T* new_dynamic = static_cast(gpr_malloc(sizeof(T) * capacity)); diff --git a/src/core/lib/gprpp/map.h b/src/core/lib/gprpp/map.h index 525c25347f4..566691df580 100644 --- a/src/core/lib/gprpp/map.h +++ b/src/core/lib/gprpp/map.h @@ -22,11 +22,15 @@ #include #include + +#include #include #include + #include "src/core/lib/gpr/useful.h" #include "src/core/lib/gprpp/memory.h" #include "src/core/lib/gprpp/pair.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" namespace grpc_core { struct StringLess { @@ -38,6 +42,13 @@ struct StringLess { } }; +template +struct RefCountedPtrLess { + bool operator()(const RefCountedPtr& p1, const RefCountedPtr& p2) { + return p1.get() < p2.get(); + } +}; + namespace testing { class MapTest; } @@ -52,8 +63,28 @@ class Map { typedef Compare key_compare; class iterator; + Map() {} ~Map() { clear(); } + // Copying not currently supported. + Map(const Map& other) = delete; + + // Move support. + Map(Map&& other) : root_(other.root_), size_(other.size_) { + other.root_ = nullptr; + other.size_ = 0; + } + Map& operator=(Map&& other) { + if (this != &other) { + clear(); + root_ = other.root_; + size_ = other.size_; + other.root_ = nullptr; + other.size_ = 0; + } + return *this; + } + T& operator[](key_type&& key); T& operator[](const key_type& key); iterator find(const key_type& k); @@ -88,6 +119,13 @@ class Map { iterator end() { return iterator(this, nullptr); } + iterator lower_bound(const Key& k) { + key_compare compare; + return std::find_if(begin(), end(), [&k, &compare](const value_type& v) { + return !compare(v.first, k); + }); + } + private: friend class testing::MapTest; struct Entry { diff --git a/src/core/lib/gprpp/memory.h b/src/core/lib/gprpp/memory.h index b4b63ae771a..70ad430c51d 100644 --- a/src/core/lib/gprpp/memory.h +++ b/src/core/lib/gprpp/memory.h @@ -29,12 +29,12 @@ // Add this to a class that want to use Delete(), but has a private or // protected destructor. -#define GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE \ +#define GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE \ template \ friend void grpc_core::Delete(T*); // Add this to a class that want to use New(), but has a private or // protected constructor. -#define GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW \ +#define GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW \ template \ friend T* grpc_core::New(Args&&...); diff --git a/src/core/lib/gprpp/orphanable.h b/src/core/lib/gprpp/orphanable.h index 2e467e49060..82350a19a2c 100644 --- a/src/core/lib/gprpp/orphanable.h +++ b/src/core/lib/gprpp/orphanable.h @@ -84,7 +84,7 @@ class InternallyRefCounted : public Orphanable { GRPC_ABSTRACT_BASE_CLASS protected: - GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE + GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE // Allow RefCountedPtr<> to access Unref() and IncrementRefCount(). template diff --git a/src/core/lib/gprpp/ref_counted.h b/src/core/lib/gprpp/ref_counted.h index 392c12a3bd1..cab1aaaaab1 100644 --- a/src/core/lib/gprpp/ref_counted.h +++ b/src/core/lib/gprpp/ref_counted.h @@ -44,7 +44,7 @@ class PolymorphicRefCount { GRPC_ABSTRACT_BASE_CLASS protected: - GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE + GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE virtual ~PolymorphicRefCount() = default; }; @@ -57,7 +57,7 @@ class NonPolymorphicRefCount { GRPC_ABSTRACT_BASE_CLASS protected: - GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE + GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE ~NonPolymorphicRefCount() = default; }; @@ -233,7 +233,7 @@ class RefCounted : public Impl { GRPC_ABSTRACT_BASE_CLASS protected: - GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE + GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE // TraceFlagT is defined to accept both DebugOnlyTraceFlag and TraceFlag. // Note: RefCount tracing is only enabled on debug builds, even when a diff --git a/src/core/lib/http/httpcli.cc b/src/core/lib/http/httpcli.cc index 8a8da8b1604..93bb1432b16 100644 --- a/src/core/lib/http/httpcli.cc +++ b/src/core/lib/http/httpcli.cc @@ -28,6 +28,7 @@ #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/string.h" +#include "src/core/lib/gprpp/memory.h" #include "src/core/lib/http/format_request.h" #include "src/core/lib/http/parser.h" #include "src/core/lib/iomgr/endpoint.h" @@ -112,12 +113,11 @@ static void append_error(internal_request* req, grpc_error* error) { GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed HTTP/1 client request"); } grpc_resolved_address* addr = &req->addresses->addrs[req->next_address - 1]; - char* addr_text = grpc_sockaddr_to_uri(addr); + grpc_core::UniquePtr addr_text(grpc_sockaddr_to_uri(addr)); req->overall_error = grpc_error_add_child( req->overall_error, grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS, - grpc_slice_from_copied_string(addr_text))); - gpr_free(addr_text); + grpc_slice_from_moved_string(std::move(addr_text)))); } static void do_read(internal_request* req) { diff --git a/src/core/lib/iomgr/buffer_list.h b/src/core/lib/iomgr/buffer_list.h index 8bb271867c2..755ce02ba95 100644 --- a/src/core/lib/iomgr/buffer_list.h +++ b/src/core/lib/iomgr/buffer_list.h @@ -133,7 +133,7 @@ class TracedBuffer { grpc_error* shutdown_err); private: - GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW + GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW TracedBuffer(uint32_t seq_no, void* arg) : seq_no_(seq_no), arg_(arg), next_(nullptr) {} diff --git a/src/core/lib/iomgr/call_combiner.cc b/src/core/lib/iomgr/call_combiner.cc index 6a4e85de4df..6530d1c6ce6 100644 --- a/src/core/lib/iomgr/call_combiner.cc +++ b/src/core/lib/iomgr/call_combiner.cc @@ -28,7 +28,7 @@ namespace grpc_core { -TraceFlag grpc_call_combiner_trace(false, "call_combiner"); +DebugOnlyTraceFlag grpc_call_combiner_trace(false, "call_combiner"); namespace { diff --git a/src/core/lib/iomgr/call_combiner.h b/src/core/lib/iomgr/call_combiner.h index a10b437c15a..b56966f4196 100644 --- a/src/core/lib/iomgr/call_combiner.h +++ b/src/core/lib/iomgr/call_combiner.h @@ -43,7 +43,7 @@ namespace grpc_core { -extern TraceFlag grpc_call_combiner_trace; +extern DebugOnlyTraceFlag grpc_call_combiner_trace; class CallCombiner { public: diff --git a/src/core/lib/iomgr/cfstream_handle.cc b/src/core/lib/iomgr/cfstream_handle.cc index 2fda160f68a..8d01386a8f9 100644 --- a/src/core/lib/iomgr/cfstream_handle.cc +++ b/src/core/lib/iomgr/cfstream_handle.cc @@ -18,6 +18,7 @@ #include +#include "src/core/lib/gprpp/memory.h" #include "src/core/lib/iomgr/port.h" #ifdef GRPC_CFSTREAM @@ -47,7 +48,7 @@ void CFStreamHandle::Release(void* info) { CFStreamHandle* CFStreamHandle::CreateStreamHandle( CFReadStreamRef read_stream, CFWriteStreamRef write_stream) { - return new CFStreamHandle(read_stream, write_stream); + return grpc_core::New(read_stream, write_stream); } void CFStreamHandle::ReadCallback(CFReadStreamRef stream, @@ -188,7 +189,7 @@ void CFStreamHandle::Unref(const char* file, int line, const char* reason) { reason, val, val - 1); } if (gpr_unref(&refcount_)) { - delete this; + grpc_core::Delete(this); } } diff --git a/src/core/lib/iomgr/cfstream_handle.h b/src/core/lib/iomgr/cfstream_handle.h index 4f4d15966e4..05f45ed6251 100644 --- a/src/core/lib/iomgr/cfstream_handle.h +++ b/src/core/lib/iomgr/cfstream_handle.h @@ -29,6 +29,7 @@ #ifdef GRPC_CFSTREAM #import +#include "src/core/lib/gprpp/memory.h" #include "src/core/lib/iomgr/closure.h" #include "src/core/lib/iomgr/lockfree_event.h" @@ -65,6 +66,9 @@ class CFStreamHandle final { dispatch_queue_t dispatch_queue_; gpr_refcount refcount_; + + GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW + GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE }; #ifdef DEBUG diff --git a/src/core/lib/iomgr/ev_posix.cc b/src/core/lib/iomgr/ev_posix.cc index ddafb7b5539..92f81c2efb8 100644 --- a/src/core/lib/iomgr/ev_posix.cc +++ b/src/core/lib/iomgr/ev_posix.cc @@ -44,11 +44,11 @@ GPR_GLOBAL_CONFIG_DEFINE_STRING( "This is a comma-separated list of engines, which are tried in priority " "order first -> last.") -grpc_core::TraceFlag grpc_polling_trace(false, - "polling"); /* Disabled by default */ +grpc_core::DebugOnlyTraceFlag grpc_polling_trace( + false, "polling"); /* Disabled by default */ /* Traces fd create/close operations */ -grpc_core::TraceFlag grpc_fd_trace(false, "fd_trace"); +grpc_core::DebugOnlyTraceFlag grpc_fd_trace(false, "fd_trace"); grpc_core::DebugOnlyTraceFlag grpc_trace_fd_refcount(false, "fd_refcount"); grpc_core::DebugOnlyTraceFlag grpc_polling_api_trace(false, "polling_api"); diff --git a/src/core/lib/iomgr/ev_posix.h b/src/core/lib/iomgr/ev_posix.h index 30bb5e40faf..84edabce71e 100644 --- a/src/core/lib/iomgr/ev_posix.h +++ b/src/core/lib/iomgr/ev_posix.h @@ -32,8 +32,9 @@ GPR_GLOBAL_CONFIG_DECLARE_STRING(grpc_poll_strategy); -extern grpc_core::TraceFlag grpc_fd_trace; /* Disabled by default */ -extern grpc_core::TraceFlag grpc_polling_trace; /* Disabled by default */ +extern grpc_core::DebugOnlyTraceFlag grpc_fd_trace; /* Disabled by default */ +extern grpc_core::DebugOnlyTraceFlag + grpc_polling_trace; /* Disabled by default */ #define GRPC_FD_TRACE(format, ...) \ if (GRPC_TRACE_FLAG_ENABLED(grpc_fd_trace)) { \ diff --git a/src/core/lib/iomgr/ev_windows.cc b/src/core/lib/iomgr/ev_windows.cc index 32c62b7a762..e3f5715a873 100644 --- a/src/core/lib/iomgr/ev_windows.cc +++ b/src/core/lib/iomgr/ev_windows.cc @@ -24,7 +24,7 @@ #include "src/core/lib/debug/trace.h" -grpc_core::TraceFlag grpc_polling_trace(false, - "polling"); /* Disabled by default */ +grpc_core::DebugOnlyTraceFlag grpc_polling_trace( + false, "polling"); /* Disabled by default */ #endif // GRPC_WINSOCK_SOCKET diff --git a/src/core/lib/iomgr/lockfree_event.cc b/src/core/lib/iomgr/lockfree_event.cc index f0c40b4827d..f33485ee59d 100644 --- a/src/core/lib/iomgr/lockfree_event.cc +++ b/src/core/lib/iomgr/lockfree_event.cc @@ -24,7 +24,7 @@ #include "src/core/lib/debug/trace.h" -extern grpc_core::TraceFlag grpc_polling_trace; +extern grpc_core::DebugOnlyTraceFlag grpc_polling_trace; /* 'state' holds the to call when the fd is readable or writable respectively. It can contain one of the following values: diff --git a/src/core/lib/iomgr/port.h b/src/core/lib/iomgr/port.h index 605692ac0d6..63a0269ed62 100644 --- a/src/core/lib/iomgr/port.h +++ b/src/core/lib/iomgr/port.h @@ -26,6 +26,11 @@ #define GRPC_CUSTOM_SOCKET #endif #endif +/* This needs to be separate from the other conditions because it needs to + * apply to custom sockets too */ +#ifdef GPR_WINDOWS +#define GRPC_ARES_RESOLVE_LOCALHOST_MANUALLY 1 +#endif #if defined(GRPC_CUSTOM_SOCKET) // Do Nothing #elif defined(GPR_MANYLINUX1) @@ -45,7 +50,6 @@ #define GRPC_WINSOCK_SOCKET 1 #define GRPC_WINDOWS_SOCKETUTILS 1 #define GRPC_WINDOWS_SOCKET_ARES_EV_DRIVER 1 -#define GRPC_ARES_RESOLVE_LOCALHOST_MANUALLY 1 #elif defined(GPR_ANDROID) #define GRPC_HAVE_IPV6_RECVPKTINFO 1 #define GRPC_HAVE_IP_PKTINFO 1 diff --git a/src/core/lib/iomgr/tcp_posix.cc b/src/core/lib/iomgr/tcp_posix.cc index cda7bba0d3a..889272f6299 100644 --- a/src/core/lib/iomgr/tcp_posix.cc +++ b/src/core/lib/iomgr/tcp_posix.cc @@ -685,7 +685,6 @@ static bool tcp_write_with_timestamps(grpc_tcp* tcp, struct msghdr* msg, uint32_t opt = grpc_core::kTimestampingSocketOptions; if (setsockopt(tcp->fd, SOL_SOCKET, SO_TIMESTAMPING, static_cast(&opt), sizeof(opt)) != 0) { - grpc_slice_buffer_reset_and_unref_internal(tcp->outgoing_buffer); if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_ERROR, "Failed to set timestamping options on the socket."); } diff --git a/src/core/lib/iomgr/tcp_uv.cc b/src/core/lib/iomgr/tcp_uv.cc index e53ff472fef..f0847a195ca 100644 --- a/src/core/lib/iomgr/tcp_uv.cc +++ b/src/core/lib/iomgr/tcp_uv.cc @@ -53,7 +53,7 @@ typedef struct uv_socket_t { char* read_buf; size_t read_len; - bool pending_connection; + int pending_connections; grpc_custom_socket* accept_socket; grpc_error* accept_error; @@ -206,7 +206,7 @@ static grpc_error* uv_socket_init_helper(uv_socket_t* uv_socket, int domain) { // Node uses a garbage collector to call destructors, so we don't // want to hold the uv loop open with active gRPC objects. uv_unref((uv_handle_t*)uv_socket->handle); - uv_socket->pending_connection = false; + uv_socket->pending_connections = 0; uv_socket->accept_socket = nullptr; uv_socket->accept_error = GRPC_ERROR_NONE; return GRPC_ERROR_NONE; @@ -243,14 +243,14 @@ static grpc_error* uv_socket_getsockname(grpc_custom_socket* socket, static void accept_new_connection(grpc_custom_socket* socket) { uv_socket_t* uv_socket = (uv_socket_t*)socket->impl; - if (!uv_socket->pending_connection || !uv_socket->accept_socket) { + if (uv_socket->pending_connections == 0 || !uv_socket->accept_socket) { return; } grpc_custom_socket* new_socket = uv_socket->accept_socket; grpc_error* error = uv_socket->accept_error; uv_socket->accept_socket = nullptr; uv_socket->accept_error = GRPC_ERROR_NONE; - uv_socket->pending_connection = false; + uv_socket->pending_connections -= 1; if (uv_socket->accept_error != GRPC_ERROR_NONE) { uv_stream_t dummy_handle; uv_accept((uv_stream_t*)uv_socket->handle, &dummy_handle); @@ -270,8 +270,6 @@ static void accept_new_connection(grpc_custom_socket* socket) { static void uv_on_connect(uv_stream_t* server, int status) { grpc_custom_socket* socket = (grpc_custom_socket*)server->data; uv_socket_t* uv_socket = (uv_socket_t*)socket->impl; - GPR_ASSERT(!uv_socket->pending_connection); - uv_socket->pending_connection = true; if (status < 0) { switch (status) { case UV_EINTR: @@ -281,6 +279,7 @@ static void uv_on_connect(uv_stream_t* server, int status) { uv_socket->accept_error = tcp_error_create("accept failed", status); } } + uv_socket->pending_connections += 1; accept_new_connection(socket); } diff --git a/src/core/lib/security/transport/security_handshaker.cc b/src/core/lib/security/transport/security_handshaker.cc index fdc64727b96..3ad04774837 100644 --- a/src/core/lib/security/transport/security_handshaker.cc +++ b/src/core/lib/security/transport/security_handshaker.cc @@ -195,7 +195,7 @@ void SecurityHandshaker::HandshakeFailedLocked(grpc_error* error) { void SecurityHandshaker::OnPeerCheckedInner(grpc_error* error) { MutexLock lock(&mu_); if (error != GRPC_ERROR_NONE || is_shutdown_) { - HandshakeFailedLocked(GRPC_ERROR_REF(error)); + HandshakeFailedLocked(error); return; } // Create zero-copy frame protector, if implemented. @@ -255,7 +255,7 @@ void SecurityHandshaker::OnPeerCheckedInner(grpc_error* error) { void SecurityHandshaker::OnPeerCheckedFn(void* arg, grpc_error* error) { RefCountedPtr(static_cast(arg)) - ->OnPeerCheckedInner(error); + ->OnPeerCheckedInner(GRPC_ERROR_REF(error)); } grpc_error* SecurityHandshaker::CheckPeerLocked() { diff --git a/src/core/lib/slice/slice.cc b/src/core/lib/slice/slice.cc index 3a3edebdc7a..eebf66bb882 100644 --- a/src/core/lib/slice/slice.cc +++ b/src/core/lib/slice/slice.cc @@ -102,18 +102,19 @@ class NewSliceRefcount { } NewSliceRefcount(void (*destroy)(void*), void* user_data) - : rc_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this, &rc_), + : base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this, + &base_), user_destroy_(destroy), user_data_(user_data) {} - GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE + GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE - grpc_slice_refcount* base_refcount() { return &rc_; } + grpc_slice_refcount* base_refcount() { return &base_; } private: ~NewSliceRefcount() { user_destroy_(user_data_); } - grpc_slice_refcount rc_; + grpc_slice_refcount base_; RefCount refs_; void (*user_destroy_)(void*); void* user_data_; @@ -141,7 +142,6 @@ grpc_slice grpc_slice_new(void* p, size_t len, void (*destroy)(void*)) { namespace grpc_core { /* grpc_slice_new_with_len support structures - we create a refcount object extended with the user provided data pointer & destroy function */ - class NewWithLenSliceRefcount { public: static void Destroy(void* arg) { @@ -150,25 +150,48 @@ class NewWithLenSliceRefcount { NewWithLenSliceRefcount(void (*destroy)(void*, size_t), void* user_data, size_t user_length) - : rc_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this, &rc_), + : base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this, + &base_), user_data_(user_data), user_length_(user_length), user_destroy_(destroy) {} - GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE + GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE - grpc_slice_refcount* base_refcount() { return &rc_; } + grpc_slice_refcount* base_refcount() { return &base_; } private: ~NewWithLenSliceRefcount() { user_destroy_(user_data_, user_length_); } - grpc_slice_refcount rc_; + grpc_slice_refcount base_; RefCount refs_; void* user_data_; size_t user_length_; void (*user_destroy_)(void*, size_t); }; +/** grpc_slice_from_moved_(string|buffer) ref count .*/ +class MovedStringSliceRefCount { + public: + MovedStringSliceRefCount(grpc_core::UniquePtr&& str) + : base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this, + &base_), + str_(std::move(str)) {} + + GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE + + grpc_slice_refcount* base_refcount() { return &base_; } + + private: + static void Destroy(void* arg) { + Delete(static_cast(arg)); + } + + grpc_slice_refcount base_; + grpc_core::RefCount refs_; + grpc_core::UniquePtr str_; +}; + } // namespace grpc_core grpc_slice grpc_slice_new_with_len(void* p, size_t len, @@ -193,6 +216,29 @@ grpc_slice grpc_slice_from_copied_string(const char* source) { return grpc_slice_from_copied_buffer(source, strlen(source)); } +grpc_slice grpc_slice_from_moved_buffer(grpc_core::UniquePtr p, + size_t len) { + uint8_t* ptr = reinterpret_cast(p.get()); + grpc_slice slice; + if (len <= sizeof(slice.data.inlined.bytes)) { + slice.refcount = nullptr; + slice.data.inlined.length = len; + memcpy(GRPC_SLICE_START_PTR(slice), ptr, len); + } else { + slice.refcount = + grpc_core::New(std::move(p)) + ->base_refcount(); + slice.data.refcounted.bytes = ptr; + slice.data.refcounted.length = len; + } + return slice; +} + +grpc_slice grpc_slice_from_moved_string(grpc_core::UniquePtr p) { + const size_t len = strlen(p.get()); + return grpc_slice_from_moved_buffer(std::move(p), len); +} + namespace { class MallocRefCount { diff --git a/src/core/lib/slice/slice_internal.h b/src/core/lib/slice/slice_internal.h index 23a2f6b81bc..c6943fe6563 100644 --- a/src/core/lib/slice/slice_internal.h +++ b/src/core/lib/slice/slice_internal.h @@ -28,6 +28,7 @@ #include #include "src/core/lib/gpr/murmur_hash.h" +#include "src/core/lib/gprpp/memory.h" #include "src/core/lib/gprpp/ref_counted.h" #include "src/core/lib/transport/static_metadata.h" @@ -302,6 +303,10 @@ inline uint32_t grpc_slice_hash_internal(const grpc_slice& s) { : grpc_slice_hash_refcounted(s); } +grpc_slice grpc_slice_from_moved_buffer(grpc_core::UniquePtr p, + size_t len); +grpc_slice grpc_slice_from_moved_string(grpc_core::UniquePtr p); + // Returns the memory used by this slice, not counting the slice structure // itself. This means that inlined and slices from static strings will return // 0. All other slices will return the size of the allocated chars. diff --git a/src/core/lib/slice/slice_string_helpers.cc b/src/core/lib/slice/slice_string_helpers.cc index c2392fd392f..7887e0305fb 100644 --- a/src/core/lib/slice/slice_string_helpers.cc +++ b/src/core/lib/slice/slice_string_helpers.cc @@ -25,6 +25,7 @@ #include #include "src/core/lib/gpr/string.h" +#include "src/core/lib/gprpp/memory.h" #include "src/core/lib/slice/slice_internal.h" char* grpc_dump_slice(const grpc_slice& s, uint32_t flags) { @@ -32,6 +33,14 @@ char* grpc_dump_slice(const grpc_slice& s, uint32_t flags) { GRPC_SLICE_LENGTH(s), flags); } +grpc_slice grpc_dump_slice_to_slice(const grpc_slice& s, uint32_t flags) { + size_t len; + grpc_core::UniquePtr ptr( + gpr_dump_return_len(reinterpret_cast GRPC_SLICE_START_PTR(s), + GRPC_SLICE_LENGTH(s), flags, &len)); + return grpc_slice_from_moved_buffer(std::move(ptr), len); +} + /** Finds the initial (\a begin) and final (\a end) offsets of the next * substring from \a str + \a read_offset until the next \a sep or the end of \a * str. diff --git a/src/core/lib/slice/slice_string_helpers.h b/src/core/lib/slice/slice_string_helpers.h index cb1df658fa5..6551a6df75d 100644 --- a/src/core/lib/slice/slice_string_helpers.h +++ b/src/core/lib/slice/slice_string_helpers.h @@ -31,6 +31,8 @@ /* Calls gpr_dump on a slice. */ char* grpc_dump_slice(const grpc_slice& slice, uint32_t flags); +/* Calls gpr_dump on a slice and returns the result as a slice. */ +grpc_slice grpc_dump_slice_to_slice(const grpc_slice& slice, uint32_t flags); /** Split \a str by the separator \a sep. Results are stored in \a dst, which * should be a properly initialized instance. */ diff --git a/src/core/lib/surface/channel.cc b/src/core/lib/surface/channel.cc index 12869b7780d..e61550743b7 100644 --- a/src/core/lib/surface/channel.cc +++ b/src/core/lib/surface/channel.cc @@ -33,6 +33,7 @@ #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/channel_trace.h" #include "src/core/lib/channel/channelz.h" +#include "src/core/lib/channel/channelz_registry.h" #include "src/core/lib/debug/stats.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gprpp/manual_constructor.h" @@ -86,18 +87,9 @@ grpc_channel* grpc_channel_create_with_builder( grpc_channel_args_destroy(args); return channel; } - channel->target = target; channel->resource_user = resource_user; channel->is_client = grpc_channel_stack_type_is_client(channel_stack_type); - bool channelz_enabled = GRPC_ENABLE_CHANNELZ_DEFAULT; - size_t channel_tracer_max_memory = - GRPC_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE_DEFAULT; - bool internal_channel = false; - // this creates the default ChannelNode. Different types of channels may - // override this to ensure a correct ChannelNode is created. - grpc_core::channelz::ChannelNodeCreationFunc channel_node_create_func = - grpc_core::channelz::ChannelNode::MakeChannelNode; gpr_mu_init(&channel->registered_call_mu); channel->registered_calls = nullptr; @@ -129,40 +121,16 @@ grpc_channel* grpc_channel_create_with_builder( channel->compression_options.enabled_algorithms_bitset = static_cast(args->args[i].value.integer) | 0x1; /* always support no compression */ - } else if (0 == strcmp(args->args[i].key, - GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE)) { - const grpc_integer_options options = { - GRPC_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE_DEFAULT, 0, INT_MAX}; - channel_tracer_max_memory = - (size_t)grpc_channel_arg_get_integer(&args->args[i], options); - } else if (0 == strcmp(args->args[i].key, GRPC_ARG_ENABLE_CHANNELZ)) { - // channelz will not be enabled by default until all concerns in - // https://github.com/grpc/grpc/issues/15986 are addressed. - channelz_enabled = grpc_channel_arg_get_bool( - &args->args[i], GRPC_ENABLE_CHANNELZ_DEFAULT); - } else if (0 == strcmp(args->args[i].key, - GRPC_ARG_CHANNELZ_CHANNEL_NODE_CREATION_FUNC)) { + } else if (0 == strcmp(args->args[i].key, GRPC_ARG_CHANNELZ_CHANNEL_NODE)) { GPR_ASSERT(args->args[i].type == GRPC_ARG_POINTER); GPR_ASSERT(args->args[i].value.pointer.p != nullptr); - channel_node_create_func = - reinterpret_cast( - args->args[i].value.pointer.p); - } else if (0 == strcmp(args->args[i].key, - GRPC_ARG_CHANNELZ_CHANNEL_IS_INTERNAL_CHANNEL)) { - internal_channel = grpc_channel_arg_get_bool(&args->args[i], false); + channel->channelz_node = static_cast( + args->args[i].value.pointer.p) + ->Ref(); } } grpc_channel_args_destroy(args); - // we only need to do the channelz bookkeeping for clients here. The channelz - // bookkeeping for server channels occurs in src/core/lib/surface/server.cc - if (channelz_enabled && channel->is_client) { - channel->channelz_channel = channel_node_create_func( - channel, channel_tracer_max_memory, !internal_channel); - channel->channelz_channel->AddTraceEvent( - grpc_core::channelz::ChannelTrace::Severity::Info, - grpc_slice_from_static_string("Channel created")); - } return channel; } @@ -197,6 +165,71 @@ static grpc_channel_args* build_channel_args( return grpc_channel_args_copy_and_add(input_args, new_args, num_new_args); } +namespace { + +void* channelz_node_copy(void* p) { + grpc_core::channelz::ChannelNode* node = + static_cast(p); + node->Ref().release(); + return p; +} +void channelz_node_destroy(void* p) { + grpc_core::channelz::ChannelNode* node = + static_cast(p); + node->Unref(); +} +int channelz_node_cmp(void* p1, void* p2) { return GPR_ICMP(p1, p2); } +const grpc_arg_pointer_vtable channelz_node_arg_vtable = { + channelz_node_copy, channelz_node_destroy, channelz_node_cmp}; + +void CreateChannelzNode(grpc_channel_stack_builder* builder) { + const grpc_channel_args* args = + grpc_channel_stack_builder_get_channel_arguments(builder); + // Check whether channelz is enabled. + const bool channelz_enabled = grpc_channel_arg_get_bool( + grpc_channel_args_find(args, GRPC_ARG_ENABLE_CHANNELZ), + GRPC_ENABLE_CHANNELZ_DEFAULT); + if (!channelz_enabled) return; + // Get parameters needed to create the channelz node. + const size_t channel_tracer_max_memory = grpc_channel_arg_get_integer( + grpc_channel_args_find(args, + GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE), + {GRPC_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE_DEFAULT, 0, INT_MAX}); + const intptr_t channelz_parent_uuid = + grpc_core::channelz::GetParentUuidFromArgs(*args); + // Create the channelz node. + grpc_core::RefCountedPtr channelz_node = + grpc_core::MakeRefCounted( + grpc_core::UniquePtr( + gpr_strdup(grpc_channel_stack_builder_get_target(builder))), + channel_tracer_max_memory, channelz_parent_uuid); + channelz_node->AddTraceEvent( + grpc_core::channelz::ChannelTrace::Severity::Info, + grpc_slice_from_static_string("Channel created")); + // Update parent channel node, if any. + if (channelz_parent_uuid > 0) { + grpc_core::RefCountedPtr parent_node = + grpc_core::channelz::ChannelzRegistry::Get(channelz_parent_uuid); + if (parent_node != nullptr) { + grpc_core::channelz::ChannelNode* parent = + static_cast(parent_node.get()); + parent->AddChildChannel(channelz_node->uuid()); + } + } + // Add channelz node to channel args. + // We remove the arg for the parent uuid, since we no longer need it. + grpc_arg new_arg = grpc_channel_arg_pointer_create( + const_cast(GRPC_ARG_CHANNELZ_CHANNEL_NODE), channelz_node.get(), + &channelz_node_arg_vtable); + const char* args_to_remove[] = {GRPC_ARG_CHANNELZ_PARENT_UUID}; + grpc_channel_args* new_args = grpc_channel_args_copy_and_add_and_remove( + args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), &new_arg, 1); + grpc_channel_stack_builder_set_channel_arguments(builder, new_args); + grpc_channel_args_destroy(new_args); +} + +} // namespace + grpc_channel* grpc_channel_create(const char* target, const grpc_channel_args* input_args, grpc_channel_stack_type channel_stack_type, @@ -219,9 +252,12 @@ grpc_channel* grpc_channel_create(const char* target, } return nullptr; } - grpc_channel* channel = - grpc_channel_create_with_builder(builder, channel_stack_type); - return channel; + // We only need to do this for clients here. For servers, this will be + // done in src/core/lib/surface/server.cc. + if (grpc_channel_stack_type_is_client(channel_stack_type)) { + CreateChannelzNode(builder); + } + return grpc_channel_create_with_builder(builder, channel_stack_type); } size_t grpc_channel_get_call_size_estimate(grpc_channel* channel) { @@ -401,12 +437,21 @@ grpc_call* grpc_channel_create_registered_call( static void destroy_channel(void* arg, grpc_error* error) { grpc_channel* channel = static_cast(arg); - if (channel->channelz_channel != nullptr) { - channel->channelz_channel->AddTraceEvent( + if (channel->channelz_node != nullptr) { + if (channel->channelz_node->parent_uuid() > 0) { + grpc_core::RefCountedPtr parent_node = + grpc_core::channelz::ChannelzRegistry::Get( + channel->channelz_node->parent_uuid()); + if (parent_node != nullptr) { + grpc_core::channelz::ChannelNode* parent = + static_cast(parent_node.get()); + parent->RemoveChildChannel(channel->channelz_node->uuid()); + } + } + channel->channelz_node->AddTraceEvent( grpc_core::channelz::ChannelTrace::Severity::Info, grpc_slice_from_static_string("Channel destroyed")); - channel->channelz_channel->MarkChannelDestroyed(); - channel->channelz_channel.reset(); + channel->channelz_node.reset(); } grpc_channel_stack_destroy(CHANNEL_STACK_FROM_CHANNEL(channel)); while (channel->registered_calls) { diff --git a/src/core/lib/surface/channel.h b/src/core/lib/surface/channel.h index 5d666220745..a4cac748f2d 100644 --- a/src/core/lib/surface/channel.h +++ b/src/core/lib/surface/channel.h @@ -88,7 +88,7 @@ struct grpc_channel { gpr_mu registered_call_mu; registered_call* registered_calls; - grpc_core::RefCountedPtr channelz_channel; + grpc_core::RefCountedPtr channelz_node; char* target; }; @@ -106,7 +106,7 @@ inline grpc_channel_stack* grpc_channel_get_channel_stack( inline grpc_core::channelz::ChannelNode* grpc_channel_get_channelz_node( grpc_channel* channel) { - return channel->channelz_channel.get(); + return channel->channelz_node.get(); } #ifndef NDEBUG diff --git a/src/core/lib/surface/server.cc b/src/core/lib/surface/server.cc index 44de0cd42dd..8f6df482aa9 100644 --- a/src/core/lib/surface/server.cc +++ b/src/core/lib/surface/server.cc @@ -1194,12 +1194,12 @@ void grpc_server_setup_transport( bool has_host; grpc_slice method; if (rm->host != nullptr) { - host = grpc_slice_intern(grpc_slice_from_static_string(rm->host)); + host = grpc_slice_from_static_string(rm->host); has_host = true; } else { has_host = false; } - method = grpc_slice_intern(grpc_slice_from_static_string(rm->method)); + method = grpc_slice_from_static_string(rm->method); hash = GRPC_MDSTR_KV_HASH(has_host ? grpc_slice_hash_internal(host) : 0, grpc_slice_hash_internal(method)); for (probes = 0; chand->registered_methods[(hash + probes) % slots] diff --git a/src/core/lib/surface/validate_metadata.cc b/src/core/lib/surface/validate_metadata.cc index a92ab823a38..0f65091333d 100644 --- a/src/core/lib/surface/validate_metadata.cc +++ b/src/core/lib/surface/validate_metadata.cc @@ -24,6 +24,7 @@ #include #include +#include "src/core/lib/gprpp/memory.h" #include "src/core/lib/iomgr/error.h" #include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/slice/slice_string_helpers.h" @@ -39,13 +40,12 @@ static grpc_error* conforms_to(const grpc_slice& slice, int byte = idx / 8; int bit = idx % 8; if ((legal_bits[byte] & (1 << bit)) == 0) { - char* dump = grpc_dump_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII); grpc_error* error = grpc_error_set_str( grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(err_desc), GRPC_ERROR_INT_OFFSET, p - GRPC_SLICE_START_PTR(slice)), - GRPC_ERROR_STR_RAW_BYTES, grpc_slice_from_copied_string(dump)); - gpr_free(dump); + GRPC_ERROR_STR_RAW_BYTES, + grpc_dump_slice_to_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII)); return error; } } diff --git a/src/core/lib/transport/metadata.cc b/src/core/lib/transport/metadata.cc index 1523ced16d8..7766ee186c6 100644 --- a/src/core/lib/transport/metadata.cc +++ b/src/core/lib/transport/metadata.cc @@ -222,7 +222,12 @@ void grpc_mdctx_global_shutdown() { abort(); } } + // For ASAN builds, we don't want to crash here, because that will + // prevent ASAN from providing leak detection information, which is + // far more useful than this simple assertion. +#ifndef GRPC_ASAN_ENABLED GPR_DEBUG_ASSERT(shard->count == 0); +#endif gpr_free(shard->elems); } } diff --git a/src/core/lib/transport/transport.cc b/src/core/lib/transport/transport.cc index 29c1e561891..80ffabce0e5 100644 --- a/src/core/lib/transport/transport.cc +++ b/src/core/lib/transport/transport.cc @@ -90,7 +90,7 @@ void grpc_stream_ref_init(grpc_stream_refcount* refcount, int initial_refs, #endif GRPC_CLOSURE_INIT(&refcount->destroy, cb, cb_arg, grpc_schedule_on_exec_ctx); - new (&refcount->refs) grpc_core::RefCount(); + new (&refcount->refs) grpc_core::RefCount(1, &grpc_trace_stream_refcount); new (&refcount->slice_refcount) grpc_slice_refcount( grpc_slice_refcount::Type::REGULAR, &refcount->refs, slice_stream_destroy, refcount, &refcount->slice_refcount); diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h index a6a6e904f08..17608f4bc60 100644 --- a/src/core/lib/transport/transport.h +++ b/src/core/lib/transport/transport.h @@ -80,11 +80,13 @@ inline void grpc_stream_ref(grpc_stream_refcount* refcount, gpr_log(GPR_DEBUG, "%s %p:%p REF %s", refcount->object_type, refcount, refcount->destroy.cb_arg, reason); } + refcount->refs.RefNonZero(DEBUG_LOCATION, reason); +} #else inline void grpc_stream_ref(grpc_stream_refcount* refcount) { -#endif refcount->refs.RefNonZero(); } +#endif void grpc_stream_destroy(grpc_stream_refcount* refcount); @@ -95,13 +97,17 @@ inline void grpc_stream_unref(grpc_stream_refcount* refcount, gpr_log(GPR_DEBUG, "%s %p:%p UNREF %s", refcount->object_type, refcount, refcount->destroy.cb_arg, reason); } + if (GPR_UNLIKELY(refcount->refs.Unref(DEBUG_LOCATION, reason))) { + grpc_stream_destroy(refcount); + } +} #else inline void grpc_stream_unref(grpc_stream_refcount* refcount) { -#endif if (GPR_UNLIKELY(refcount->refs.Unref())) { grpc_stream_destroy(refcount); } } +#endif /* Wrap a buffer that is owned by some stream object into a slice that shares the same refcount */ diff --git a/src/cpp/client/channel_cc.cc b/src/cpp/client/channel_cc.cc index f0aa8e4017a..de0f4e1787b 100644 --- a/src/cpp/client/channel_cc.cc +++ b/src/cpp/client/channel_cc.cc @@ -144,7 +144,7 @@ void ChannelResetConnectionBackoff(Channel* channel) { // ClientRpcInfo should be set before call because set_call also checks // whether the call has been cancelled, and if the call was cancelled, we - // should notify the interceptors too/ + // should notify the interceptors too. auto* info = context->set_client_rpc_info(method.name(), method.method_type(), this, interceptor_creators_, interceptor_pos); diff --git a/src/cpp/client/client_context.cc b/src/cpp/client/client_context.cc index 0ae1ecbf4ba..efb10a44006 100644 --- a/src/cpp/client/client_context.cc +++ b/src/cpp/client/client_context.cc @@ -34,9 +34,6 @@ namespace grpc_impl { class Channel; -} - -namespace grpc { class DefaultGlobalClientCallbacks final : public ClientContext::GlobalCallbacks { @@ -46,7 +43,7 @@ class DefaultGlobalClientCallbacks final void Destructor(ClientContext* context) override {} }; -static internal::GrpcLibraryInitializer g_gli_initializer; +static grpc::internal::GrpcLibraryInitializer g_gli_initializer; static DefaultGlobalClientCallbacks* g_default_client_callbacks = new DefaultGlobalClientCallbacks(); static ClientContext::GlobalCallbacks* g_client_callbacks = @@ -76,7 +73,7 @@ ClientContext::~ClientContext() { } std::unique_ptr ClientContext::FromServerContext( - const ServerContext& context, PropagationOptions options) { + const grpc::ServerContext& context, PropagationOptions options) { std::unique_ptr ctx(new ClientContext); ctx->propagate_from_call_ = context.call_; ctx->propagation_options_ = options; @@ -130,7 +127,7 @@ void ClientContext::TryCancel() { } void ClientContext::SendCancelToInterceptors() { - internal::CancelInterceptorBatchMethods cancel_methods; + grpc::internal::CancelInterceptorBatchMethods cancel_methods; for (size_t i = 0; i < rpc_info_.interceptors_.size(); i++) { rpc_info_.RunInterceptor(&cancel_methods, i); } @@ -153,4 +150,4 @@ void ClientContext::SetGlobalCallbacks(GlobalCallbacks* client_callbacks) { g_client_callbacks = client_callbacks; } -} // namespace grpc +} // namespace grpc_impl diff --git a/src/cpp/ext/filters/census/grpc_plugin.h b/src/cpp/ext/filters/census/grpc_plugin.h index 993faae0a94..13176759e37 100644 --- a/src/cpp/ext/filters/census/grpc_plugin.h +++ b/src/cpp/ext/filters/census/grpc_plugin.h @@ -25,8 +25,11 @@ #include "include/grpcpp/opencensus.h" #include "opencensus/stats/stats.h" -namespace grpc { +namespace grpc_impl { class ServerContext; +} + +namespace grpc { // The tag keys set when recording RPC stats. ::opencensus::stats::TagKey ClientMethodTagKey(); diff --git a/src/cpp/server/server_context.cc b/src/cpp/server/server_context.cc index eced89d1a79..ba834237ae9 100644 --- a/src/cpp/server/server_context.cc +++ b/src/cpp/server/server_context.cc @@ -16,7 +16,7 @@ * */ -#include +#include #include #include @@ -28,23 +28,25 @@ #include #include #include -#include #include +#include #include #include "src/core/lib/gprpp/ref_counted.h" #include "src/core/lib/gprpp/sync.h" #include "src/core/lib/surface/call.h" -namespace grpc { +namespace grpc_impl { // CompletionOp -class ServerContext::CompletionOp final : public internal::CallOpSetInterface { +class ServerContext::CompletionOp final + : public ::grpc::internal::CallOpSetInterface { public: // initial refs: one in the server context, one in the cq // must ref the call before calling constructor and after deleting this - CompletionOp(internal::Call* call, internal::ServerReactor* reactor) + CompletionOp(::grpc::internal::Call* call, + ::grpc::internal::ServerReactor* reactor) : call_(*call), reactor_(reactor), has_tag_(false), @@ -67,7 +69,7 @@ class ServerContext::CompletionOp final : public internal::CallOpSetInterface { } } - void FillOps(internal::Call* call) override; + void FillOps(::grpc::internal::Call* call) override; // This should always be arena allocated in the call, so override delete. // But this class is not trivially destructible, so must actually call delete @@ -149,8 +151,8 @@ class ServerContext::CompletionOp final : public internal::CallOpSetInterface { return finalized_ ? (cancelled_ != 0) : false; } - internal::Call call_; - internal::ServerReactor* const reactor_; + ::grpc::internal::Call call_; + ::grpc::internal::ServerReactor* const reactor_; bool has_tag_; void* tag_; void* core_cq_tag_; @@ -160,7 +162,7 @@ class ServerContext::CompletionOp final : public internal::CallOpSetInterface { int cancelled_; // This is an int (not bool) because it is passed to core std::function cancel_callback_; bool done_intercepting_; - internal::InterceptorBatchMethodsImpl interceptor_methods_; + ::grpc::internal::InterceptorBatchMethodsImpl interceptor_methods_; }; void ServerContext::CompletionOp::Unref() { @@ -171,7 +173,7 @@ void ServerContext::CompletionOp::Unref() { } } -void ServerContext::CompletionOp::FillOps(internal::Call* call) { +void ServerContext::CompletionOp::FillOps(::grpc::internal::Call* call) { grpc_op ops; ops.op = GRPC_OP_RECV_CLOSE_ON_SERVER; ops.data.recv_close_on_server.cancelled = &cancelled_; @@ -227,7 +229,7 @@ bool ServerContext::CompletionOp::FinalizeResult(void** tag, bool* status) { } /* Add interception point and run through interceptors */ interceptor_methods_.AddInterceptionHookPoint( - experimental::InterceptionHookPoints::POST_RECV_CLOSE); + ::grpc::experimental::InterceptionHookPoints::POST_RECV_CLOSE); if (interceptor_methods_.RunInterceptors()) { /* No interceptors were run */ if (has_tag_) { @@ -292,9 +294,9 @@ void ServerContext::Clear() { } } -void ServerContext::BeginCompletionOp(internal::Call* call, - std::function callback, - internal::ServerReactor* reactor) { +void ServerContext::BeginCompletionOp( + ::grpc::internal::Call* call, std::function callback, + ::grpc::internal::ServerReactor* reactor) { GPR_ASSERT(!completion_op_); if (rpc_info_) { rpc_info_->Ref(); @@ -313,8 +315,8 @@ void ServerContext::BeginCompletionOp(internal::Call* call, call->PerformOps(completion_op_); } -internal::CompletionQueueTag* ServerContext::GetCompletionOpTag() { - return static_cast(completion_op_); +::grpc::internal::CompletionQueueTag* ServerContext::GetCompletionOpTag() { + return static_cast<::grpc::internal::CompletionQueueTag*>(completion_op_); } void ServerContext::AddInitialMetadata(const grpc::string& key, @@ -328,7 +330,7 @@ void ServerContext::AddTrailingMetadata(const grpc::string& key, } void ServerContext::TryCancel() const { - internal::CancelInterceptorBatchMethods cancel_methods; + ::grpc::internal::CancelInterceptorBatchMethods cancel_methods; if (rpc_info_) { for (size_t i = 0; i < rpc_info_->interceptors_.size(); i++) { rpc_info_->RunInterceptor(&cancel_methods, i); @@ -398,4 +400,4 @@ void ServerContext::SetLoadReportingCosts( } } -} // namespace grpc +} // namespace grpc_impl diff --git a/src/csharp/Grpc.Core/Interceptors/CallInvokerExtensions.cs b/src/csharp/Grpc.Core.Api/Interceptors/CallInvokerExtensions.cs similarity index 100% rename from src/csharp/Grpc.Core/Interceptors/CallInvokerExtensions.cs rename to src/csharp/Grpc.Core.Api/Interceptors/CallInvokerExtensions.cs diff --git a/src/csharp/Grpc.Core/Interceptors/InterceptingCallInvoker.cs b/src/csharp/Grpc.Core.Api/Interceptors/InterceptingCallInvoker.cs similarity index 100% rename from src/csharp/Grpc.Core/Interceptors/InterceptingCallInvoker.cs rename to src/csharp/Grpc.Core.Api/Interceptors/InterceptingCallInvoker.cs diff --git a/src/csharp/Grpc.Core/ForwardedTypes.cs b/src/csharp/Grpc.Core/ForwardedTypes.cs index ab5f5a87c67..fb99cfc018d 100644 --- a/src/csharp/Grpc.Core/ForwardedTypes.cs +++ b/src/csharp/Grpc.Core/ForwardedTypes.cs @@ -36,6 +36,7 @@ using Grpc.Core.Utils; [assembly:TypeForwardedToAttribute(typeof(CallCredentials))] [assembly:TypeForwardedToAttribute(typeof(CallFlags))] [assembly:TypeForwardedToAttribute(typeof(CallInvoker))] +[assembly:TypeForwardedToAttribute(typeof(CallInvokerExtensions))] [assembly:TypeForwardedToAttribute(typeof(CallOptions))] [assembly:TypeForwardedToAttribute(typeof(ClientInterceptorContext<,>))] [assembly:TypeForwardedToAttribute(typeof(ContextPropagationOptions))] @@ -45,6 +46,7 @@ using Grpc.Core.Utils; [assembly:TypeForwardedToAttribute(typeof(IAsyncStreamWriter<>))] [assembly:TypeForwardedToAttribute(typeof(IClientStreamWriter<>))] [assembly:TypeForwardedToAttribute(typeof(Interceptor))] +[assembly:TypeForwardedToAttribute(typeof(InterceptingCallInvoker))] [assembly:TypeForwardedToAttribute(typeof(IServerStreamWriter<>))] [assembly:TypeForwardedToAttribute(typeof(Marshaller<>))] [assembly:TypeForwardedToAttribute(typeof(Marshallers))] diff --git a/src/csharp/Grpc.Core/ServerCredentials.cs b/src/csharp/Grpc.Core/ServerCredentials.cs index 8e4e44ba504..d0fc600f85a 100644 --- a/src/csharp/Grpc.Core/ServerCredentials.cs +++ b/src/csharp/Grpc.Core/ServerCredentials.cs @@ -103,7 +103,7 @@ namespace Grpc.Core /// /// Server requests client certificate and enforces that the client presents a /// certificate. - /// The cerificate presented by the client is verified by the gRPC framework. + /// The certificate presented by the client is verified by the gRPC framework. /// (For a successful connection the client needs to present a certificate that /// can be verified against the root certificate configured by the server) /// The client's key certificate pair must be valid for the SSL connection to diff --git a/src/csharp/Grpc.Tools/ProtoCompile.cs b/src/csharp/Grpc.Tools/ProtoCompile.cs index 40cfbeb029b..36a0ea36cee 100644 --- a/src/csharp/Grpc.Tools/ProtoCompile.cs +++ b/src/csharp/Grpc.Tools/ProtoCompile.cs @@ -136,7 +136,7 @@ namespace Grpc.Tools new ErrorListFilter { Pattern = new Regex( - pattern: "(?'FILENAME'.+)\\((?'LINE'\\d+)\\) ?: ?warning in column=(?'COLUMN'\\d+) ?: ?(?'TEXT'.*)", + pattern: "^(?'FILENAME'.+?)\\((?'LINE'\\d+)\\) ?: ?warning in column=(?'COLUMN'\\d+) ?: ?(?'TEXT'.*)", options: RegexOptions.Compiled | RegexOptions.IgnoreCase, matchTimeout: s_regexTimeout), LogAction = (log, match) => @@ -162,7 +162,7 @@ namespace Grpc.Tools new ErrorListFilter { Pattern = new Regex( - pattern: "(?'FILENAME'.+)\\((?'LINE'\\d+)\\) ?: ?error in column=(?'COLUMN'\\d+) ?: ?(?'TEXT'.*)", + pattern: "^(?'FILENAME'.+?)\\((?'LINE'\\d+)\\) ?: ?error in column=(?'COLUMN'\\d+) ?: ?(?'TEXT'.*)", options: RegexOptions.Compiled | RegexOptions.IgnoreCase, matchTimeout: s_regexTimeout), LogAction = (log, match) => @@ -185,10 +185,10 @@ namespace Grpc.Tools // Example warning without location //../Protos/greet.proto: warning: Import google/protobuf/empty.proto but not used. - new ErrorListFilter + new ErrorListFilter { Pattern = new Regex( - pattern: "(?'FILENAME'.+): ?warning: ?(?'TEXT'.*)", + pattern: "^(?'FILENAME'.+?): ?warning: ?(?'TEXT'.*)", options: RegexOptions.Compiled | RegexOptions.IgnoreCase, matchTimeout: s_regexTimeout), LogAction = (log, match) => @@ -211,7 +211,7 @@ namespace Grpc.Tools new ErrorListFilter { Pattern = new Regex( - pattern: "(?'FILENAME'.+): ?(?'TEXT'.*)", + pattern: "^(?'FILENAME'.+?): ?(?'TEXT'.*)", options: RegexOptions.Compiled | RegexOptions.IgnoreCase, matchTimeout: s_regexTimeout), LogAction = (log, match) => @@ -518,7 +518,7 @@ namespace Grpc.Tools foreach (ErrorListFilter filter in s_errorListFilters) { Match match = filter.Pattern.Match(singleLine); - + if (match.Success) { filter.LogAction(Log, match); diff --git a/src/csharp/doc/.gitignore b/src/csharp/docfx/.gitignore similarity index 100% rename from src/csharp/doc/.gitignore rename to src/csharp/docfx/.gitignore diff --git a/src/csharp/doc/README.md b/src/csharp/docfx/README.md similarity index 100% rename from src/csharp/doc/README.md rename to src/csharp/docfx/README.md diff --git a/src/csharp/doc/docfx.json b/src/csharp/docfx/docfx.json similarity index 100% rename from src/csharp/doc/docfx.json rename to src/csharp/docfx/docfx.json diff --git a/src/csharp/doc/generate_reference_docs.sh b/src/csharp/docfx/generate_reference_docs.sh similarity index 90% rename from src/csharp/doc/generate_reference_docs.sh rename to src/csharp/docfx/generate_reference_docs.sh index c20d6c30bd3..dbed2bad27f 100755 --- a/src/csharp/doc/generate_reference_docs.sh +++ b/src/csharp/docfx/generate_reference_docs.sh @@ -23,7 +23,7 @@ rm -rf html obj grpc-gh-pages # generate into src/csharp/doc/html directory cd .. docker run --rm -v "$(pwd)":/work -w /work/doc --user "$(id -u):$(id -g)" -it tsgkadot/docker-docfx:latest docfx -cd doc +cd docfx # prepare a clone of "gh-pages" branch where the generated docs are stored GITHUB_USER="${USER}" @@ -35,4 +35,4 @@ git remote add origin "git@github.com:${GITHUB_USER}/grpc.git" rm -r csharp cp -r ../html csharp -echo "Done. Go to src/csharp/doc/grpc-gh-pages git repository and create a pull request to update the generated docs." +echo "Done. Go to src/csharp/docfx/grpc-gh-pages git repository and create a pull request to update the generated docs." diff --git a/src/csharp/doc/toc.yml b/src/csharp/docfx/toc.yml similarity index 100% rename from src/csharp/doc/toc.yml rename to src/csharp/docfx/toc.yml diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 71b03f15f17..e97ed6e3a9e 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -714,7 +714,12 @@ const char *kCFStreamVarName = "grpc_cfstream"; __strong GRPCCall *strongSelf = weakSelf; if (strongSelf) { @synchronized(strongSelf) { - strongSelf.responseHeaders = headers; + // it is ok to set nil because headers are only received once + strongSelf.responseHeaders = nil; + // copy the header so that the GRPCOpRecvMetadata object may be dealloc'ed + NSDictionary *copiedHeaders = + [[NSDictionary alloc] initWithDictionary:headers copyItems:YES]; + strongSelf.responseHeaders = copiedHeaders; strongSelf->_pendingCoreRead = NO; [strongSelf maybeStartNextRead]; } diff --git a/src/objective-c/tests/InteropTests/InteropTests.m b/src/objective-c/tests/InteropTests/InteropTests.m index 7d4aee0bc90..91e133a1300 100644 --- a/src/objective-c/tests/InteropTests/InteropTests.m +++ b/src/objective-c/tests/InteropTests/InteropTests.m @@ -701,21 +701,21 @@ initWithInterceptorManager:(GRPCInterceptorManager *)interceptorManager XCTAssertNotNil([[self class] host]); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"HigherResponseSizeLimit"]; + __block NSError *callError = nil; RMTSimpleRequest *request = [RMTSimpleRequest message]; const size_t kPayloadSize = 5 * 1024 * 1024; // 5MB request.responseSize = kPayloadSize; [GRPCCall setResponseSizeLimit:6 * 1024 * 1024 forHost:[[self class] host]]; - [_service unaryCallWithRequest:request handler:^(RMTSimpleResponse *response, NSError *error) { - XCTAssertNil(error, @"Finished with unexpected error: %@", error); - XCTAssertEqual(response.payload.body.length, kPayloadSize); + callError = error; [expectation fulfill]; }]; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; + XCTAssertNil(callError, @"Finished with unexpected error: %@", callError); } - (void)testClientStreamingRPC { diff --git a/src/php/README.md b/src/php/README.md index 5e9fa387636..dde6152cfce 100644 --- a/src/php/README.md +++ b/src/php/README.md @@ -294,9 +294,9 @@ Run a local server serving the math services. Please see [Node][] for how to run an example server. ```sh -$ cd grpc +$ cd grpc/src/php/tests/generated_code $ npm install -$ node src/node/test/math/math_server.js +$ node math_server.js ``` ### Run test client diff --git a/src/php/lib/Grpc/BaseStub.php b/src/php/lib/Grpc/BaseStub.php index fe81e377610..f33dbd4a80c 100644 --- a/src/php/lib/Grpc/BaseStub.php +++ b/src/php/lib/Grpc/BaseStub.php @@ -199,6 +199,13 @@ class BaseStub */ private function _get_jwt_aud_uri($method) { + // TODO(jtattermusch): This is not the correct implementation + // of extracting JWT "aud" claim. We should rely on + // grpc_metadata_credentials_plugin which + // also provides the correct value of "aud" claim + // in the grpc_auth_metadata_context.service_url field. + // Trying to do the construction of "aud" field ourselves + // is bad. $last_slash_idx = strrpos($method, '/'); if ($last_slash_idx === false) { throw new \InvalidArgumentException( @@ -213,6 +220,12 @@ class BaseStub $hostname = $this->hostname; } + // Remove the port if it is 443 + // See https://github.com/grpc/grpc/blob/07c9f7a36b2a0d34fcffebc85649cf3b8c339b5d/src/core/lib/security/transport/client_auth_filter.cc#L205 + if ((strlen($hostname) > 4) && (substr($hostname, -4) === ":443")) { + $hostname = substr($hostname, 0, -4); + } + return 'https://'.$hostname.$service_name; } @@ -228,10 +241,10 @@ class BaseStub { $metadata_copy = []; foreach ($metadata as $key => $value) { - if (!preg_match('/^[A-Za-z\d_-]+$/', $key)) { + if (!preg_match('/^[.A-Za-z\d_-]+$/', $key)) { throw new \InvalidArgumentException( 'Metadata keys must be nonempty strings containing only '. - 'alphanumeric characters, hyphens and underscores' + 'alphanumeric characters, hyphens, underscores and dots' ); } $metadata_copy[strtolower($key)] = $value; diff --git a/src/php/tests/generated_code/AbstractGeneratedCodeTest.php b/src/php/tests/generated_code/AbstractGeneratedCodeTest.php index c050a26cbf5..f7b47359992 100644 --- a/src/php/tests/generated_code/AbstractGeneratedCodeTest.php +++ b/src/php/tests/generated_code/AbstractGeneratedCodeTest.php @@ -71,6 +71,33 @@ abstract class AbstractGeneratedCodeTest extends PHPUnit_Framework_TestCase $call = self::$client->Div($div_arg, [' ' => 'abc123']); } + public function testMetadata() + { + $div_arg = new Math\DivArgs(); + $call = self::$client->Div($div_arg, ['somekey' => ['abc123']]); + } + + public function testMetadataKey() + { + $div_arg = new Math\DivArgs(); + $call = self::$client->Div($div_arg, ['somekey_-1' => ['abc123']]); + } + + public function testMetadataKeyWithDot() + { + $div_arg = new Math\DivArgs(); + $call = self::$client->Div($div_arg, ['someKEY._-1' => ['abc123']]); + } + + /** + * @expectedException InvalidArgumentException + */ + public function testMetadataInvalidKey() + { + $div_arg = new Math\DivArgs(); + $call = self::$client->Div($div_arg, ['(somekey)' => ['abc123']]); + } + public function testGetCallMetadata() { $div_arg = new Math\DivArgs(); @@ -81,6 +108,8 @@ abstract class AbstractGeneratedCodeTest extends PHPUnit_Framework_TestCase public function testTimeout() { $div_arg = new Math\DivArgs(); + $div_arg->setDividend(7); + $div_arg->setDivisor(4); $call = self::$client->Div($div_arg, [], ['timeout' => 1]); list($response, $status) = $call->wait(); $this->assertSame(\Grpc\STATUS_DEADLINE_EXCEEDED, $status->code); diff --git a/src/php/tests/generated_code/math_server.js b/src/php/tests/generated_code/math_server.js new file mode 100644 index 00000000000..1492c936e13 --- /dev/null +++ b/src/php/tests/generated_code/math_server.js @@ -0,0 +1,127 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +var PROTO_PATH = __dirname + '/../../../proto/math/math.proto'; + +var grpc = require('grpc'); +var protoLoader = require('@grpc/proto-loader'); +var packageDefinition = protoLoader.loadSync( + PROTO_PATH, + {keepCase: true, + longs: String, + enums: String, + defaults: true, + oneofs: true + }); +var math_proto = grpc.loadPackageDefinition(packageDefinition).math; + +/** + * Implements the Div RPC method. + */ +function Div(call, callback) { + var divisor = call.request.divisor; + var dividend = call.request.dividend; + if (divisor == 0) { + callback({ + code: grpc.status.INVALID_ARGUMENT, + details: 'Cannot divide by zero' + }); + } else { + setTimeout(function () { + callback(null, { + quotient: Math.floor(dividend / divisor), + remainder: dividend % divisor + }); + }, 1); // 1 millisecond, to make sure 1 microsecond timeout from test + // will hit. TODO: Consider fixing this. + } +} + +/** + * Implements the Fib RPC method. + */ +function Fib(stream) { + var previous = 0, current = 1; + for (var i = 0; i < stream.request.limit; i++) { + stream.write({ + num: current + }); + var temp = current; + current += previous; + previous = temp; + } + stream.end(); +} + +/** + * Implements the Sum RPC method. + */ +function Sum(call, callback) { + var sum = 0; + call.on('data', function(data) { + sum += parseInt(data.num); + }); + call.on('end', function() { + callback(null, { + num: sum + }); + }); +} + +/** + * Implements the DivMany RPC method. + */ +function DivMany(stream) { + stream.on('data', function(div_args) { + var divisor = div_args.divisor; + var dividend = div_args.dividend; + if (divisor == 0) { + stream.emit('error', { + code: grpc.status.INVALID_ARGUMENT, + details: 'Cannot divide by zero' + }); + } else { + stream.write({ + quotient: Math.floor(dividend / divisor), + remainder: dividend % divisor + }); + } + }); + stream.on('end', function() { + stream.end(); + }); +} + + +/** + * Starts an RPC server that receives requests for the Math service at the + * sample server port + */ +function main() { + var server = new grpc.Server(); + server.addService(math_proto.Math.service, { + Div: Div, + Fib: Fib, + Sum: Sum, + DivMany: DivMany, + }); + server.bind('0.0.0.0:50051', grpc.ServerCredentials.createInsecure()); + server.start(); +} + +main(); diff --git a/src/php/tests/generated_code/package.json b/src/php/tests/generated_code/package.json new file mode 100644 index 00000000000..5cc28be35d2 --- /dev/null +++ b/src/php/tests/generated_code/package.json @@ -0,0 +1,8 @@ +{ + "name": "grpc-examples", + "version": "0.1.0", + "dependencies": { + "@grpc/proto-loader": "^0.1.0", + "grpc": "^1.11.0" + } +} diff --git a/src/php/tests/interop/interop_client.php b/src/php/tests/interop/interop_client.php index 19cbf21bc2b..e4750475dc5 100755 --- a/src/php/tests/interop/interop_client.php +++ b/src/php/tests/interop/interop_client.php @@ -530,12 +530,7 @@ function _makeStub($args) throw new Exception('Missing argument: --test_case is required'); } - if ($args['server_port'] === '443') { - $server_address = $args['server_host']; - } else { - $server_address = $args['server_host'].':'.$args['server_port']; - } - + $server_address = $args['server_host'].':'.$args['server_port']; $test_case = $args['test_case']; $host_override = ''; diff --git a/src/python/grpcio/README.rst b/src/python/grpcio/README.rst index 07c94342de1..c7c6aa497d5 100644 --- a/src/python/grpcio/README.rst +++ b/src/python/grpcio/README.rst @@ -1,8 +1,13 @@ gRPC Python =========== +|compat_check_pypi| + Package for gRPC Python. +.. |compat_check_pypi| image:: https://python-compatibility-tools.appspot.com/one_badge_image?package=grpcio + :target: https://python-compatibility-tools.appspot.com/one_badge_target?package=grpcio + Supported Python Versions ------------------------- Python >= 3.5 diff --git a/src/python/grpcio/grpc/_channel.py b/src/python/grpcio/grpc/_channel.py index f566fd698ad..24f928ef69f 100644 --- a/src/python/grpcio/grpc/_channel.py +++ b/src/python/grpcio/grpc/_channel.py @@ -966,11 +966,6 @@ def _poll_connectivity(state, channel, initial_try_to_connect): _spawn_delivery(state, callbacks) -def _moot(state): - with state.lock: - del state.callbacks_and_connectivities[:] - - def _subscribe(state, callback, try_to_connect): with state.lock: if not state.callbacks_and_connectivities and not state.polling: @@ -1000,11 +995,6 @@ def _unsubscribe(state, callback): break -def _unsubscribe_all(state): - with state.lock: - del state.callbacks_and_connectivities[:] - - def _augment_options(base_options, compression): compression_option = _compression.create_channel_option(compression) return tuple(base_options) + compression_option + (( @@ -1071,16 +1061,21 @@ class Channel(grpc.Channel): self._channel, _channel_managed_call_management(self._call_state), _common.encode(method), request_serializer, response_deserializer) + def _unsubscribe_all(self): + state = self._connectivity_state + if state: + with state.lock: + del state.callbacks_and_connectivities[:] + def _close(self): - _unsubscribe_all(self._connectivity_state) + self._unsubscribe_all() self._channel.close(cygrpc.StatusCode.cancelled, 'Channel closed!') cygrpc.fork_unregister_channel(self) - _moot(self._connectivity_state) def _close_on_fork(self): + self._unsubscribe_all() self._channel.close_on_fork(cygrpc.StatusCode.cancelled, 'Channel closed due to fork') - _moot(self._connectivity_state) def __enter__(self): return self @@ -1102,7 +1097,9 @@ class Channel(grpc.Channel): # for as long as they are in use and to close them after using them, # then deletion of this grpc._channel.Channel instance can be made to # effect closure of the underlying cygrpc.Channel instance. - # This prevent the failed-at-initializing object removal from failing. - # Though the __init__ failed, the removal will still trigger __del__. - if _moot is not None and hasattr(self, '_connectivity_state'): - _moot(self._connectivity_state) + try: + self._unsubscribe_all() + except: # pylint: disable=bare-except + # Exceptions in __del__ are ignored by Python anyway, but they can + # keep spamming logs. Just silence them. + pass diff --git a/templates/CMakeLists.txt.template b/templates/CMakeLists.txt.template index 4057da40c16..43bc063aee5 100644 --- a/templates/CMakeLists.txt.template +++ b/templates/CMakeLists.txt.template @@ -130,6 +130,8 @@ set(_gRPC_PLATFORM_LINUX ON) elseif(<%text>${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set(_gRPC_PLATFORM_MAC ON) + elseif(<%text>${CMAKE_SYSTEM_NAME} MATCHES "iOS") + set(_gRPC_PLATFORM_IOS ON) elseif(<%text>${CMAKE_SYSTEM_NAME} MATCHES "Android") set(_gRPC_PLATFORM_ANDROID ON) else() @@ -173,7 +175,7 @@ endif() endif() - if (_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC) + if (_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_IOS) # C core has C++ source code, but should not depend on libstc++ (for better portability). # We need to use a few tricks to convince cmake to do that. # https://stackoverflow.com/questions/15058403/how-to-stop-cmake-from-linking-against-libstdc @@ -198,7 +200,7 @@ set(CMAKE_CXX_FLAGS "<%text>${CMAKE_CXX_FLAGS} -std=c++11") endif() - if(_gRPC_PLATFORM_MAC) + if(_gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_IOS) set(_gRPC_ALLTARGETS_LIBRARIES <%text>${CMAKE_DL_LIBS} m pthread) elseif(_gRPC_PLATFORM_ANDROID) set(_gRPC_ALLTARGETS_LIBRARIES <%text>${CMAKE_DL_LIBS} m) diff --git a/templates/tools/dockerfile/bazel.include b/templates/tools/dockerfile/bazel.include index 3744dacc281..272936007da 100644 --- a/templates/tools/dockerfile/bazel.include +++ b/templates/tools/dockerfile/bazel.include @@ -1,9 +1,12 @@ #======================== # Bazel installation -# Must be in sync with tools/bazel.sh +# Must be in sync with tools/bazel ENV BAZEL_VERSION 0.24.1 +# The correct bazel version is already preinstalled, no need to use //tools/bazel wrapper. +ENV DISABLE_BAZEL_WRAPPER 1 + RUN apt-get update && apt-get install -y wget && apt-get clean RUN wget "https://github.com/bazelbuild/bazel/releases/download/$BAZEL_VERSION/bazel-$BAZEL_VERSION-installer-linux-x86_64.sh" && ${'\\'} bash ./bazel-$BAZEL_VERSION-installer-linux-x86_64.sh && ${'\\'} diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_aspnetcore/build_interop.sh.template b/templates/tools/dockerfile/interoptest/grpc_interop_aspnetcore/build_interop.sh.template index 55ecfb30192..acf12579357 100644 --- a/templates/tools/dockerfile/interoptest/grpc_interop_aspnetcore/build_interop.sh.template +++ b/templates/tools/dockerfile/interoptest/grpc_interop_aspnetcore/build_interop.sh.template @@ -39,4 +39,4 @@ ln -s $(pwd)/.dotnet/dotnet /usr/local/bin/dotnet fi - dotnet build --configuration Debug Grpc.AspNetCore.sln + dotnet build --configuration Debug Grpc.DotNet.sln diff --git a/test/core/channel/channel_trace_test.cc b/test/core/channel/channel_trace_test.cc index b3c0b368982..5ac7f0871a4 100644 --- a/test/core/channel/channel_trace_test.cc +++ b/test/core/channel/channel_trace_test.cc @@ -23,6 +23,7 @@ #include #include +#include #include "src/core/lib/channel/channel_trace.h" #include "src/core/lib/channel/channelz.h" @@ -174,7 +175,7 @@ TEST(ChannelTracerTest, ComplexTest) { AddSimpleTrace(&tracer); ChannelFixture channel1(kEventListMemoryLimit); RefCountedPtr sc1 = MakeRefCounted( - channel1.channel(), kEventListMemoryLimit, true); + UniquePtr(gpr_strdup("fake_target")), kEventListMemoryLimit, 0); ChannelNodePeer sc1_peer(sc1.get()); tracer.AddTraceEventWithReference( ChannelTrace::Severity::Info, @@ -193,7 +194,7 @@ TEST(ChannelTracerTest, ComplexTest) { ValidateChannelTrace(&tracer, 5); ChannelFixture channel2(kEventListMemoryLimit); RefCountedPtr sc2 = MakeRefCounted( - channel2.channel(), kEventListMemoryLimit, true); + UniquePtr(gpr_strdup("fake_target")), kEventListMemoryLimit, 0); tracer.AddTraceEventWithReference( ChannelTrace::Severity::Info, grpc_slice_from_static_string("LB channel two created"), sc2); @@ -222,7 +223,7 @@ TEST(ChannelTracerTest, TestNesting) { ValidateChannelTrace(&tracer, 2); ChannelFixture channel1(kEventListMemoryLimit); RefCountedPtr sc1 = MakeRefCounted( - channel1.channel(), kEventListMemoryLimit, true); + UniquePtr(gpr_strdup("fake_target")), kEventListMemoryLimit, 0); ChannelNodePeer sc1_peer(sc1.get()); tracer.AddTraceEventWithReference( ChannelTrace::Severity::Info, @@ -231,7 +232,7 @@ TEST(ChannelTracerTest, TestNesting) { AddSimpleTrace(sc1_peer.trace()); ChannelFixture channel2(kEventListMemoryLimit); RefCountedPtr conn1 = MakeRefCounted( - channel2.channel(), kEventListMemoryLimit, true); + UniquePtr(gpr_strdup("fake_target")), kEventListMemoryLimit, 0); ChannelNodePeer conn1_peer(conn1.get()); // nesting one level deeper. sc1_peer.trace()->AddTraceEventWithReference( @@ -245,7 +246,7 @@ TEST(ChannelTracerTest, TestNesting) { ValidateChannelTrace(conn1_peer.trace(), 1); ChannelFixture channel3(kEventListMemoryLimit); RefCountedPtr sc2 = MakeRefCounted( - channel3.channel(), kEventListMemoryLimit, true); + UniquePtr(gpr_strdup("fake_target")), kEventListMemoryLimit, 0); tracer.AddTraceEventWithReference( ChannelTrace::Severity::Info, grpc_slice_from_static_string("subchannel two created"), sc2); diff --git a/test/core/channel/channelz_registry_test.cc b/test/core/channel/channelz_registry_test.cc index 030d52fd548..deb85d85624 100644 --- a/test/core/channel/channelz_registry_test.cc +++ b/test/core/channel/channelz_registry_test.cc @@ -43,16 +43,6 @@ namespace grpc_core { namespace channelz { namespace testing { -class ChannelzRegistryPeer { - public: - const InlinedVector* entities() { - return &ChannelzRegistry::Default()->entities_; - } - int num_empty_slots() { - return ChannelzRegistry::Default()->num_empty_slots_; - } -}; - class ChannelzRegistryTest : public ::testing::Test { protected: // ensure we always have a fresh registry for tests. @@ -115,38 +105,15 @@ TEST_F(ChannelzRegistryTest, NullIfNotPresentTest) { EXPECT_EQ(channelz_channel, retrieved); } -TEST_F(ChannelzRegistryTest, TestCompaction) { - const int kLoopIterations = 300; - // These channels that will stay in the registry for the duration of the test. - std::vector> even_channels; - even_channels.reserve(kLoopIterations); - { - // The channels will unregister themselves at the end of the for block. - std::vector> odd_channels; - odd_channels.reserve(kLoopIterations); - for (int i = 0; i < kLoopIterations; i++) { - even_channels.push_back( - MakeRefCounted(BaseNode::EntityType::kTopLevelChannel)); - odd_channels.push_back( - MakeRefCounted(BaseNode::EntityType::kTopLevelChannel)); - } - } - // without compaction, there would be exactly kLoopIterations empty slots at - // this point. However, one of the unregisters should have triggered - // compaction. - ChannelzRegistryPeer peer; - EXPECT_LT(peer.num_empty_slots(), kLoopIterations); -} - -TEST_F(ChannelzRegistryTest, TestGetAfterCompaction) { +TEST_F(ChannelzRegistryTest, TestUnregistration) { const int kLoopIterations = 100; - // These channels that will stay in the registry for the duration of the test. + // These channels will stay in the registry for the duration of the test. std::vector> even_channels; even_channels.reserve(kLoopIterations); std::vector odd_uuids; odd_uuids.reserve(kLoopIterations); { - // The channels will unregister themselves at the end of the for block. + // These channels will unregister themselves at the end of this block. std::vector> odd_channels; odd_channels.reserve(kLoopIterations); for (int i = 0; i < kLoopIterations; i++) { @@ -157,6 +124,7 @@ TEST_F(ChannelzRegistryTest, TestGetAfterCompaction) { odd_uuids.push_back(odd_channels[i]->uuid()); } } + // Check that the even channels are present and the odd channels are not. for (int i = 0; i < kLoopIterations; i++) { RefCountedPtr retrieved = ChannelzRegistry::Get(even_channels[i]->uuid()); @@ -164,27 +132,8 @@ TEST_F(ChannelzRegistryTest, TestGetAfterCompaction) { retrieved = ChannelzRegistry::Get(odd_uuids[i]); EXPECT_EQ(retrieved, nullptr); } -} - -TEST_F(ChannelzRegistryTest, TestAddAfterCompaction) { - const int kLoopIterations = 100; - // These channels that will stay in the registry for the duration of the test. - std::vector> even_channels; - even_channels.reserve(kLoopIterations); - std::vector odd_uuids; - odd_uuids.reserve(kLoopIterations); - { - // The channels will unregister themselves at the end of the for block. - std::vector> odd_channels; - odd_channels.reserve(kLoopIterations); - for (int i = 0; i < kLoopIterations; i++) { - even_channels.push_back( - MakeRefCounted(BaseNode::EntityType::kTopLevelChannel)); - odd_channels.push_back( - MakeRefCounted(BaseNode::EntityType::kTopLevelChannel)); - odd_uuids.push_back(odd_channels[i]->uuid()); - } - } + // Add more channels and verify that they get added correctly, to make + // sure that the unregistration didn't leave the registry in a weird state. std::vector> more_channels; more_channels.reserve(kLoopIterations); for (int i = 0; i < kLoopIterations; i++) { diff --git a/test/core/channel/channelz_test.cc b/test/core/channel/channelz_test.cc index abd1601ad14..7c55f9ffe0f 100644 --- a/test/core/channel/channelz_test.cc +++ b/test/core/channel/channelz_test.cc @@ -486,8 +486,7 @@ TEST_F(ChannelzRegistryBasedTest, InternalChannelTest) { (void)channels; // suppress unused variable error // create an internal channel grpc_arg client_a[2]; - client_a[0] = grpc_channel_arg_integer_create( - const_cast(GRPC_ARG_CHANNELZ_CHANNEL_IS_INTERNAL_CHANNEL), true); + client_a[0] = grpc_core::channelz::MakeParentUuidArg(1); client_a[1] = grpc_channel_arg_integer_create( const_cast(GRPC_ARG_ENABLE_CHANNELZ), true); grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a}; diff --git a/test/core/gprpp/inlined_vector_test.cc b/test/core/gprpp/inlined_vector_test.cc index f943128f53c..4b7e46761c0 100644 --- a/test/core/gprpp/inlined_vector_test.cc +++ b/test/core/gprpp/inlined_vector_test.cc @@ -109,6 +109,24 @@ TEST(InlinedVectorTest, ConstIndexOperator) { const_func(v); } +TEST(InlinedVectorTest, EqualOperator) { + constexpr int kNumElements = 10; + // Both v1 and v2 are empty. + InlinedVector v1; + InlinedVector v2; + EXPECT_TRUE(v1 == v2); + // Both v1 and v2 contains the same data. + FillVector(&v1, kNumElements); + FillVector(&v2, kNumElements); + EXPECT_TRUE(v1 == v2); + // The sizes of v1 and v2 are different. + v1.push_back(0); + EXPECT_FALSE(v1 == v2); + // The contents of v1 and v2 are different although their sizes are the same. + v2.push_back(1); + EXPECT_FALSE(v1 == v2); +} + // the following constants and typedefs are used for copy/move // construction/assignment const size_t kInlinedLength = 8; diff --git a/test/core/gprpp/map_test.cc b/test/core/gprpp/map_test.cc index 6e70a2a2ac2..21aeee82486 100644 --- a/test/core/gprpp/map_test.cc +++ b/test/core/gprpp/map_test.cc @@ -419,6 +419,53 @@ TEST_F(MapTest, RandomOpsWithIntKey) { EXPECT_TRUE(test_map.empty()); } +// Tests lower_bound(). +TEST_F(MapTest, LowerBound) { + Map test_map; + for (int i = 0; i < 10; i += 2) { + test_map.emplace(i, Payload(i)); + } + auto it = test_map.lower_bound(-1); + EXPECT_EQ(it, test_map.begin()); + it = test_map.lower_bound(0); + EXPECT_EQ(it, test_map.begin()); + it = test_map.lower_bound(2); + EXPECT_EQ(it->first, 2); + it = test_map.lower_bound(3); + EXPECT_EQ(it->first, 4); + it = test_map.lower_bound(9); + EXPECT_EQ(it, test_map.end()); +} + +// Test move ctor +TEST_F(MapTest, MoveCtor) { + Map test_map; + for (int i = 0; i < 5; i++) { + test_map.emplace(kKeys[i], Payload(i)); + } + Map test_map2 = std::move(test_map); + for (int i = 0; i < 5; i++) { + EXPECT_EQ(test_map.end(), test_map.find(kKeys[i])); + EXPECT_EQ(i, test_map2.find(kKeys[i])->second.data()); + } +} + +// Test move assignment +TEST_F(MapTest, MoveAssignment) { + Map test_map; + for (int i = 0; i < 5; i++) { + test_map.emplace(kKeys[i], Payload(i)); + } + Map test_map2; + test_map2.emplace("xxx", Payload(123)); + test_map2 = std::move(test_map); + for (int i = 0; i < 5; i++) { + EXPECT_EQ(test_map.end(), test_map.find(kKeys[i])); + EXPECT_EQ(i, test_map2.find(kKeys[i])->second.data()); + } + EXPECT_EQ(test_map2.end(), test_map2.find("xxx")); +} + } // namespace testing } // namespace grpc_core diff --git a/test/core/slice/slice_test.cc b/test/core/slice/slice_test.cc index 6ed02366fe2..4f824cbd5ad 100644 --- a/test/core/slice/slice_test.cc +++ b/test/core/slice/slice_test.cc @@ -27,6 +27,7 @@ #include #include +#include "src/core/lib/gprpp/memory.h" #include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/transport/static_metadata.h" #include "test/core/util/test_config.h" @@ -285,6 +286,44 @@ static void test_static_slice_copy_interning(void) { grpc_shutdown(); } +static void test_moved_string_slice(void) { + LOG_TEST_NAME("test_moved_string_slice"); + + grpc_init(); + + // Small string should be inlined. + constexpr char kSmallStr[] = "hello12345"; + char* small_ptr = strdup(kSmallStr); + grpc_slice small = + grpc_slice_from_moved_string(grpc_core::UniquePtr(small_ptr)); + GPR_ASSERT(GRPC_SLICE_LENGTH(small) == strlen(kSmallStr)); + GPR_ASSERT(GRPC_SLICE_START_PTR(small) != + reinterpret_cast(small_ptr)); + grpc_slice_unref(small); + + // Large string should be move the reference. + constexpr char kSLargeStr[] = "hello123456789123456789123456789"; + char* large_ptr = strdup(kSLargeStr); + grpc_slice large = + grpc_slice_from_moved_string(grpc_core::UniquePtr(large_ptr)); + GPR_ASSERT(GRPC_SLICE_LENGTH(large) == strlen(kSLargeStr)); + GPR_ASSERT(GRPC_SLICE_START_PTR(large) == + reinterpret_cast(large_ptr)); + grpc_slice_unref(large); + + // Moved buffer must respect the provided length not the actual length of the + // string. + large_ptr = strdup(kSLargeStr); + small = grpc_slice_from_moved_buffer(grpc_core::UniquePtr(large_ptr), + strlen(kSmallStr)); + GPR_ASSERT(GRPC_SLICE_LENGTH(small) == strlen(kSmallStr)); + GPR_ASSERT(GRPC_SLICE_START_PTR(small) != + reinterpret_cast(large_ptr)); + grpc_slice_unref(small); + + grpc_shutdown(); +} + int main(int argc, char** argv) { unsigned length; grpc::testing::TestEnvironment env(argc, argv); @@ -302,6 +341,7 @@ int main(int argc, char** argv) { test_slice_interning(); test_static_slice_interning(); test_static_slice_copy_interning(); + test_moved_string_slice(); grpc_shutdown(); return 0; } diff --git a/test/core/util/test_lb_policies.cc b/test/core/util/test_lb_policies.cc index ced6d9d8027..041ce1f45a1 100644 --- a/test/core/util/test_lb_policies.cc +++ b/test/core/util/test_lb_policies.cc @@ -72,12 +72,6 @@ class ForwardingLoadBalancingPolicy : public LoadBalancingPolicy { void ResetBackoffLocked() override { delegate_->ResetBackoffLocked(); } - void FillChildRefsForChannelz( - channelz::ChildRefsList* child_subchannels, - channelz::ChildRefsList* child_channels) override { - delegate_->FillChildRefsForChannelz(child_subchannels, child_channels); - } - private: void ShutdownLocked() override { delegate_.reset(); } @@ -123,7 +117,7 @@ class InterceptRecvTrailingMetadataLoadBalancingPolicy PickResult Pick(PickArgs args) override { PickResult result = delegate_picker_->Pick(args); if (result.type == PickResult::PICK_COMPLETE && - result.connected_subchannel != nullptr) { + result.subchannel != nullptr) { new (args.call_state->Alloc(sizeof(TrailingMetadataHandler))) TrailingMetadataHandler(&result, cb_, user_data_); } @@ -164,6 +158,10 @@ class InterceptRecvTrailingMetadataLoadBalancingPolicy parent_->channel_control_helper()->RequestReresolution(); } + void AddTraceEvent(TraceSeverity severity, const char* message) override { + parent_->channel_control_helper()->AddTraceEvent(severity, message); + } + private: RefCountedPtr parent_; InterceptRecvTrailingMetadataCallback cb_; diff --git a/test/cpp/codegen/compiler_test_golden b/test/cpp/codegen/compiler_test_golden index 761c3ac6106..64ab123123b 100644 --- a/test/cpp/codegen/compiler_test_golden +++ b/test/cpp/codegen/compiler_test_golden @@ -43,6 +43,7 @@ namespace grpc_impl { class CompletionQueue; class ServerCompletionQueue; +class ServerContext; } // namespace grpc_impl namespace grpc { @@ -50,7 +51,6 @@ namespace experimental { template class MessageAllocator; } // namespace experimental -class ServerContext; } // namespace grpc namespace grpc { diff --git a/test/cpp/end2end/cfstream_test.cc b/test/cpp/end2end/cfstream_test.cc index 59cf98ffc20..1c9320861fd 100644 --- a/test/cpp/end2end/cfstream_test.cc +++ b/test/cpp/end2end/cfstream_test.cc @@ -42,6 +42,7 @@ #include "src/core/lib/gpr/env.h" #include "src/proto/grpc/testing/echo.grpc.pb.h" +#include "test/core/util/debugger_macros.h" #include "test/core/util/port.h" #include "test/core/util/test_config.h" #include "test/cpp/end2end/test_service_impl.h" @@ -144,6 +145,18 @@ class CFStreamTest : public ::testing::TestWithParam { return CreateCustomChannel(server_address.str(), channel_creds, args); } + int GetStreamID(ClientContext& context) { + int stream_id = 0; + grpc_call* call = context.c_call(); + if (call) { + grpc_chttp2_stream* stream = grpc_chttp2_stream_from_call(call); + if (stream) { + stream_id = stream->id; + } + } + return stream_id; + } + void SendRpc( const std::unique_ptr& stub, bool expect_success = false) { @@ -153,10 +166,13 @@ class CFStreamTest : public ::testing::TestWithParam { request.set_message(msg); ClientContext context; Status status = stub->Echo(&context, request, response.get()); + int stream_id = GetStreamID(context); if (status.ok()) { + gpr_log(GPR_DEBUG, "RPC with stream_id %d succeeded", stream_id); EXPECT_EQ(msg, response->message()); } else { - gpr_log(GPR_DEBUG, "RPC failed: %s", status.error_message().c_str()); + gpr_log(GPR_DEBUG, "RPC with stream_id %d failed: %s", stream_id, + status.error_message().c_str()); } if (expect_success) { EXPECT_TRUE(status.ok()); @@ -341,7 +357,9 @@ TEST_P(CFStreamTest, NetworkFlapRpcsInFlight) { // Channel should be in READY state after we send some RPCs for (int i = 0; i < 10; ++i) { - SendAsyncRpc(stub); + RequestParams param; + param.set_skip_cancelled_check(true); + SendAsyncRpc(stub, param); ++rpcs_sent; } EXPECT_TRUE(WaitForChannelReady(channel.get())); @@ -359,14 +377,17 @@ TEST_P(CFStreamTest, NetworkFlapRpcsInFlight) { ++total_completions; GPR_ASSERT(ok); AsyncClientCall* call = static_cast(got_tag); + int stream_id = GetStreamID(call->context); if (!call->status.ok()) { - gpr_log(GPR_DEBUG, "RPC failed with error: %s", - call->status.error_message().c_str()); + gpr_log(GPR_DEBUG, "RPC with stream_id %d failed with error: %s", + stream_id, call->status.error_message().c_str()); // Bring network up when RPCs start failing if (network_down) { NetworkUp(); network_down = false; } + } else { + gpr_log(GPR_DEBUG, "RPC with stream_id %d succeeded", stream_id); } delete call; } @@ -374,7 +395,9 @@ TEST_P(CFStreamTest, NetworkFlapRpcsInFlight) { }); for (int i = 0; i < 100; ++i) { - SendAsyncRpc(stub); + RequestParams param; + param.set_skip_cancelled_check(true); + SendAsyncRpc(stub, param); std::this_thread::sleep_for(std::chrono::milliseconds(10)); ++rpcs_sent; } @@ -393,21 +416,19 @@ TEST_P(CFStreamTest, ConcurrentRpc) { std::thread thd = std::thread([this, &rpcs_sent]() { void* got_tag; bool ok = false; - bool network_down = true; int total_completions = 0; while (CQNext(&got_tag, &ok)) { ++total_completions; GPR_ASSERT(ok); AsyncClientCall* call = static_cast(got_tag); + int stream_id = GetStreamID(call->context); if (!call->status.ok()) { - gpr_log(GPR_DEBUG, "RPC failed: %s", - call->status.error_message().c_str()); + gpr_log(GPR_DEBUG, "RPC with stream_id %d failed with error: %s", + stream_id, call->status.error_message().c_str()); // Bring network up when RPCs start failing - if (network_down) { - NetworkUp(); - network_down = false; - } + } else { + gpr_log(GPR_DEBUG, "RPC with stream_id %d succeeded", stream_id); } delete call; } diff --git a/test/cpp/end2end/channelz_service_test.cc b/test/cpp/end2end/channelz_service_test.cc index 26ef59fbeb3..69c56c574f9 100644 --- a/test/cpp/end2end/channelz_service_test.cc +++ b/test/cpp/end2end/channelz_service_test.cc @@ -163,13 +163,12 @@ class ChannelzServerTest : public ::testing::Test { } std::unique_ptr NewEchoStub() { - static int salt = 0; string target = "dns:localhost:" + to_string(proxy_port_); ChannelArguments args; // disable channelz. We only want to focus on proxy to backend outbound. args.SetInt(GRPC_ARG_ENABLE_CHANNELZ, 0); // This ensures that gRPC will not do connection sharing. - args.SetInt("salt", salt++); + args.SetInt(GRPC_ARG_USE_LOCAL_SUBCHANNEL_POOL, true); std::shared_ptr channel = ::grpc::CreateCustomChannel(target, InsecureChannelCredentials(), args); return grpc::testing::EchoTestService::NewStub(channel); diff --git a/test/cpp/qps/client_async.cc b/test/cpp/qps/client_async.cc index bad24cf04a2..059dc4f9002 100644 --- a/test/cpp/qps/client_async.cc +++ b/test/cpp/qps/client_async.cc @@ -479,7 +479,7 @@ class ClientRpcContextStreamingPingPongImpl : public ClientRpcContext { next_state_ = State::STREAM_IDLE; stream_->StartCall(ClientRpcContext::tag(this)); if (coalesce_) { - // When the intial metadata is corked, the tag will not come back and we + // When the initial metadata is corked, the tag will not come back and we // need to manually drive the state machine. RunNextState(true, nullptr); } diff --git a/test/cpp/util/cli_call.h b/test/cpp/util/cli_call.h index 3f279095a42..65144a1892c 100644 --- a/test/cpp/util/cli_call.h +++ b/test/cpp/util/cli_call.h @@ -27,9 +27,11 @@ #include #include -namespace grpc { +namespace grpc_impl { class ClientContext; +} // namespace grpc_impl +namespace grpc { namespace testing { @@ -85,7 +87,7 @@ class CliCall final { private: std::unique_ptr stub_; - grpc::ClientContext ctx_; + grpc_impl::ClientContext ctx_; std::unique_ptr call_; grpc::CompletionQueue cq_; gpr_mu write_mu_; diff --git a/tools/bazel.sh b/tools/bazel similarity index 55% rename from tools/bazel.sh rename to tools/bazel index b0508bddbd9..4f08d18c656 100755 --- a/tools/bazel.sh +++ b/tools/bazel @@ -19,17 +19,28 @@ # supported version, and then calling it. This way, we can make sure # that running bazel will always get meaningful results, at least # until Bazel 1.0 is released. +# NOTE: This script relies on bazel's feature where //tools/bazel +# script can be used to hijack "bazel" invocations in given workspace. set -e +# First of all, if DISABLE_BAZEL_WRAPPER is set, just use BAZEL_REAL as set by +# https://github.com/bazelbuild/bazel/blob/master/scripts/packages/bazel.sh +# that originally invoked this script. +if [ "${BAZEL_REAL}" != "" ] && [ "${DISABLE_BAZEL_WRAPPER}" != "" ] +then + exec -a "$0" "${BAZEL_REAL}" "$@" +fi + VERSION=0.26.0 -CWD=`pwd` +echo "INFO: Running bazel wrapper (see //tools/bazel for details), bazel version $VERSION will be used instead of system-wide bazel installation." + BASEURL=https://github.com/bazelbuild/bazel/releases/download/ -cd `dirname $0` -TOOLDIR=`pwd` +pushd "$(dirname "$0")" >/dev/null +TOOLDIR=$(pwd) -case `uname -sm` in +case $(uname -sm) in "Linux x86_64") suffix=linux-x86_64 ;; @@ -37,17 +48,17 @@ case `uname -sm` in suffix=darwin-x86_64 ;; *) - echo "Unsupported architecture: `uname -sm`" + echo "Unsupported architecture: $(uname -sm)" exit 1 ;; esac -filename=bazel-$VERSION-$suffix +filename="bazel-$VERSION-$suffix" -if [ ! -x $filename ] ; then - curl -L $BASEURL/$VERSION/$filename > $filename - chmod a+x $filename +if [ ! -x "$filename" ] ; then + curl -L "$BASEURL/$VERSION/$filename" > "$filename" + chmod a+x "$filename" fi -cd $CWD -$TOOLDIR/$filename $@ +popd >/dev/null +exec "$TOOLDIR/$filename" "$@" diff --git a/tools/dockerfile/interoptest/grpc_interop_aspnetcore/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_aspnetcore/build_interop.sh index 0b32638b54b..acb2a0ab2d9 100644 --- a/tools/dockerfile/interoptest/grpc_interop_aspnetcore/build_interop.sh +++ b/tools/dockerfile/interoptest/grpc_interop_aspnetcore/build_interop.sh @@ -37,4 +37,4 @@ then ln -s $(pwd)/.dotnet/dotnet /usr/local/bin/dotnet fi -dotnet build --configuration Debug Grpc.AspNetCore.sln +dotnet build --configuration Debug Grpc.DotNet.sln diff --git a/tools/dockerfile/test/bazel/Dockerfile b/tools/dockerfile/test/bazel/Dockerfile index b9fc409d939..df7a7a2f32a 100644 --- a/tools/dockerfile/test/bazel/Dockerfile +++ b/tools/dockerfile/test/bazel/Dockerfile @@ -51,9 +51,12 @@ RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 t #======================== # Bazel installation -# Must be in sync with tools/bazel.sh +# Must be in sync with tools/bazel ENV BAZEL_VERSION 0.24.1 +# The correct bazel version is already preinstalled, no need to use //tools/bazel wrapper. +ENV DISABLE_BAZEL_WRAPPER 1 + RUN apt-get update && apt-get install -y wget && apt-get clean RUN wget "https://github.com/bazelbuild/bazel/releases/download/$BAZEL_VERSION/bazel-$BAZEL_VERSION-installer-linux-x86_64.sh" && \ bash ./bazel-$BAZEL_VERSION-installer-linux-x86_64.sh && \ diff --git a/tools/dockerfile/test/sanity/Dockerfile b/tools/dockerfile/test/sanity/Dockerfile index 4ef4a0a9454..9a080d0efb2 100644 --- a/tools/dockerfile/test/sanity/Dockerfile +++ b/tools/dockerfile/test/sanity/Dockerfile @@ -97,9 +97,12 @@ ENV CLANG_TIDY=clang-tidy #======================== # Bazel installation -# Must be in sync with tools/bazel.sh +# Must be in sync with tools/bazel ENV BAZEL_VERSION 0.24.1 +# The correct bazel version is already preinstalled, no need to use //tools/bazel wrapper. +ENV DISABLE_BAZEL_WRAPPER 1 + RUN apt-get update && apt-get install -y wget && apt-get clean RUN wget "https://github.com/bazelbuild/bazel/releases/download/$BAZEL_VERSION/bazel-$BAZEL_VERSION-installer-linux-x86_64.sh" && \ bash ./bazel-$BAZEL_VERSION-installer-linux-x86_64.sh && \ diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++ index 913d7be993b..466bb5cd5a3 100644 --- a/tools/doxygen/Doxyfile.c++ +++ b/tools/doxygen/Doxyfile.c++ @@ -956,6 +956,7 @@ include/grpcpp/impl/codegen/callback_common.h \ include/grpcpp/impl/codegen/channel_interface.h \ include/grpcpp/impl/codegen/client_callback.h \ include/grpcpp/impl/codegen/client_context.h \ +include/grpcpp/impl/codegen/client_context_impl.h \ include/grpcpp/impl/codegen/client_interceptor.h \ include/grpcpp/impl/codegen/client_unary_call.h \ include/grpcpp/impl/codegen/completion_queue.h \ @@ -982,6 +983,7 @@ include/grpcpp/impl/codegen/security/auth_context.h \ include/grpcpp/impl/codegen/serialization_traits.h \ include/grpcpp/impl/codegen/server_callback.h \ include/grpcpp/impl/codegen/server_context.h \ +include/grpcpp/impl/codegen/server_context_impl.h \ include/grpcpp/impl/codegen/server_interceptor.h \ include/grpcpp/impl/codegen/server_interface.h \ include/grpcpp/impl/codegen/service_type.h \ diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 8b664d8ac01..9b0f8f9fcd7 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -957,6 +957,7 @@ include/grpcpp/impl/codegen/callback_common.h \ include/grpcpp/impl/codegen/channel_interface.h \ include/grpcpp/impl/codegen/client_callback.h \ include/grpcpp/impl/codegen/client_context.h \ +include/grpcpp/impl/codegen/client_context_impl.h \ include/grpcpp/impl/codegen/client_interceptor.h \ include/grpcpp/impl/codegen/client_unary_call.h \ include/grpcpp/impl/codegen/completion_queue.h \ @@ -984,6 +985,7 @@ include/grpcpp/impl/codegen/security/auth_context.h \ include/grpcpp/impl/codegen/serialization_traits.h \ include/grpcpp/impl/codegen/server_callback.h \ include/grpcpp/impl/codegen/server_context.h \ +include/grpcpp/impl/codegen/server_context_impl.h \ include/grpcpp/impl/codegen/server_interceptor.h \ include/grpcpp/impl/codegen/server_interface.h \ include/grpcpp/impl/codegen/service_type.h \ diff --git a/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh b/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh index bcde79ecd8e..5a358acc09d 100755 --- a/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh +++ b/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh @@ -21,7 +21,7 @@ cd $(dirname $0)/../../.. source tools/internal_ci/helper_scripts/prepare_build_linux_rc # make sure bazel is available -tools/bazel.sh version +tools/bazel version # to get "bazel" link for kokoro build, we need to generate # invocation UUID, set a flag for bazel to use it @@ -29,7 +29,7 @@ tools/bazel.sh version BAZEL_INVOCATION_ID="$(uuidgen)" echo "${BAZEL_INVOCATION_ID}" >"${KOKORO_ARTIFACTS_DIR}/bazel_invocation_ids" -tools/bazel.sh \ +tools/bazel \ --bazelrc=tools/remote_build/kokoro.bazelrc \ test \ --invocation_id="${BAZEL_INVOCATION_ID}" \ diff --git a/tools/internal_ci/linux/grpc_bazel_rbe_incompatible_changes.sh b/tools/internal_ci/linux/grpc_bazel_rbe_incompatible_changes.sh index 9c3712a07da..85b82443bcd 100644 --- a/tools/internal_ci/linux/grpc_bazel_rbe_incompatible_changes.sh +++ b/tools/internal_ci/linux/grpc_bazel_rbe_incompatible_changes.sh @@ -15,9 +15,14 @@ set -ex -# TODO(jtattermusch): use the latest version of bazel +# Use bazelisk to download the right bazel version +wget https://github.com/bazelbuild/bazelisk/releases/download/v0.0.7/bazelisk-linux-amd64 +chmod u+x bazelisk-linux-amd64 -# Use --all_incompatible_changes to give an early warning about future -# bazel incompatibilities. -EXTRA_FLAGS="--config=opt --cache_test_results=no --all_incompatible_changes" +# We want bazelisk to run the latest stable version +export USE_BAZEL_VERSION=latest +# Use bazelisk instead of our usual //tools/bazel wrapper +mv bazelisk-linux-amd64 github/grpc/tools/bazel + +EXTRA_FLAGS="--config=opt --cache_test_results=no" github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh "${EXTRA_FLAGS}" diff --git a/tools/internal_ci/macos/grpc_interop.cfg b/tools/internal_ci/linux/pull_request/grpc_basictests_c_cpp_build_only.cfg similarity index 75% rename from tools/internal_ci/macos/grpc_interop.cfg rename to tools/internal_ci/linux/pull_request/grpc_basictests_c_cpp_build_only.cfg index 434ecd19c4d..0eb27206eeb 100644 --- a/tools/internal_ci/macos/grpc_interop.cfg +++ b/tools/internal_ci/linux/pull_request/grpc_basictests_c_cpp_build_only.cfg @@ -1,4 +1,4 @@ -# Copyright 2017 gRPC authors. +# Copyright 2019 The gRPC Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,12 +15,16 @@ # Config file for the internal CI (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc/tools/internal_ci/macos/grpc_interop.sh" -gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" -timeout_mins: 240 +build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh" +timeout_mins: 60 action { define_artifacts { regex: "**/*sponge_log.*" regex: "github/grpc/reports/**" } } + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests linux corelang --inner_jobs 16 -j 1 --internal_ci --build_only" +} diff --git a/tools/internal_ci/macos/grpc_interop.sh b/tools/internal_ci/macos/grpc_interop.sh deleted file mode 100755 index e290ed60c47..00000000000 --- a/tools/internal_ci/macos/grpc_interop.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash -# Copyright 2017 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -ex - -# change to grpc repo root -cd $(dirname $0)/../../.. - -source tools/internal_ci/helper_scripts/prepare_build_macos_interop_rc -source tools/internal_ci/helper_scripts/prepare_build_macos_rc - -tools/run_tests/run_interop_tests.py -l objc -s all --use_docker -t -j 1 || FAILED="true" - -tools/internal_ci/helper_scripts/delete_nonartifacts.sh || true - -if [ "$FAILED" != "" ] -then - exit 1 -fi diff --git a/tools/internal_ci/macos/grpc_interop_toprod.sh b/tools/internal_ci/macos/grpc_interop_toprod.sh index 36e5a2103d9..13bf58ad1b2 100755 --- a/tools/internal_ci/macos/grpc_interop_toprod.sh +++ b/tools/internal_ci/macos/grpc_interop_toprod.sh @@ -34,6 +34,7 @@ tools/run_tests/run_interop_tests.py -l c++ \ --google_default_creds_use_key_file \ --prod_servers default gateway_v4 \ --service_account_key_file="${KOKORO_KEYSTORE_DIR}/73836_interop_to_prod_tests_service_account_key" \ + --default_service_account="interop-to-prod-tests@grpc-testing.iam.gserviceaccount.com" \ --skip_compute_engine_creds --internal_ci -t -j 4 || FAILED="true" tools/internal_ci/helper_scripts/delete_nonartifacts.sh || true diff --git a/tools/internal_ci/windows/bazel_rbe.bat b/tools/internal_ci/windows/bazel_rbe.bat index 30c66896edf..8abab687ed2 100644 --- a/tools/internal_ci/windows/bazel_rbe.bat +++ b/tools/internal_ci/windows/bazel_rbe.bat @@ -13,7 +13,7 @@ @rem limitations under the License. @rem TODO(jtattermusch): make this generate less output -@rem TODO(jtattermusch): use tools/bazel.sh script to keep the versions in sync +@rem TODO(jtattermusch): use tools/bazel script to keep the versions in sync choco install bazel -y --version 0.24.1 --limit-output cd github/grpc diff --git a/tools/remote_build/README.md b/tools/remote_build/README.md index 4cc3c7a0ea1..2cd5f03daf1 100644 --- a/tools/remote_build/README.md +++ b/tools/remote_build/README.md @@ -17,27 +17,22 @@ and tests run by Kokoro CI. ## Running remote build manually from dev workstation -*At the time being, tools/bazel.sh is used instead of invoking "bazel" directly -to overcome the bazel versioning problem (our BUILD files currently only work with -a specific window of bazel version and bazel.sh wrapper makes sure that version -is used).* - Run from repository root (opt, dbg): ``` # manual run of bazel tests remotely on Foundry -tools/bazel.sh --bazelrc=tools/remote_build/manual.bazelrc test --config=opt //test/... +bazel --bazelrc=tools/remote_build/manual.bazelrc test --config=opt //test/... ``` Sanitizer runs (asan, msan, tsan, ubsan): ``` # manual run of bazel tests remotely on Foundry with given sanitizer -tools/bazel.sh --bazelrc=tools/remote_build/manual.bazelrc test --config=asan //test/... +bazel --bazelrc=tools/remote_build/manual.bazelrc test --config=asan //test/... ``` Run on Windows MSVC: ``` # RBE manual run only for c-core (must be run on a Windows host machine) -tools/bazel.sh --bazelrc=tools/remote_build/windows.bazelrc build :all [--credentials_json=(path to service account credentials)] +bazel --bazelrc=tools/remote_build/windows.bazelrc build :all [--credentials_json=(path to service account credentials)] ``` Available command line options can be found in diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index a479a00509a..0da1dc36ff9 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -10130,6 +10130,7 @@ "include/grpcpp/impl/codegen/channel_interface.h", "include/grpcpp/impl/codegen/client_callback.h", "include/grpcpp/impl/codegen/client_context.h", + "include/grpcpp/impl/codegen/client_context_impl.h", "include/grpcpp/impl/codegen/client_interceptor.h", "include/grpcpp/impl/codegen/client_unary_call.h", "include/grpcpp/impl/codegen/completion_queue.h", @@ -10151,6 +10152,7 @@ "include/grpcpp/impl/codegen/serialization_traits.h", "include/grpcpp/impl/codegen/server_callback.h", "include/grpcpp/impl/codegen/server_context.h", + "include/grpcpp/impl/codegen/server_context_impl.h", "include/grpcpp/impl/codegen/server_interceptor.h", "include/grpcpp/impl/codegen/server_interface.h", "include/grpcpp/impl/codegen/service_type.h", @@ -10208,6 +10210,7 @@ "include/grpcpp/impl/codegen/channel_interface.h", "include/grpcpp/impl/codegen/client_callback.h", "include/grpcpp/impl/codegen/client_context.h", + "include/grpcpp/impl/codegen/client_context_impl.h", "include/grpcpp/impl/codegen/client_interceptor.h", "include/grpcpp/impl/codegen/client_unary_call.h", "include/grpcpp/impl/codegen/completion_queue.h", @@ -10229,6 +10232,7 @@ "include/grpcpp/impl/codegen/serialization_traits.h", "include/grpcpp/impl/codegen/server_callback.h", "include/grpcpp/impl/codegen/server_context.h", + "include/grpcpp/impl/codegen/server_context_impl.h", "include/grpcpp/impl/codegen/server_interceptor.h", "include/grpcpp/impl/codegen/server_interface.h", "include/grpcpp/impl/codegen/service_type.h", diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py index 96e5ee340fc..e71d308dcbe 100755 --- a/tools/run_tests/run_interop_tests.py +++ b/tools/run_tests/run_interop_tests.py @@ -807,23 +807,17 @@ def compute_engine_creds_required(language, test_case): return False -def auth_options(language, - test_case, - google_default_creds_use_key_file, - service_account_key_file=None): +def auth_options(language, test_case, google_default_creds_use_key_file, + service_account_key_file, default_service_account): """Returns (cmdline, env) tuple with cloud_to_prod_auth test options.""" language = str(language) cmdargs = [] env = {} - if not service_account_key_file: - # this file path only works inside docker - service_account_key_file = '/root/service_account/grpc-testing-ebe7c1ac7381.json' oauth_scope_arg = '--oauth_scope=https://www.googleapis.com/auth/xapi.zoo' key_file_arg = '--service_account_key_file=%s' % service_account_key_file - # default compute engine credentials associated with the testing VMs in "grpc-testing" cloud project - default_account_arg = '--default_service_account=830293263384-compute@developer.gserviceaccount.com' + default_account_arg = '--default_service_account=%s' % default_service_account if test_case in ['jwt_token_creds', 'per_rpc_creds', 'oauth2_auth_token']: if language in [ @@ -874,6 +868,7 @@ def cloud_to_prod_jobspec(language, auth=False, manual_cmd_log=None, service_account_key_file=None, + default_service_account=None, transport_security='tls'): """Creates jobspec for cloud-to-prod interop test""" container_name = None @@ -901,9 +896,9 @@ def cloud_to_prod_jobspec(language, cmdargs = cmdargs + transport_security_options environ = dict(language.cloud_to_prod_env(), **language.global_env()) if auth: - auth_cmdargs, auth_env = auth_options(language, test_case, - google_default_creds_use_key_file, - service_account_key_file) + auth_cmdargs, auth_env = auth_options( + language, test_case, google_default_creds_use_key_file, + service_account_key_file, default_service_account) cmdargs += auth_cmdargs environ.update(auth_env) cmdline = bash_cmdline(language.client_cmd(cmdargs)) @@ -1212,12 +1207,17 @@ argp.add_argument( help= 'Use servername=HOST:PORT to explicitly specify a server. E.g. csharp=localhost:50000', default=[]) +# TODO(jtattermusch): the default service_account_key_file only works when --use_docker is used. argp.add_argument( '--service_account_key_file', type=str, - help= - 'Override the default service account key file to use for auth interop tests.', - default=None) + help='The service account key file to use for some auth interop tests.', + default='/root/service_account/grpc-testing-ebe7c1ac7381.json') +argp.add_argument( + '--default_service_account', + type=str, + help='Default GCE service account email to use for some auth interop tests.', + default='830293263384-compute@developer.gserviceaccount.com') argp.add_argument( '-t', '--travis', default=False, action='store_const', const=True) argp.add_argument( @@ -1470,6 +1470,8 @@ try: manual_cmd_log=client_manual_cmd_log, service_account_key_file=args. service_account_key_file, + default_service_account=args. + default_service_account, transport_security=transport_security) jobs.append(test_job) if args.http2_interop: @@ -1484,6 +1486,7 @@ try: docker_image=docker_images.get(str(http2Interop)), manual_cmd_log=client_manual_cmd_log, service_account_key_file=args.service_account_key_file, + default_service_account=args.default_service_account, transport_security=args.transport_security) jobs.append(test_job) @@ -1517,6 +1520,8 @@ try: manual_cmd_log=client_manual_cmd_log, service_account_key_file=args. service_account_key_file, + default_service_account=args. + default_service_account, transport_security=transport_security) jobs.append(test_job) for server in args.override_server: