From b69f1f6aacad86bdc72e25085d74e64f17f32195 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Wed, 9 May 2018 10:38:44 -0700 Subject: [PATCH 01/57] Update channelz proto --- src/core/lib/channel/channel_trace.cc | 2 +- src/proto/grpc/channelz/channelz.proto | 143 ++++++++++++++------ test/core/channel/channel_trace_test.cc | 2 +- test/cpp/util/channel_trace_proto_helper.cc | 4 +- 4 files changed, 106 insertions(+), 45 deletions(-) diff --git a/src/core/lib/channel/channel_trace.cc b/src/core/lib/channel/channel_trace.cc index eb7214b3557..84f7f000f72 100644 --- a/src/core/lib/channel/channel_trace.cc +++ b/src/core/lib/channel/channel_trace.cc @@ -219,7 +219,7 @@ char* ChannelTrace::RenderTrace() const { grpc_json_create_child(json_iterator, json, "numEventsLogged", num_events_logged_str, GRPC_JSON_STRING, true); json_iterator = - grpc_json_create_child(json_iterator, json, "creationTime", + grpc_json_create_child(json_iterator, json, "creationTimestamp", fmt_time(time_created_), GRPC_JSON_STRING, true); grpc_json* events = grpc_json_create_child(json_iterator, json, "events", nullptr, GRPC_JSON_ARRAY, false); diff --git a/src/proto/grpc/channelz/channelz.proto b/src/proto/grpc/channelz/channelz.proto index 14db66a654b..d930dfcfb40 100644 --- a/src/proto/grpc/channelz/channelz.proto +++ b/src/proto/grpc/channelz/channelz.proto @@ -1,4 +1,4 @@ -// Copyright 2018 gRPC authors. +// Copyright 2018 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. @@ -12,20 +12,30 @@ // See the License for the specific language governing permissions and // limitations under the License. +// This file defines an interface for exporting monitoring information +// out of gRPC servers. See the full design at +// https://github.com/grpc/proposal/blob/master/A14-channelz.md +// +// The canonical version of this proto can be found at +// https://github.com/grpc/grpc-proto/blob/master/grpc/channelz/v1/channelz.proto + syntax = "proto3"; -package grpc.channelz; +package grpc.channelz.v1; import "google/protobuf/any.proto"; import "google/protobuf/duration.proto"; import "google/protobuf/timestamp.proto"; import "google/protobuf/wrappers.proto"; -// See go/grpc-channelz. +option go_package = "google.golang.org/grpc/channelz/grpc_channelz_v1"; +option java_multiple_files = true; +option java_package = "io.grpc.channelz.v1"; +option java_outer_classname = "ChannelzProto"; // Channel is a logical grouping of channels, subchannels, and sockets. message Channel { - // The identifier for this channel. + // The identifier for this channel. This should bet set. ChannelRef ref = 1; // Data specific to this channel. ChannelData data = 2; @@ -43,7 +53,7 @@ message Channel { repeated SubchannelRef subchannel_ref = 4; // There are no ordering guarantees on the order of sockets. - repeated SocketRef socket = 5; + repeated SocketRef socket_ref = 5; } // Subchannel is a logical grouping of channels, subchannels, and sockets. @@ -67,7 +77,7 @@ message Subchannel { repeated SubchannelRef subchannel_ref = 4; // There are no ordering guarantees on the order of sockets. - repeated SocketRef socket = 5; + repeated SocketRef socket_ref = 5; } // These come from the specified states in this document: @@ -84,20 +94,23 @@ message ChannelConnectivityState { State state = 1; } +// Channel data is data related to a specific Channel or Subchannel. message ChannelData { - + // The connectivity state of the channel or subchannel. Implementations + // should always set this. ChannelConnectivityState state = 1; // The target this channel originally tried to connect to. May be absent string target = 2; + // A trace of recent events on the channel. May be absent. ChannelTrace trace = 3; // The number of calls started on the channel int64 calls_started = 4; // The number of calls that have completed with an OK status int64 calls_succeeded = 5; - // The number of calls that have a completed with a non-OK status + // The number of calls that have completed with a non-OK status int64 calls_failed = 6; // The last time a call was started on the channel. @@ -130,26 +143,29 @@ message ChannelTraceEvent { } } +// ChannelTrace represents the recent events that have occurred on the channel. message ChannelTrace { // Number of events ever logged in this tracing object. This can differ from // events.size() because events can be overwritten or garbage collected by // implementations. int64 num_events_logged = 1; // Time that this channel was created. - google.protobuf.Timestamp creation_time = 2; + google.protobuf.Timestamp creation_timestamp = 2; // List of events that have occurred on this channel. repeated ChannelTraceEvent events = 3; } +// ChannelRef is a reference to a Channel. message ChannelRef { // The globally unique id for this channel. Must be a positive number. int64 channel_id = 1; // An optional name associated with the channel. string name = 2; // Intentionally don't use field numbers from other refs. - reserved 3, 4, 5, 6; + reserved 3, 4, 5, 6, 7, 8; } +// ChannelRef is a reference to a Subchannel. message SubchannelRef { // The globally unique id for this subchannel. Must be a positive number. int64 subchannel_id = 7; @@ -159,6 +175,7 @@ message SubchannelRef { reserved 1, 2, 3, 4, 5, 6; } +// SocketRef is a reference to a Socket. message SocketRef { int64 socket_id = 3; // An optional name associated with the socket. @@ -167,8 +184,9 @@ message SocketRef { reserved 1, 2, 5, 6, 7, 8; } +// ServerRef is a reference to a Server. message ServerRef { - // A globally unique identifier for this server. Must be a positive number. + // A globally unique identifier for this server. Must be a positive number. int64 server_id = 5; // An optional name associated with the server. string name = 6; @@ -176,16 +194,22 @@ message ServerRef { reserved 1, 2, 3, 4, 7, 8; } +// Server represents a single server. There may be multiple servers in a single +// program. message Server { + // The identifier for a Server. This should be set. ServerRef ref = 1; + // The associated data of the Server. ServerData data = 2; // The sockets that the server is listening on. There are no ordering - // guarantees. + // guarantees. This may be absent. repeated SocketRef listen_socket = 3; } +// ServerData is data for a specific Server. message ServerData { + // A trace of recent events on the server. May be absent. ChannelTrace trace = 1; // The number of incoming calls started on the server @@ -201,13 +225,17 @@ message ServerData { // Information about an actual connection. Pronounced "sock-ay". message Socket { + // The identifier for the Socket. SocketRef ref = 1; + // Data specific to this Socket. SocketData data = 2; // The locally bound address. Address local = 3; // The remote bound address. May be absent. Address remote = 4; + // Security details for this socket. May be absent if not available, or + // there is no security on the socket. Security security = 5; // Optional, represents the name of the remote endpoint, if different than @@ -215,17 +243,23 @@ message Socket { string remote_name = 6; } +// SocketData is data associated for a specific Socket. The fields present +// are specific to the implementation, so there may be minor differences in +// the semantics. (e.g. flow control windows) message SocketData { // The number of streams that have been started. int64 streams_started = 1; - // The number of streams that have ended successfully with the EoS bit set for - // both end points + // The number of streams that have ended successfully: + // On client side, received frame with eos bit set; + // On server side, sent frame with eos bit set. int64 streams_succeeded = 2; - // The number of incoming streams that have a completed with a non-OK status + // The number of streams that have ended unsuccessfully: + // On client side, ended without receiving frame with eos bit set; + // On server side, ended without sending frame with eos bit set. int64 streams_failed = 3; - - // The number of messages successfully sent on this socket. + // The number of grpc messages successfully sent on this socket. int64 messages_sent = 4; + // The number of grpc messages received on this socket. int64 messages_received = 5; // The number of keep alives sent. This is typically implemented with HTTP/2 @@ -254,12 +288,14 @@ message SocketData { // include stream level or TCP level flow control info. google.protobuf.Int64Value remote_flow_control_window = 12; + // Socket options set on this socket. May be absent. repeated SocketOption option = 13; } +// Address represents the address used to create the socket. message Address { message TcpIpAddress { - // Either the IPv4 or IPv6 address in bytes. Will either be 4 bytes or 16 + // Either the IPv4 or IPv6 address in bytes. Will be either 4 bytes or 16 // bytes in length. bytes ip_address = 1; // 0-64k, or -1 if not appropriate. @@ -271,7 +307,7 @@ message Address { } // An address type not included above. message OtherAddress { - // The human readable version of the value. + // The human readable version of the value. This value should be set. string name = 1; // The actual address message. google.protobuf.Any value = 2; @@ -284,12 +320,17 @@ message Address { } } +// Security represents details about how secure the socket is. message Security { message Tls { - // The key exchange used. e.g. X25519 - string key_exchange = 1; - // The cipher used. e.g. AES_128_GCM. - string cipher = 2; + oneof cipher_suite { + // The cipher suite name in the RFC 4346 format: + // https://tools.ietf.org/html/rfc4346#appendix-C + string standard_name = 1; + // Some other way to describe the cipher suite if + // the RFC 4346 name is not available. + string other_name = 2; + } // the certificate used by this endpoint. bytes local_certificate = 3; // the certificate used by the remote endpoint. @@ -307,7 +348,11 @@ message Security { } } +// SocketOption represents socket options for a socket. Specifically, these +// are the options returned by getsockopt(). message SocketOption { + // The full name of the socket option. Typically this will be the upper case + // name, such as "SO_REUSEPORT". string name = 1; // The human readable value of this socket option. At least one of value or // additional will be set. @@ -323,12 +368,17 @@ message SocketOptionTimeout { google.protobuf.Duration duration = 1; } +// For use with SocketOption's additional field. This is primarily used for +// SO_LINGER. message SocketOptionLinger { + // active maps to `struct linger.l_onoff` bool active = 1; + // duration maps to `struct linger.l_linger` google.protobuf.Duration duration = 2; } -// Tcp info for SOL_TCP, TCP_INFO +// For use with SocketOption's additional field. Tcp info for +// SOL_TCP and TCP_INFO. message SocketOptionTcpInfo { uint32 tcpi_state = 1; @@ -366,8 +416,10 @@ message SocketOptionTcpInfo { uint32 tcpi_reordering = 29; } +// Channelz is a service exposed by gRPC servers that provides detailed debug +// information. service Channelz { - // Gets all root channels (e.g. channels the application has directly + // Gets all root channels (i.e. channels the application has directly // created). This does not include subchannels nor non-top level channels. rpc GetTopChannels(GetTopChannelsRequest) returns (GetTopChannelsResponse); // Gets all servers that exist in the process. @@ -382,6 +434,22 @@ service Channelz { rpc GetSocket(GetSocketRequest) returns (GetSocketResponse); } +message GetTopChannelsRequest { + // start_channel_id indicates that only channels at or above this id should be + // included in the results. + int64 start_channel_id = 1; +} + +message GetTopChannelsResponse { + // list of channels that the connection detail service knows about. Sorted in + // ascending channel_id order. + repeated Channel channel = 1; + // If set, indicates that the list of channels is the final list. Requesting + // more channels can only return more if they are created after this RPC + // completes. + bool end = 2; +} + message GetServersRequest { // start_server_id indicates that only servers at or above this id should be // included in the results. @@ -415,42 +483,35 @@ message GetServerSocketsResponse { bool end = 2; } -message GetTopChannelsRequest { - // start_channel_id indicates that only channels at or above this id should be - // included in the results. - int64 start_channel_id = 1; -} - -message GetTopChannelsResponse { - // list of channels that the connection detail service knows about. Sorted in - // ascending channel_id order. - repeated Channel channel = 1; - // If set, indicates that the list of channels is the final list. Requesting - // more channels can only return more if they are created after this RPC - // completes. - bool end = 2; -} - message GetChannelRequest { + // channel_id is the identifier of the specific channel to get. int64 channel_id = 1; } message GetChannelResponse { + // The Channel that corresponds to the requested channel_id. This field + // should be set. Channel channel = 1; } message GetSubchannelRequest { + // subchannel_id is the identifier of the specific subchannel to get. int64 subchannel_id = 1; } message GetSubchannelResponse { + // The Subchannel that corresponds to the requested subchannel_id. This + // field should be set. Subchannel subchannel = 1; } message GetSocketRequest { + // socket_id is the identifier of the specific socket to get. int64 socket_id = 1; } message GetSocketResponse { + // The Socket that corresponds to the requested socket_id. This field + // should be set. Socket socket = 1; } diff --git a/test/core/channel/channel_trace_test.cc b/test/core/channel/channel_trace_test.cc index 64de05bc0a8..9befdb4fa37 100644 --- a/test/core/channel/channel_trace_test.cc +++ b/test/core/channel/channel_trace_test.cc @@ -69,7 +69,7 @@ void ValidateChannelTraceData(grpc_json* json, ASSERT_NE(json, nullptr); grpc_json* num_events_logged_json = GetJsonChild(json, "numEventsLogged"); ASSERT_NE(num_events_logged_json, nullptr); - grpc_json* start_time = GetJsonChild(json, "creationTime"); + grpc_json* start_time = GetJsonChild(json, "creationTimestamp"); ASSERT_NE(start_time, nullptr); size_t num_events_logged = (size_t)strtol(num_events_logged_json->value, nullptr, 0); diff --git a/test/cpp/util/channel_trace_proto_helper.cc b/test/cpp/util/channel_trace_proto_helper.cc index fbc9f1501c4..c395f607f48 100644 --- a/test/cpp/util/channel_trace_proto_helper.cc +++ b/test/cpp/util/channel_trace_proto_helper.cc @@ -32,13 +32,13 @@ namespace testing { void ValidateChannelTraceProtoJsonTranslation(char* tracer_json_c_str) { std::string tracer_json_str(tracer_json_c_str); - grpc::channelz::ChannelTrace channel_trace; + grpc::channelz::v1::ChannelTrace channel_trace; google::protobuf::util::JsonParseOptions parse_options; // If the following line is failing, then uncomment the last line of the // comment, and uncomment the lines that print the two strings. You can // then compare the output, and determine what fields are missing. // - // options.ignore_unknown_fields = true; + // parse_options.ignore_unknown_fields = true; ASSERT_EQ(google::protobuf::util::JsonStringToMessage( tracer_json_str, &channel_trace, parse_options), google::protobuf::util::Status::OK); From c3c6e064b33ab8b7a2d3cf5a56171029d0bb1edc Mon Sep 17 00:00:00 2001 From: ncteisen Date: Wed, 9 May 2018 11:10:21 -0700 Subject: [PATCH 02/57] Add basic support for GetChannel --- BUILD | 2 + CMakeLists.txt | 60 ++++++- Makefile | 62 ++++++- build.yaml | 23 ++- config.m4 | 1 + config.w32 | 1 + gRPC-C++.podspec | 2 + gRPC-Core.podspec | 3 + grpc.def | 1 + grpc.gemspec | 2 + grpc.gyp | 4 + include/grpc/grpc.h | 3 + package.xml | 2 + src/core/lib/channel/channelz.cc | 164 ++++++++++++++++++ src/core/lib/channel/channelz.h | 68 ++++++++ src/core/lib/surface/call.cc | 27 ++- src/core/lib/surface/channel.cc | 13 ++ src/core/lib/surface/channel.h | 5 + src/python/grpcio/grpc_core_dependencies.py | 1 + src/ruby/ext/grpc/rb_grpc_imports.generated.c | 2 + src/ruby/ext/grpc/rb_grpc_imports.generated.h | 3 + test/core/channel/BUILD | 9 + test/core/channel/channelz_test.cc | 57 ++++++ test/core/end2end/fuzzers/api_fuzzer.cc | 1 + test/core/end2end/tests/simple_request.cc | 7 + .../core/surface/public_headers_must_be_c89.c | 1 + test/cpp/util/channel_trace_proto_helper.cc | 34 +++- test/cpp/util/channel_trace_proto_helper.h | 1 + tools/doxygen/Doxyfile.c++.internal | 1 + tools/doxygen/Doxyfile.core.internal | 2 + .../generated/sources_and_headers.json | 26 ++- tools/run_tests/generated/tests.json | 24 +++ 32 files changed, 579 insertions(+), 33 deletions(-) create mode 100644 src/core/lib/channel/channelz.cc create mode 100644 src/core/lib/channel/channelz.h create mode 100644 test/core/channel/channelz_test.cc diff --git a/BUILD b/BUILD index db1bdaa9947..9ab216a0926 100644 --- a/BUILD +++ b/BUILD @@ -679,6 +679,7 @@ grpc_cc_library( "src/core/lib/channel/channel_stack_builder.cc", "src/core/lib/channel/channel_trace.cc", "src/core/lib/channel/channelz_registry.cc", + "src/core/lib/channel/channelz.cc", "src/core/lib/channel/connected_channel.cc", "src/core/lib/channel/handshaker.cc", "src/core/lib/channel/handshaker_factory.cc", @@ -826,6 +827,7 @@ grpc_cc_library( "src/core/lib/channel/channel_stack_builder.h", "src/core/lib/channel/channel_trace.h", "src/core/lib/channel/channelz_registry.h", + "src/core/lib/channel/channelz.h", "src/core/lib/channel/connected_channel.h", "src/core/lib/channel/context.h", "src/core/lib/channel/handshaker.h", diff --git a/CMakeLists.txt b/CMakeLists.txt index af56886cd98..37bde81a9d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -539,6 +539,7 @@ add_dependencies(buildtests_cxx channel_arguments_test) add_dependencies(buildtests_cxx channel_filter_test) add_dependencies(buildtests_cxx channel_trace_test) add_dependencies(buildtests_cxx channelz_registry_test) +add_dependencies(buildtests_cxx channelz_test) add_dependencies(buildtests_cxx check_gcp_environment_linux_test) add_dependencies(buildtests_cxx check_gcp_environment_windows_test) add_dependencies(buildtests_cxx chttp2_settings_timeout_test) @@ -923,6 +924,7 @@ add_library(grpc src/core/lib/channel/channel_stack.cc src/core/lib/channel/channel_stack_builder.cc src/core/lib/channel/channel_trace.cc + src/core/lib/channel/channelz.cc src/core/lib/channel/channelz_registry.cc src/core/lib/channel/connected_channel.cc src/core/lib/channel/handshaker.cc @@ -1316,6 +1318,7 @@ add_library(grpc_cronet src/core/lib/channel/channel_stack.cc src/core/lib/channel/channel_stack_builder.cc src/core/lib/channel/channel_trace.cc + src/core/lib/channel/channelz.cc src/core/lib/channel/channelz_registry.cc src/core/lib/channel/connected_channel.cc src/core/lib/channel/handshaker.cc @@ -1701,6 +1704,7 @@ add_library(grpc_test_util src/core/lib/channel/channel_stack.cc src/core/lib/channel/channel_stack_builder.cc src/core/lib/channel/channel_trace.cc + src/core/lib/channel/channelz.cc src/core/lib/channel/channelz_registry.cc src/core/lib/channel/connected_channel.cc src/core/lib/channel/handshaker.cc @@ -2005,6 +2009,7 @@ add_library(grpc_test_util_unsecure src/core/lib/channel/channel_stack.cc src/core/lib/channel/channel_stack_builder.cc src/core/lib/channel/channel_trace.cc + src/core/lib/channel/channelz.cc src/core/lib/channel/channelz_registry.cc src/core/lib/channel/connected_channel.cc src/core/lib/channel/handshaker.cc @@ -2288,6 +2293,7 @@ add_library(grpc_unsecure src/core/lib/channel/channel_stack.cc src/core/lib/channel/channel_stack_builder.cc src/core/lib/channel/channel_trace.cc + src/core/lib/channel/channelz.cc src/core/lib/channel/channelz_registry.cc src/core/lib/channel/connected_channel.cc src/core/lib/channel/handshaker.cc @@ -3114,6 +3120,7 @@ add_library(grpc++_cronet src/core/lib/channel/channel_stack.cc src/core/lib/channel/channel_stack_builder.cc src/core/lib/channel/channel_trace.cc + src/core/lib/channel/channelz.cc src/core/lib/channel/channelz_registry.cc src/core/lib/channel/connected_channel.cc src/core/lib/channel/handshaker.cc @@ -10472,17 +10479,10 @@ if (gRPC_BUILD_TESTS) add_executable(channel_trace_test test/core/channel/channel_trace_test.cc - ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/channelz/channelz.pb.cc - ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/channelz/channelz.grpc.pb.cc - ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/channelz/channelz.pb.h - ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/channelz/channelz.grpc.pb.h third_party/googletest/googletest/src/gtest-all.cc third_party/googletest/googlemock/src/gmock-all.cc ) -protobuf_generate_grpc_cpp( - src/proto/grpc/channelz/channelz.proto -) target_include_directories(channel_trace_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} @@ -10555,6 +10555,52 @@ target_link_libraries(channelz_registry_test endif (gRPC_BUILD_TESTS) if (gRPC_BUILD_TESTS) +add_executable(channelz_test + test/core/channel/channelz_test.cc + ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/channelz/channelz.pb.cc + ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/channelz/channelz.grpc.pb.cc + ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/channelz/channelz.pb.h + ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/channelz/channelz.grpc.pb.h + third_party/googletest/googletest/src/gtest-all.cc + third_party/googletest/googlemock/src/gmock-all.cc +) + +protobuf_generate_grpc_cpp( + src/proto/grpc/channelz/channelz.proto +) + +target_include_directories(channelz_test + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include + PRIVATE ${_gRPC_SSL_INCLUDE_DIR} + PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR} + PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR} + PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR} + PRIVATE ${_gRPC_CARES_INCLUDE_DIR} + PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR} + PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + PRIVATE third_party/googletest/googletest/include + PRIVATE third_party/googletest/googletest + PRIVATE third_party/googletest/googlemock/include + PRIVATE third_party/googletest/googlemock + PRIVATE ${_gRPC_PROTO_GENS_DIR} +) + +target_link_libraries(channelz_test + ${_gRPC_PROTOBUF_LIBRARIES} + ${_gRPC_ALLTARGETS_LIBRARIES} + grpc_test_util + grpc++_test_util + grpc++ + grpc + gpr_test_util + gpr + ${_gRPC_GFLAGS_LIBRARIES} +) + +endif (gRPC_BUILD_TESTS) +if (gRPC_BUILD_TESTS) + add_executable(check_gcp_environment_linux_test test/core/security/check_gcp_environment_linux_test.cc third_party/googletest/googletest/src/gtest-all.cc diff --git a/Makefile b/Makefile index 1247566ffec..f5423ea6435 100644 --- a/Makefile +++ b/Makefile @@ -1123,6 +1123,7 @@ channel_arguments_test: $(BINDIR)/$(CONFIG)/channel_arguments_test channel_filter_test: $(BINDIR)/$(CONFIG)/channel_filter_test channel_trace_test: $(BINDIR)/$(CONFIG)/channel_trace_test channelz_registry_test: $(BINDIR)/$(CONFIG)/channelz_registry_test +channelz_test: $(BINDIR)/$(CONFIG)/channelz_test check_gcp_environment_linux_test: $(BINDIR)/$(CONFIG)/check_gcp_environment_linux_test check_gcp_environment_windows_test: $(BINDIR)/$(CONFIG)/check_gcp_environment_windows_test chttp2_settings_timeout_test: $(BINDIR)/$(CONFIG)/chttp2_settings_timeout_test @@ -1618,6 +1619,7 @@ buildtests_cxx: privatelibs_cxx \ $(BINDIR)/$(CONFIG)/channel_filter_test \ $(BINDIR)/$(CONFIG)/channel_trace_test \ $(BINDIR)/$(CONFIG)/channelz_registry_test \ + $(BINDIR)/$(CONFIG)/channelz_test \ $(BINDIR)/$(CONFIG)/check_gcp_environment_linux_test \ $(BINDIR)/$(CONFIG)/check_gcp_environment_windows_test \ $(BINDIR)/$(CONFIG)/chttp2_settings_timeout_test \ @@ -1793,6 +1795,7 @@ buildtests_cxx: privatelibs_cxx \ $(BINDIR)/$(CONFIG)/channel_filter_test \ $(BINDIR)/$(CONFIG)/channel_trace_test \ $(BINDIR)/$(CONFIG)/channelz_registry_test \ + $(BINDIR)/$(CONFIG)/channelz_test \ $(BINDIR)/$(CONFIG)/check_gcp_environment_linux_test \ $(BINDIR)/$(CONFIG)/check_gcp_environment_windows_test \ $(BINDIR)/$(CONFIG)/chttp2_settings_timeout_test \ @@ -2228,6 +2231,8 @@ test_cxx: buildtests_cxx $(Q) $(BINDIR)/$(CONFIG)/channel_trace_test || ( echo test channel_trace_test failed ; exit 1 ) $(E) "[RUN] Testing channelz_registry_test" $(Q) $(BINDIR)/$(CONFIG)/channelz_registry_test || ( echo test channelz_registry_test failed ; exit 1 ) + $(E) "[RUN] Testing channelz_test" + $(Q) $(BINDIR)/$(CONFIG)/channelz_test || ( echo test channelz_test failed ; exit 1 ) $(E) "[RUN] Testing check_gcp_environment_linux_test" $(Q) $(BINDIR)/$(CONFIG)/check_gcp_environment_linux_test || ( echo test check_gcp_environment_linux_test failed ; exit 1 ) $(E) "[RUN] Testing check_gcp_environment_windows_test" @@ -3304,6 +3309,7 @@ LIBGRPC_SRC = \ src/core/lib/channel/channel_stack.cc \ src/core/lib/channel/channel_stack_builder.cc \ src/core/lib/channel/channel_trace.cc \ + src/core/lib/channel/channelz.cc \ src/core/lib/channel/channelz_registry.cc \ src/core/lib/channel/connected_channel.cc \ src/core/lib/channel/handshaker.cc \ @@ -3697,6 +3703,7 @@ LIBGRPC_CRONET_SRC = \ src/core/lib/channel/channel_stack.cc \ src/core/lib/channel/channel_stack_builder.cc \ src/core/lib/channel/channel_trace.cc \ + src/core/lib/channel/channelz.cc \ src/core/lib/channel/channelz_registry.cc \ src/core/lib/channel/connected_channel.cc \ src/core/lib/channel/handshaker.cc \ @@ -4081,6 +4088,7 @@ LIBGRPC_TEST_UTIL_SRC = \ src/core/lib/channel/channel_stack.cc \ src/core/lib/channel/channel_stack_builder.cc \ src/core/lib/channel/channel_trace.cc \ + src/core/lib/channel/channelz.cc \ src/core/lib/channel/channelz_registry.cc \ src/core/lib/channel/connected_channel.cc \ src/core/lib/channel/handshaker.cc \ @@ -4377,6 +4385,7 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \ src/core/lib/channel/channel_stack.cc \ src/core/lib/channel/channel_stack_builder.cc \ src/core/lib/channel/channel_trace.cc \ + src/core/lib/channel/channelz.cc \ src/core/lib/channel/channelz_registry.cc \ src/core/lib/channel/connected_channel.cc \ src/core/lib/channel/handshaker.cc \ @@ -4639,6 +4648,7 @@ LIBGRPC_UNSECURE_SRC = \ src/core/lib/channel/channel_stack.cc \ src/core/lib/channel/channel_stack_builder.cc \ src/core/lib/channel/channel_trace.cc \ + src/core/lib/channel/channelz.cc \ src/core/lib/channel/channelz_registry.cc \ src/core/lib/channel/connected_channel.cc \ src/core/lib/channel/handshaker.cc \ @@ -5458,6 +5468,7 @@ LIBGRPC++_CRONET_SRC = \ src/core/lib/channel/channel_stack.cc \ src/core/lib/channel/channel_stack_builder.cc \ src/core/lib/channel/channel_trace.cc \ + src/core/lib/channel/channelz.cc \ src/core/lib/channel/channelz_registry.cc \ src/core/lib/channel/connected_channel.cc \ src/core/lib/channel/handshaker.cc \ @@ -16296,7 +16307,6 @@ endif CHANNEL_TRACE_TEST_SRC = \ test/core/channel/channel_trace_test.cc \ - $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc \ CHANNEL_TRACE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CHANNEL_TRACE_TEST_SRC)))) ifeq ($(NO_SECURE),true) @@ -16329,8 +16339,6 @@ endif $(OBJDIR)/$(CONFIG)/test/core/channel/channel_trace_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a -$(OBJDIR)/$(CONFIG)/src/proto/grpc/channelz/channelz.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a - deps_channel_trace_test: $(CHANNEL_TRACE_TEST_OBJS:.o=.dep) ifneq ($(NO_SECURE),true) @@ -16338,7 +16346,6 @@ ifneq ($(NO_DEPS),true) -include $(CHANNEL_TRACE_TEST_OBJS:.o=.dep) endif endif -$(OBJDIR)/$(CONFIG)/test/core/channel/channel_trace_test.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc CHANNELZ_REGISTRY_TEST_SRC = \ @@ -16384,6 +16391,53 @@ endif endif +CHANNELZ_TEST_SRC = \ + test/core/channel/channelz_test.cc \ + $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc \ + +CHANNELZ_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CHANNELZ_TEST_SRC)))) +ifeq ($(NO_SECURE),true) + +# You can't build secure targets if you don't have OpenSSL. + +$(BINDIR)/$(CONFIG)/channelz_test: openssl_dep_error + +else + + + + +ifeq ($(NO_PROTOBUF),true) + +# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.5.0+. + +$(BINDIR)/$(CONFIG)/channelz_test: protobuf_dep_error + +else + +$(BINDIR)/$(CONFIG)/channelz_test: $(PROTOBUF_DEP) $(CHANNELZ_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + $(E) "[LD] Linking $@" + $(Q) mkdir -p `dirname $@` + $(Q) $(LDXX) $(LDFLAGS) $(CHANNELZ_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/channelz_test + +endif + +endif + +$(OBJDIR)/$(CONFIG)/test/core/channel/channelz_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + +$(OBJDIR)/$(CONFIG)/src/proto/grpc/channelz/channelz.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + +deps_channelz_test: $(CHANNELZ_TEST_OBJS:.o=.dep) + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(CHANNELZ_TEST_OBJS:.o=.dep) +endif +endif +$(OBJDIR)/$(CONFIG)/test/core/channel/channelz_test.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc + + CHECK_GCP_ENVIRONMENT_LINUX_TEST_SRC = \ test/core/security/check_gcp_environment_linux_test.cc \ diff --git a/build.yaml b/build.yaml index 16c90fbd4c1..3df140e9222 100644 --- a/build.yaml +++ b/build.yaml @@ -235,6 +235,7 @@ filegroups: - src/core/lib/channel/channel_stack.cc - src/core/lib/channel/channel_stack_builder.cc - src/core/lib/channel/channel_trace.cc + - src/core/lib/channel/channelz.cc - src/core/lib/channel/channelz_registry.cc - src/core/lib/channel/connected_channel.cc - src/core/lib/channel/handshaker.cc @@ -405,6 +406,7 @@ filegroups: - src/core/lib/channel/channel_stack.h - src/core/lib/channel/channel_stack_builder.h - src/core/lib/channel/channel_trace.h + - src/core/lib/channel/channelz.h - src/core/lib/channel/channelz_registry.h - src/core/lib/channel/connected_channel.h - src/core/lib/channel/context.h @@ -4203,10 +4205,6 @@ targets: - grpc - gpr_test_util - gpr - filegroups: - - grpc++_channelz_proto - uses: - - grpc++_test - name: channelz_registry_test gtest: true build: test @@ -4223,6 +4221,23 @@ targets: uses: - grpc++_test uses_polling: false +- name: channelz_test + gtest: true + build: test + language: c++ + src: + - test/core/channel/channelz_test.cc + deps: + - grpc_test_util + - grpc++_test_util + - grpc++ + - grpc + - gpr_test_util + - gpr + filegroups: + - grpc++_channelz_proto + uses: + - grpc++_test - name: check_gcp_environment_linux_test build: test language: c++ diff --git a/config.m4 b/config.m4 index 8190485249c..da8dca7c3cf 100644 --- a/config.m4 +++ b/config.m4 @@ -89,6 +89,7 @@ if test "$PHP_GRPC" != "no"; then src/core/lib/channel/channel_stack.cc \ src/core/lib/channel/channel_stack_builder.cc \ src/core/lib/channel/channel_trace.cc \ + src/core/lib/channel/channelz.cc \ src/core/lib/channel/channelz_registry.cc \ src/core/lib/channel/connected_channel.cc \ src/core/lib/channel/handshaker.cc \ diff --git a/config.w32 b/config.w32 index db7679ce53b..b4311cb6d18 100644 --- a/config.w32 +++ b/config.w32 @@ -65,6 +65,7 @@ if (PHP_GRPC != "no") { "src\\core\\lib\\channel\\channel_stack.cc " + "src\\core\\lib\\channel\\channel_stack_builder.cc " + "src\\core\\lib\\channel\\channel_trace.cc " + + "src\\core\\lib\\channel\\channelz.cc " + "src\\core\\lib\\channel\\channelz_registry.cc " + "src\\core\\lib\\channel\\connected_channel.cc " + "src\\core\\lib\\channel\\handshaker.cc " + diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index 262de72971b..ce56e514dd6 100644 --- a/gRPC-C++.podspec +++ b/gRPC-C++.podspec @@ -347,6 +347,7 @@ Pod::Spec.new do |s| 'src/core/lib/channel/channel_stack.h', 'src/core/lib/channel/channel_stack_builder.h', 'src/core/lib/channel/channel_trace.h', + 'src/core/lib/channel/channelz.h', 'src/core/lib/channel/channelz_registry.h', 'src/core/lib/channel/connected_channel.h', 'src/core/lib/channel/context.h', @@ -532,6 +533,7 @@ Pod::Spec.new do |s| 'src/core/lib/channel/channel_stack.h', 'src/core/lib/channel/channel_stack_builder.h', 'src/core/lib/channel/channel_trace.h', + 'src/core/lib/channel/channelz.h', 'src/core/lib/channel/channelz_registry.h', 'src/core/lib/channel/connected_channel.h', 'src/core/lib/channel/context.h', diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index f3be7129b59..a10cfb5739f 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -357,6 +357,7 @@ Pod::Spec.new do |s| 'src/core/lib/channel/channel_stack.h', 'src/core/lib/channel/channel_stack_builder.h', 'src/core/lib/channel/channel_trace.h', + 'src/core/lib/channel/channelz.h', 'src/core/lib/channel/channelz_registry.h', 'src/core/lib/channel/connected_channel.h', 'src/core/lib/channel/context.h', @@ -507,6 +508,7 @@ Pod::Spec.new do |s| 'src/core/lib/channel/channel_stack.cc', 'src/core/lib/channel/channel_stack_builder.cc', 'src/core/lib/channel/channel_trace.cc', + 'src/core/lib/channel/channelz.cc', 'src/core/lib/channel/channelz_registry.cc', 'src/core/lib/channel/connected_channel.cc', 'src/core/lib/channel/handshaker.cc', @@ -935,6 +937,7 @@ Pod::Spec.new do |s| 'src/core/lib/channel/channel_stack.h', 'src/core/lib/channel/channel_stack_builder.h', 'src/core/lib/channel/channel_trace.h', + 'src/core/lib/channel/channelz.h', 'src/core/lib/channel/channelz_registry.h', 'src/core/lib/channel/connected_channel.h', 'src/core/lib/channel/context.h', diff --git a/grpc.def b/grpc.def index 6a91214e8c3..1a8c40f9509 100644 --- a/grpc.def +++ b/grpc.def @@ -47,6 +47,7 @@ EXPORTS grpc_channel_destroy grpc_channel_get_trace grpc_channel_get_uuid + grpc_channelz_get_channel grpc_call_cancel grpc_call_cancel_with_status grpc_call_ref diff --git a/grpc.gemspec b/grpc.gemspec index 5ab37136835..cf0e3081459 100644 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -294,6 +294,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/channel/channel_stack.h ) s.files += %w( src/core/lib/channel/channel_stack_builder.h ) s.files += %w( src/core/lib/channel/channel_trace.h ) + s.files += %w( src/core/lib/channel/channelz.h ) s.files += %w( src/core/lib/channel/channelz_registry.h ) s.files += %w( src/core/lib/channel/connected_channel.h ) s.files += %w( src/core/lib/channel/context.h ) @@ -444,6 +445,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/channel/channel_stack.cc ) s.files += %w( src/core/lib/channel/channel_stack_builder.cc ) s.files += %w( src/core/lib/channel/channel_trace.cc ) + s.files += %w( src/core/lib/channel/channelz.cc ) s.files += %w( src/core/lib/channel/channelz_registry.cc ) s.files += %w( src/core/lib/channel/connected_channel.cc ) s.files += %w( src/core/lib/channel/handshaker.cc ) diff --git a/grpc.gyp b/grpc.gyp index 2ceae3fe36b..a3ea8674fc0 100644 --- a/grpc.gyp +++ b/grpc.gyp @@ -249,6 +249,7 @@ 'src/core/lib/channel/channel_stack.cc', 'src/core/lib/channel/channel_stack_builder.cc', 'src/core/lib/channel/channel_trace.cc', + 'src/core/lib/channel/channelz.cc', 'src/core/lib/channel/channelz_registry.cc', 'src/core/lib/channel/connected_channel.cc', 'src/core/lib/channel/handshaker.cc', @@ -598,6 +599,7 @@ 'src/core/lib/channel/channel_stack.cc', 'src/core/lib/channel/channel_stack_builder.cc', 'src/core/lib/channel/channel_trace.cc', + 'src/core/lib/channel/channelz.cc', 'src/core/lib/channel/channelz_registry.cc', 'src/core/lib/channel/connected_channel.cc', 'src/core/lib/channel/handshaker.cc', @@ -829,6 +831,7 @@ 'src/core/lib/channel/channel_stack.cc', 'src/core/lib/channel/channel_stack_builder.cc', 'src/core/lib/channel/channel_trace.cc', + 'src/core/lib/channel/channelz.cc', 'src/core/lib/channel/channelz_registry.cc', 'src/core/lib/channel/connected_channel.cc', 'src/core/lib/channel/handshaker.cc', @@ -1038,6 +1041,7 @@ 'src/core/lib/channel/channel_stack.cc', 'src/core/lib/channel/channel_stack_builder.cc', 'src/core/lib/channel/channel_trace.cc', + 'src/core/lib/channel/channelz.cc', 'src/core/lib/channel/channelz_registry.cc', 'src/core/lib/channel/connected_channel.cc', 'src/core/lib/channel/handshaker.cc', diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h index dd8a5d7d5f8..de7c39b1834 100644 --- a/include/grpc/grpc.h +++ b/include/grpc/grpc.h @@ -294,6 +294,9 @@ GRPCAPI char* grpc_channel_get_trace(grpc_channel* channel); later time. */ GRPCAPI intptr_t grpc_channel_get_uuid(grpc_channel* channel); +/** channelz support */ +GRPCAPI char* grpc_channelz_get_channel(intptr_t channel_id); + /** Error handling for grpc_call Most grpc_call functions return a grpc_error. If the error is not GRPC_OK then the operation failed due to some unsatisfied precondition. diff --git a/package.xml b/package.xml index b8cda9d79f0..1a13bf81b5f 100644 --- a/package.xml +++ b/package.xml @@ -299,6 +299,7 @@ + @@ -449,6 +450,7 @@ + diff --git a/src/core/lib/channel/channelz.cc b/src/core/lib/channel/channelz.cc new file mode 100644 index 00000000000..aabc941dcd5 --- /dev/null +++ b/src/core/lib/channel/channelz.cc @@ -0,0 +1,164 @@ +/* + * + * 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. + * + */ + +#include + +#include "src/core/lib/channel/channelz.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "src/core/lib/channel/channelz_registry.h" +#include "src/core/lib/channel/status_util.h" +#include "src/core/lib/gpr/string.h" +#include "src/core/lib/gpr/useful.h" +#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/surface/channel.h" +#include "src/core/lib/transport/connectivity_state.h" +#include "src/core/lib/transport/error_utils.h" + +// TODO(ncteisen): actually implement this +char* grpc_channelz_get_channel(intptr_t channel_id) { return nullptr; } + +namespace grpc_core { +namespace channelz { + +// TODO(ncteisen): more this functions to a loc where it can be used +namespace { + +// returns an allocated string that represents tm according to RFC-3339, and, +// more specifically, follows: +// https://developers.google.com/protocol-buffers/docs/proto3#json +// +// "Uses RFC 3339, where generated output will always be Z-normalized and uses +// 0, 3, 6 or 9 fractional digits." +char* fmt_time(gpr_timespec tm) { + char time_buffer[35]; + char ns_buffer[11]; // '.' + 9 digits of precision + struct tm* tm_info = localtime((const time_t*)&tm.tv_sec); + strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%dT%H:%M:%S", tm_info); + snprintf(ns_buffer, 11, ".%09d", tm.tv_nsec); + // This loop trims off trailing zeros by inserting a null character that the + // right point. We iterate in chunks of three because we want 0, 3, 6, or 9 + // fractional digits. + for (int i = 7; i >= 1; i -= 3) { + if (ns_buffer[i] == '0' && ns_buffer[i + 1] == '0' && + ns_buffer[i + 2] == '0') { + ns_buffer[i] = '\0'; + // Edge case in which all fractional digits were 0. + if (i == 1) { + ns_buffer[0] = '\0'; + } + } else { + break; + } + } + char* full_time_str; + gpr_asprintf(&full_time_str, "%s%sZ", time_buffer, ns_buffer); + return full_time_str; +} + +// TODO(ncteisen); move this to json library +grpc_json* add_num_str(grpc_json* parent, grpc_json* it, const char* name, + uint64_t num) { + char* num_str; + gpr_asprintf(&num_str, "%" PRIu64, num); + return grpc_json_create_child(it, parent, name, num_str, GRPC_JSON_STRING, + true); +} + +} // namespace + +Channel::Channel(grpc_channel* channel) : channel_(channel) { + target_ = grpc_channel_get_target(channel_); + channel_uuid_ = ChannelzRegistry::Register(this); +} + +Channel::~Channel() { + gpr_free(const_cast(target_)); + ChannelzRegistry::Unregister(channel_uuid_); +} + +void Channel::CallStarted() { + calls_started_++; + last_call_started_timestamp_ = grpc_millis_to_timespec( + grpc_core::ExecCtx::Get()->Now(), GPR_CLOCK_REALTIME); +} + +grpc_connectivity_state Channel::GetConnectivityState() { + if (channel_destroyed_) { + return GRPC_CHANNEL_SHUTDOWN; + } else { + return grpc_channel_check_connectivity_state(channel_, false); + } +} + +char* Channel::RenderJSON() { + // We need to track these three json objects to build our object + grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT); + grpc_json* json = top_level_json; + grpc_json* json_iterator = nullptr; + + // create and fill the ref child + json_iterator = grpc_json_create_child(json_iterator, json, "ref", nullptr, + GRPC_JSON_OBJECT, true); + json = json_iterator; + json_iterator = nullptr; + json_iterator = add_num_str(json, json_iterator, "channelId", channel_uuid_); + + // reset json iterators to top level object + json = top_level_json; + json_iterator = nullptr; + + // create and fill the data child + json_iterator = grpc_json_create_child(json_iterator, json, "data", nullptr, + GRPC_JSON_OBJECT, true); + json = json_iterator; + json_iterator = nullptr; + json_iterator = + add_num_str(json, json_iterator, "callsStarted", calls_started_); + json_iterator = + add_num_str(json, json_iterator, "callsSucceeded", calls_succeeded_); + json_iterator = + add_num_str(json, json_iterator, "callsFailed", calls_failed_); + json_iterator = grpc_json_create_child( + json_iterator, json, "lastCallStartedTimestamp", + fmt_time(last_call_started_timestamp_), GRPC_JSON_STRING, true); + json_iterator = grpc_json_create_child(json_iterator, json, "target", target_, + GRPC_JSON_STRING, false); + grpc_connectivity_state connectivity_state = GetConnectivityState(); + json_iterator = + grpc_json_create_child(json_iterator, json, "state", + grpc_connectivity_state_name(connectivity_state), + GRPC_JSON_STRING, false); + + // render and return the over json object + char* json_str = grpc_json_dump_to_string(top_level_json, 0); + grpc_json_destroy(top_level_json); + return json_str; +} + +} // namespace channelz +} // namespace grpc_core diff --git a/src/core/lib/channel/channelz.h b/src/core/lib/channel/channelz.h new file mode 100644 index 00000000000..661228cf446 --- /dev/null +++ b/src/core/lib/channel/channelz.h @@ -0,0 +1,68 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_CORE_LIB_CHANNEL_CHANNELZ_H +#define GRPC_CORE_LIB_CHANNEL_CHANNELZ_H + +#include + +#include + +#include "src/core/ext/filters/client_channel/client_channel.h" +#include "src/core/lib/gprpp/ref_counted.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" +#include "src/core/lib/iomgr/error.h" +#include "src/core/lib/json/json.h" + +namespace grpc_core { +namespace channelz { + +// owned by the client_channel that it points to and tracks +class Channel : public RefCounted { + public: + Channel(grpc_channel* channel); + ~Channel(); + + void CallStarted(); + void CallFailed() { calls_failed_++; } + void CallSucceeded() { calls_succeeded_++; } + + char* RenderJSON(); + + void set_channel_destroyed() { + GPR_ASSERT(!channel_destroyed_); + channel_destroyed_ = true; + } + + private: + bool channel_destroyed_ = false; + grpc_channel* channel_; + const char* target_; + uint64_t calls_started_ = 0; + uint64_t calls_succeeded_ = 0; + uint64_t calls_failed_ = 0; + gpr_timespec last_call_started_timestamp_; + intptr_t channel_uuid_; + + grpc_connectivity_state GetConnectivityState(); +}; + +} // namespace channelz +} // namespace grpc_core + +#endif /* GRPC_CORE_LIB_CHANNEL_CHANNELZ_H */ diff --git a/src/core/lib/surface/call.cc b/src/core/lib/surface/call.cc index 86e0afa6ee3..924d633cb27 100644 --- a/src/core/lib/surface/call.cc +++ b/src/core/lib/surface/call.cc @@ -1077,13 +1077,23 @@ static void recv_trailing_filter(void* args, grpc_metadata_batch* b) { if (b->idx.named.grpc_status != nullptr) { grpc_status_code status_code = grpc_get_status_code_from_metadata(b->idx.named.grpc_status->md); - grpc_error* error = - status_code == GRPC_STATUS_OK - ? GRPC_ERROR_NONE - : grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING( - "Error received from peer"), - GRPC_ERROR_INT_GRPC_STATUS, - static_cast(status_code)); + grpc_error* error = GRPC_ERROR_NONE; + grpc_core::channelz::Channel* channelz_channel = + call->channel != nullptr + ? grpc_channel_get_channelz_channel(call->channel) + : nullptr; + if (status_code == GRPC_STATUS_OK) { + if (channelz_channel != nullptr) { + channelz_channel->CallSucceeded(); + } + } else { + if (channelz_channel != nullptr) { + channelz_channel->CallFailed(); + } + error = grpc_error_set_int( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error received from peer"), + GRPC_ERROR_INT_GRPC_STATUS, static_cast(status_code)); + } if (b->idx.named.grpc_message != nullptr) { error = grpc_error_set_str( error, GRPC_ERROR_STR_GRPC_MESSAGE, @@ -1665,6 +1675,9 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops, stream_op_payload->send_initial_metadata.peer_string = &call->peer_string; } + grpc_core::channelz::Channel* channelz_channel = + grpc_channel_get_channelz_channel(call->channel); + channelz_channel->CallStarted(); break; } case GRPC_OP_SEND_MESSAGE: { diff --git a/src/core/lib/surface/channel.cc b/src/core/lib/surface/channel.cc index a466b325bef..da66a120d57 100644 --- a/src/core/lib/surface/channel.cc +++ b/src/core/lib/surface/channel.cc @@ -32,6 +32,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/debug/stats.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gprpp/manual_constructor.h" @@ -67,6 +68,7 @@ struct grpc_channel { registered_call* registered_calls; grpc_core::RefCountedPtr tracer; + grpc_core::RefCountedPtr channelz_channel; char* target; }; @@ -150,6 +152,8 @@ grpc_channel* grpc_channel_create_with_builder( channel->tracer->AddTraceEvent( grpc_core::ChannelTrace::Severity::Info, grpc_slice_from_static_string("Channel created")); + channel->channelz_channel = + grpc_core::MakeRefCounted(channel); return channel; } @@ -188,6 +192,15 @@ char* grpc_channel_get_trace(grpc_channel* channel) { return channel->tracer->RenderTrace(); } +char* grpc_channel_render_channelz(grpc_channel* channel) { + return channel->channelz_channel->RenderJSON(); +} + +grpc_core::channelz::Channel* grpc_channel_get_channelz_channel( + grpc_channel* channel) { + return channel->channelz_channel.get(); +} + intptr_t grpc_channel_get_uuid(grpc_channel* channel) { return channel->tracer->GetUuid(); } diff --git a/src/core/lib/surface/channel.h b/src/core/lib/surface/channel.h index 288313951e4..52290f05f7a 100644 --- a/src/core/lib/surface/channel.h +++ b/src/core/lib/surface/channel.h @@ -23,6 +23,7 @@ #include "src/core/lib/channel/channel_stack.h" #include "src/core/lib/channel/channel_stack_builder.h" +#include "src/core/lib/channel/channelz.h" #include "src/core/lib/surface/channel_stack_type.h" grpc_channel* grpc_channel_create(const char* target, @@ -50,6 +51,10 @@ grpc_call* grpc_channel_create_pollset_set_call( /** Get a (borrowed) pointer to this channels underlying channel stack */ grpc_channel_stack* grpc_channel_get_channel_stack(grpc_channel* channel); +grpc_core::channelz::Channel* grpc_channel_get_channelz_channel( + grpc_channel* channel); +char* grpc_channel_render_channelz(grpc_channel* channel); + /** Get a grpc_mdelem of grpc-status: X where X is the numeric value of status_code. diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index 5511bf9a322..a64fb42f9ba 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -64,6 +64,7 @@ CORE_SOURCE_FILES = [ 'src/core/lib/channel/channel_stack.cc', 'src/core/lib/channel/channel_stack_builder.cc', 'src/core/lib/channel/channel_trace.cc', + 'src/core/lib/channel/channelz.cc', 'src/core/lib/channel/channelz_registry.cc', 'src/core/lib/channel/connected_channel.cc', 'src/core/lib/channel/handshaker.cc', diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c index 02f84c0b962..075219a3af3 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c @@ -70,6 +70,7 @@ grpc_lame_client_channel_create_type grpc_lame_client_channel_create_import; grpc_channel_destroy_type grpc_channel_destroy_import; grpc_channel_get_trace_type grpc_channel_get_trace_import; grpc_channel_get_uuid_type grpc_channel_get_uuid_import; +grpc_channelz_get_channel_type grpc_channelz_get_channel_import; grpc_call_cancel_type grpc_call_cancel_import; grpc_call_cancel_with_status_type grpc_call_cancel_with_status_import; grpc_call_ref_type grpc_call_ref_import; @@ -318,6 +319,7 @@ void grpc_rb_load_imports(HMODULE library) { grpc_channel_destroy_import = (grpc_channel_destroy_type) GetProcAddress(library, "grpc_channel_destroy"); grpc_channel_get_trace_import = (grpc_channel_get_trace_type) GetProcAddress(library, "grpc_channel_get_trace"); grpc_channel_get_uuid_import = (grpc_channel_get_uuid_type) GetProcAddress(library, "grpc_channel_get_uuid"); + grpc_channelz_get_channel_import = (grpc_channelz_get_channel_type) GetProcAddress(library, "grpc_channelz_get_channel"); grpc_call_cancel_import = (grpc_call_cancel_type) GetProcAddress(library, "grpc_call_cancel"); grpc_call_cancel_with_status_import = (grpc_call_cancel_with_status_type) GetProcAddress(library, "grpc_call_cancel_with_status"); grpc_call_ref_import = (grpc_call_ref_type) GetProcAddress(library, "grpc_call_ref"); diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h index b2186a69aa9..590a6b2439b 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h @@ -185,6 +185,9 @@ extern grpc_channel_get_trace_type grpc_channel_get_trace_import; typedef intptr_t(*grpc_channel_get_uuid_type)(grpc_channel* channel); extern grpc_channel_get_uuid_type grpc_channel_get_uuid_import; #define grpc_channel_get_uuid grpc_channel_get_uuid_import +typedef char*(*grpc_channelz_get_channel_type)(intptr_t channel_id); +extern grpc_channelz_get_channel_type grpc_channelz_get_channel_import; +#define grpc_channelz_get_channel grpc_channelz_get_channel_import typedef grpc_call_error(*grpc_call_cancel_type)(grpc_call* call, void* reserved); extern grpc_call_cancel_type grpc_call_cancel_import; #define grpc_call_cancel grpc_call_cancel_import diff --git a/test/core/channel/BUILD b/test/core/channel/BUILD index c554b20148c..c336688209d 100644 --- a/test/core/channel/BUILD +++ b/test/core/channel/BUILD @@ -84,8 +84,13 @@ grpc_cc_test( ) grpc_cc_test( +<<<<<<< HEAD name = "channelz_registry_test", srcs = ["channelz_registry_test.cc"], +======= + name = "channelz_test", + srcs = ["channelz_test.cc"], +>>>>>>> Add channelz test language = "C++", deps = [ "//:gpr", @@ -93,6 +98,10 @@ grpc_cc_test( "//:grpc++", "//test/core/util:gpr_test_util", "//test/core/util:grpc_test_util", +<<<<<<< HEAD +======= + "//test/cpp/util:channel_trace_proto_helper", +>>>>>>> Add channelz test ], external_deps = [ "gtest", diff --git a/test/core/channel/channelz_test.cc b/test/core/channel/channelz_test.cc new file mode 100644 index 00000000000..503bb9065ba --- /dev/null +++ b/test/core/channel/channelz_test.cc @@ -0,0 +1,57 @@ +/* + * + * 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. + * + */ + +#include +#include + +#include + +#include +#include + +#include "src/core/lib/channel/channel_trace.h" +#include "src/core/lib/channel/channelz_registry.h" +#include "src/core/lib/gpr/useful.h" +#include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/json/json.h" + +#include "test/core/util/test_config.h" +#include "test/cpp/util/channel_trace_proto_helper.h" + +// remove me +#include +#include +#include + +namespace grpc_core { +namespace testing { +namespace {} // anonymous namespace + +TEST(ChannelzTest, Channel) {} + +} // namespace testing +} // namespace grpc_core + +int main(int argc, char** argv) { + grpc_test_init(argc, argv); + grpc_init(); + ::testing::InitGoogleTest(&argc, argv); + int ret = RUN_ALL_TESTS(); + grpc_shutdown(); + return ret; +} diff --git a/test/core/end2end/fuzzers/api_fuzzer.cc b/test/core/end2end/fuzzers/api_fuzzer.cc index 36f257d6dab..ba9c04fd0e8 100644 --- a/test/core/end2end/fuzzers/api_fuzzer.cc +++ b/test/core/end2end/fuzzers/api_fuzzer.cc @@ -1048,6 +1048,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { op->reserved = nullptr; op->flags = grpc_fuzzer_get_next_uint32(&inp); } + if (g_channel == nullptr) ok = false; if (ok) { validator* v = make_finished_batch_validator(g_active_call, has_ops); g_active_call->pending_ops++; diff --git a/test/core/end2end/tests/simple_request.cc b/test/core/end2end/tests/simple_request.cc index 941d9ae3198..6e36e54cd37 100644 --- a/test/core/end2end/tests/simple_request.cc +++ b/test/core/end2end/tests/simple_request.cc @@ -21,6 +21,9 @@ #include #include +#include "src/core/ext/filters/client_channel/client_channel.h" +#include "src/core/lib/surface/channel.h" + #include #include #include @@ -198,6 +201,10 @@ static void simple_request_body(grpc_end2end_test_config config, CQ_EXPECT_COMPLETION(cqv, tag(1), 1); cq_verify(cqv); + char* json = grpc_channel_render_channelz(f.client); + gpr_log(GPR_ERROR, "%s", json); + gpr_free(json); + GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED); GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz")); // the following sanity check makes sure that the requested error string is diff --git a/test/core/surface/public_headers_must_be_c89.c b/test/core/surface/public_headers_must_be_c89.c index 52a1b039980..bc9c2f2a13e 100644 --- a/test/core/surface/public_headers_must_be_c89.c +++ b/test/core/surface/public_headers_must_be_c89.c @@ -108,6 +108,7 @@ int main(int argc, char **argv) { printf("%lx", (unsigned long) grpc_channel_destroy); printf("%lx", (unsigned long) grpc_channel_get_trace); printf("%lx", (unsigned long) grpc_channel_get_uuid); + printf("%lx", (unsigned long) grpc_channelz_get_channel); printf("%lx", (unsigned long) grpc_call_cancel); printf("%lx", (unsigned long) grpc_call_cancel_with_status); printf("%lx", (unsigned long) grpc_call_ref); diff --git a/test/cpp/util/channel_trace_proto_helper.cc b/test/cpp/util/channel_trace_proto_helper.cc index c395f607f48..db9390163bc 100644 --- a/test/cpp/util/channel_trace_proto_helper.cc +++ b/test/cpp/util/channel_trace_proto_helper.cc @@ -30,26 +30,42 @@ namespace grpc { namespace testing { -void ValidateChannelTraceProtoJsonTranslation(char* tracer_json_c_str) { - std::string tracer_json_str(tracer_json_c_str); - grpc::channelz::v1::ChannelTrace channel_trace; +namespace { + +// Generic helper that takes in a json string, converts it to a proto, and +// then back to json. This ensures that the json string was correctly formatted +// according to https://developers.google.com/protocol-buffers/docs/proto3#json +template +void VaidateProtoJsonTranslation(char* json_c_str) { + std::string json_str(json_c_str); + Message msg; google::protobuf::util::JsonParseOptions parse_options; // If the following line is failing, then uncomment the last line of the // comment, and uncomment the lines that print the two strings. You can // then compare the output, and determine what fields are missing. // // parse_options.ignore_unknown_fields = true; - ASSERT_EQ(google::protobuf::util::JsonStringToMessage( - tracer_json_str, &channel_trace, parse_options), + ASSERT_EQ(google::protobuf::util::JsonStringToMessage(json_str, &msg, + parse_options), google::protobuf::util::Status::OK); std::string proto_json_str; - ASSERT_EQ(google::protobuf::util::MessageToJsonString(channel_trace, - &proto_json_str), + ASSERT_EQ(google::protobuf::util::MessageToJsonString(msg, &proto_json_str), google::protobuf::util::Status::OK); // uncomment these to compare the the json strings. - // gpr_log(GPR_ERROR, "tracer json: %s", tracer_json_str.c_str()); + // gpr_log(GPR_ERROR, "tracer json: %s", json_str.c_str()); // gpr_log(GPR_ERROR, "proto json: %s", proto_json_str.c_str()); - ASSERT_EQ(tracer_json_str, proto_json_str); + ASSERT_EQ(json_str, proto_json_str); +} + +} // namespace + +void ValidateChannelTraceProtoJsonTranslation(char* tracer_json_c_str) { + VaidateProtoJsonTranslation( + tracer_json_c_str); +} + +void ValidateChannelProtoJsonTranslation(char* channel_json_c_str) { + VaidateProtoJsonTranslation(channel_json_c_str); } } // namespace testing diff --git a/test/cpp/util/channel_trace_proto_helper.h b/test/cpp/util/channel_trace_proto_helper.h index d7043d9f063..d1a36033725 100644 --- a/test/cpp/util/channel_trace_proto_helper.h +++ b/test/cpp/util/channel_trace_proto_helper.h @@ -23,6 +23,7 @@ namespace grpc { namespace testing { void ValidateChannelTraceProtoJsonTranslation(char* tracer_json_c_str); +void ValidateChannelProtoJsonTranslation(char* channel_json_c_str); } // namespace testing } // namespace grpc diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index ea2f377c917..3e3c4dd7771 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -1012,6 +1012,7 @@ src/core/lib/channel/channel_args.h \ src/core/lib/channel/channel_stack.h \ src/core/lib/channel/channel_stack_builder.h \ src/core/lib/channel/channel_trace.h \ +src/core/lib/channel/channelz.h \ src/core/lib/channel/channelz_registry.h \ src/core/lib/channel/connected_channel.h \ src/core/lib/channel/context.h \ diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 589e862b9a8..f95e0f38dbe 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -1038,6 +1038,8 @@ src/core/lib/channel/channel_stack_builder.cc \ src/core/lib/channel/channel_stack_builder.h \ src/core/lib/channel/channel_trace.cc \ src/core/lib/channel/channel_trace.h \ +src/core/lib/channel/channelz.cc \ +src/core/lib/channel/channelz.h \ src/core/lib/channel/channelz_registry.cc \ src/core/lib/channel/channelz_registry.h \ src/core/lib/channel/connected_channel.cc \ diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index 0af4e19a1ad..46508d47494 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -3068,8 +3068,6 @@ "gpr_test_util", "grpc", "grpc++", - "grpc++_channelz_proto", - "grpc++_test", "grpc++_test_util", "grpc_test_util" ], @@ -3103,6 +3101,27 @@ "third_party": false, "type": "target" }, + { + "deps": [ + "gpr", + "gpr_test_util", + "grpc", + "grpc++", + "grpc++_channelz_proto", + "grpc++_test", + "grpc++_test_util", + "grpc_test_util" + ], + "headers": [], + "is_filegroup": false, + "language": "c++", + "name": "channelz_test", + "src": [ + "test/core/channel/channelz_test.cc" + ], + "third_party": false, + "type": "target" + }, { "deps": [ "gpr", @@ -9294,6 +9313,7 @@ "src/core/lib/channel/channel_stack.cc", "src/core/lib/channel/channel_stack_builder.cc", "src/core/lib/channel/channel_trace.cc", + "src/core/lib/channel/channelz.cc", "src/core/lib/channel/channelz_registry.cc", "src/core/lib/channel/connected_channel.cc", "src/core/lib/channel/handshaker.cc", @@ -9465,6 +9485,7 @@ "src/core/lib/channel/channel_stack.h", "src/core/lib/channel/channel_stack_builder.h", "src/core/lib/channel/channel_trace.h", + "src/core/lib/channel/channelz.h", "src/core/lib/channel/channelz_registry.h", "src/core/lib/channel/connected_channel.h", "src/core/lib/channel/context.h", @@ -9614,6 +9635,7 @@ "src/core/lib/channel/channel_stack.h", "src/core/lib/channel/channel_stack_builder.h", "src/core/lib/channel/channel_trace.h", + "src/core/lib/channel/channelz.h", "src/core/lib/channel/channelz_registry.h", "src/core/lib/channel/connected_channel.h", "src/core/lib/channel/context.h", diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index 00604f181c6..0a02b1df05f 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -3693,6 +3693,30 @@ ], "uses_polling": false }, + { + "args": [], + "benchmark": false, + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": true, + "language": "c++", + "name": "channelz_test", + "platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "uses_polling": true + }, { "args": [], "benchmark": false, From 23c50fda51a38d0484f4b1537492fd93eeae33ac Mon Sep 17 00:00:00 2001 From: ncteisen Date: Fri, 18 May 2018 16:38:29 -0700 Subject: [PATCH 03/57] Incorperate channel trace into channelz --- src/core/lib/channel/channel_trace.cc | 37 +++++++++++++++------------ src/core/lib/channel/channel_trace.h | 21 ++++++++------- src/core/lib/channel/channelz.cc | 13 +++++++--- src/core/lib/channel/channelz.h | 9 ++++++- src/core/lib/surface/channel.cc | 19 +++++++------- 5 files changed, 58 insertions(+), 41 deletions(-) diff --git a/src/core/lib/channel/channel_trace.cc b/src/core/lib/channel/channel_trace.cc index 84f7f000f72..efa034a1887 100644 --- a/src/core/lib/channel/channel_trace.cc +++ b/src/core/lib/channel/channel_trace.cc @@ -40,16 +40,17 @@ #include "src/core/lib/transport/error_utils.h" namespace grpc_core { +namespace channelz { -ChannelTrace::TraceEvent::TraceEvent( - Severity severity, grpc_slice data, - RefCountedPtr referenced_tracer, ReferencedType type) +ChannelTrace::TraceEvent::TraceEvent(Severity severity, grpc_slice data, + RefCountedPtr referenced_channel, + ReferencedType type) : severity_(severity), data_(data), timestamp_(grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(), GPR_CLOCK_REALTIME)), next_(nullptr), - referenced_tracer_(std::move(referenced_tracer)), + referenced_channel_(std::move(referenced_channel)), referenced_type_(type) {} ChannelTrace::TraceEvent::TraceEvent(Severity severity, grpc_slice data) @@ -117,20 +118,21 @@ void ChannelTrace::AddTraceEvent(Severity severity, grpc_slice data) { void ChannelTrace::AddTraceEventReferencingChannel( Severity severity, grpc_slice data, - RefCountedPtr referenced_tracer) { + RefCountedPtr referenced_channel) { if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0 // create and fill up the new event - AddTraceEventHelper( - New(severity, data, std::move(referenced_tracer), Channel)); + AddTraceEventHelper(New( + severity, data, std::move(referenced_channel), ReferencedType::Channel)); } void ChannelTrace::AddTraceEventReferencingSubchannel( Severity severity, grpc_slice data, - RefCountedPtr referenced_tracer) { + RefCountedPtr referenced_channel) { if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0 // create and fill up the new event - AddTraceEventHelper(New( - severity, data, std::move(referenced_tracer), Subchannel)); + AddTraceEventHelper(New(severity, data, + std::move(referenced_channel), + ReferencedType::Subchannel)); } namespace { @@ -193,17 +195,19 @@ void ChannelTrace::TraceEvent::RenderTraceEvent(grpc_json* json) const { json_iterator = grpc_json_create_child(json_iterator, json, "timestamp", fmt_time(timestamp_), GRPC_JSON_STRING, true); - if (referenced_tracer_ != nullptr) { + if (referenced_channel_ != nullptr) { char* uuid_str; - gpr_asprintf(&uuid_str, "%" PRIdPTR, referenced_tracer_->channel_uuid_); + gpr_asprintf(&uuid_str, "%" PRIdPTR, referenced_channel_->channel_uuid()); grpc_json* child_ref = grpc_json_create_child( json_iterator, json, - (referenced_type_ == Channel) ? "channelRef" : "subchannelRef", nullptr, - GRPC_JSON_OBJECT, false); + (referenced_type_ == ReferencedType::Channel) ? "channelRef" + : "subchannelRef", + nullptr, GRPC_JSON_OBJECT, false); json_iterator = grpc_json_create_child( nullptr, child_ref, - (referenced_type_ == Channel) ? "channelId" : "subchannelId", uuid_str, - GRPC_JSON_STRING, true); + (referenced_type_ == ReferencedType::Channel) ? "channelId" + : "subchannelId", + uuid_str, GRPC_JSON_STRING, true); json_iterator = child_ref; } } @@ -236,4 +240,5 @@ char* ChannelTrace::RenderTrace() const { return json_str; } +} // namespace channelz } // namespace grpc_core diff --git a/src/core/lib/channel/channel_trace.h b/src/core/lib/channel/channel_trace.h index 1df1e585f25..687c6bc0630 100644 --- a/src/core/lib/channel/channel_trace.h +++ b/src/core/lib/channel/channel_trace.h @@ -28,11 +28,14 @@ #include "src/core/lib/json/json.h" namespace grpc_core { +namespace channelz { + +class Channel; // Object used to hold live data for a channel. This data is exposed via the // channelz service: // https://github.com/grpc/proposal/blob/master/A14-channelz.md -class ChannelTrace : public RefCounted { +class ChannelTrace { public: ChannelTrace(size_t max_events); ~ChannelTrace(); @@ -59,17 +62,15 @@ class ChannelTrace : public RefCounted { // created a new subchannel, then it would record that with a TraceEvent // referencing the new subchannel. // - // TODO(ncteisen): Once channelz is implemented, the events should reference - // the overall channelz object, not just the ChannelTrace object. // TODO(ncteisen): as this call is used more and more throughout the gRPC // stack, determine if it makes more sense to accept a char* instead of a // slice. void AddTraceEventReferencingChannel( Severity severity, grpc_slice data, - RefCountedPtr referenced_tracer); + RefCountedPtr referenced_tracer); void AddTraceEventReferencingSubchannel( Severity severity, grpc_slice data, - RefCountedPtr referenced_tracer); + RefCountedPtr referenced_tracer); // Returns the tracing data rendered as a grpc json string. // The string is owned by the caller and must be freed. @@ -77,17 +78,14 @@ class ChannelTrace : public RefCounted { private: // Types of objects that can be references by trace events. - enum ReferencedType { Channel, Subchannel }; + enum class ReferencedType { Channel, Subchannel }; // Private class to encapsulate all the data and bookkeeping needed for a // a trace event. class TraceEvent { public: // Constructor for a TraceEvent that references a different channel. - // TODO(ncteisen): once channelz is implemented, this should reference the - // overall channelz object, not just the ChannelTrace object TraceEvent(Severity severity, grpc_slice data, - RefCountedPtr referenced_tracer, - ReferencedType type); + RefCountedPtr referenced_tracer, ReferencedType type); // Constructor for a TraceEvent that does not reverence a different // channel. @@ -109,7 +107,7 @@ class ChannelTrace : public RefCounted { gpr_timespec timestamp_; TraceEvent* next_; // the tracer object for the (sub)channel that this trace event refers to. - RefCountedPtr referenced_tracer_; + RefCountedPtr referenced_channel_; // the type that the referenced tracer points to. Unused if this trace // does not point to any channel or subchannel ReferencedType referenced_type_; @@ -128,6 +126,7 @@ class ChannelTrace : public RefCounted { gpr_timespec time_created_; }; +} // namespace channelz } // namespace grpc_core #endif /* GRPC_CORE_LIB_CHANNEL_CHANNEL_TRACE_H */ diff --git a/src/core/lib/channel/channelz.cc b/src/core/lib/channel/channelz.cc index aabc941dcd5..cf7545621e5 100644 --- a/src/core/lib/channel/channelz.cc +++ b/src/core/lib/channel/channelz.cc @@ -91,7 +91,9 @@ grpc_json* add_num_str(grpc_json* parent, grpc_json* it, const char* name, } // namespace -Channel::Channel(grpc_channel* channel) : channel_(channel) { +Channel::Channel(grpc_channel* channel, size_t channel_tracer_max_nodes) + : channel_(channel) { + trace_.Init(channel_tracer_max_nodes); target_ = grpc_channel_get_target(channel_); channel_uuid_ = ChannelzRegistry::Register(this); } @@ -103,8 +105,8 @@ Channel::~Channel() { void Channel::CallStarted() { calls_started_++; - last_call_started_timestamp_ = grpc_millis_to_timespec( - grpc_core::ExecCtx::Get()->Now(), GPR_CLOCK_REALTIME); + last_call_started_timestamp_ = + grpc_millis_to_timespec(ExecCtx::Get()->Now(), GPR_CLOCK_REALTIME); } grpc_connectivity_state Channel::GetConnectivityState() { @@ -153,6 +155,11 @@ char* Channel::RenderJSON() { grpc_json_create_child(json_iterator, json, "state", grpc_connectivity_state_name(connectivity_state), GRPC_JSON_STRING, false); + char* trace = trace_->RenderTrace(); + if (trace != nullptr) { + json_iterator = grpc_json_create_child(json_iterator, json, "trace", trace, + GRPC_JSON_STRING, true); + } // render and return the over json object char* json_str = grpc_json_dump_to_string(top_level_json, 0); diff --git a/src/core/lib/channel/channelz.h b/src/core/lib/channel/channelz.h index 661228cf446..7cea00392f5 100644 --- a/src/core/lib/channel/channelz.h +++ b/src/core/lib/channel/channelz.h @@ -24,6 +24,8 @@ #include #include "src/core/ext/filters/client_channel/client_channel.h" +#include "src/core/lib/channel/channel_trace.h" +#include "src/core/lib/gprpp/manual_constructor.h" #include "src/core/lib/gprpp/ref_counted.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/iomgr/error.h" @@ -35,7 +37,7 @@ namespace channelz { // owned by the client_channel that it points to and tracks class Channel : public RefCounted { public: - Channel(grpc_channel* channel); + Channel(grpc_channel* channel, size_t channel_tracer_max_nodes); ~Channel(); void CallStarted(); @@ -44,11 +46,15 @@ class Channel : public RefCounted { char* RenderJSON(); + ChannelTrace* Trace() { return trace_.get(); } + void set_channel_destroyed() { GPR_ASSERT(!channel_destroyed_); channel_destroyed_ = true; } + intptr_t channel_uuid() { return channel_uuid_; } + private: bool channel_destroyed_ = false; grpc_channel* channel_; @@ -58,6 +64,7 @@ class Channel : public RefCounted { uint64_t calls_failed_ = 0; gpr_timespec last_call_started_timestamp_; intptr_t channel_uuid_; + ManualConstructor trace_; grpc_connectivity_state GetConnectivityState(); }; diff --git a/src/core/lib/surface/channel.cc b/src/core/lib/surface/channel.cc index da66a120d57..22760f4ea93 100644 --- a/src/core/lib/surface/channel.cc +++ b/src/core/lib/surface/channel.cc @@ -67,7 +67,6 @@ struct grpc_channel { gpr_mu registered_call_mu; registered_call* registered_calls; - grpc_core::RefCountedPtr tracer; grpc_core::RefCountedPtr channelz_channel; char* target; @@ -147,13 +146,13 @@ grpc_channel* grpc_channel_create_with_builder( } grpc_channel_args_destroy(args); - channel->tracer = grpc_core::MakeRefCounted( - channel_tracer_max_nodes); - channel->tracer->AddTraceEvent( - grpc_core::ChannelTrace::Severity::Info, - grpc_slice_from_static_string("Channel created")); + channel_tracer_max_nodes = 10; channel->channelz_channel = - grpc_core::MakeRefCounted(channel); + grpc_core::MakeRefCounted( + channel, channel_tracer_max_nodes); + channel->channelz_channel->Trace()->AddTraceEvent( + grpc_core::channelz::ChannelTrace::Severity::Info, + grpc_slice_from_static_string("Channel created")); return channel; } @@ -189,7 +188,7 @@ static grpc_channel_args* build_channel_args( } char* grpc_channel_get_trace(grpc_channel* channel) { - return channel->tracer->RenderTrace(); + return channel->channelz_channel->Trace()->RenderTrace(); } char* grpc_channel_render_channelz(grpc_channel* channel) { @@ -202,7 +201,7 @@ grpc_core::channelz::Channel* grpc_channel_get_channelz_channel( } intptr_t grpc_channel_get_uuid(grpc_channel* channel) { - return channel->tracer->GetUuid(); + return channel->channelz_channel->Trace()->GetUuid(); } grpc_channel* grpc_channel_create(const char* target, @@ -416,7 +415,7 @@ static void destroy_channel(void* arg, grpc_error* error) { GRPC_MDELEM_UNREF(rc->authority); gpr_free(rc); } - channel->tracer.reset(); + channel->channelz_channel.reset(); gpr_mu_destroy(&channel->registered_call_mu); gpr_free(channel->target); gpr_free(channel); From 9a1bb051812a53462b2deb7e472f20e3e1dd785f Mon Sep 17 00:00:00 2001 From: ncteisen Date: Wed, 30 May 2018 16:17:06 -0700 Subject: [PATCH 04/57] Build out the channelz unit test --- include/grpc/grpc.h | 3 - src/core/lib/channel/channel_trace.cc | 16 +- src/core/lib/channel/channel_trace.h | 13 +- src/core/lib/channel/channelz.cc | 76 +++++--- src/core/lib/channel/channelz.h | 6 +- src/core/lib/surface/channel.cc | 5 +- test/core/channel/BUILD | 24 ++- test/core/channel/channel_trace_test.cc | 182 +++++++++++--------- test/core/channel/channelz_test.cc | 150 +++++++++++++++- test/cpp/util/channel_trace_proto_helper.cc | 11 +- 10 files changed, 340 insertions(+), 146 deletions(-) diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h index de7c39b1834..dd8a5d7d5f8 100644 --- a/include/grpc/grpc.h +++ b/include/grpc/grpc.h @@ -294,9 +294,6 @@ GRPCAPI char* grpc_channel_get_trace(grpc_channel* channel); later time. */ GRPCAPI intptr_t grpc_channel_get_uuid(grpc_channel* channel); -/** channelz support */ -GRPCAPI char* grpc_channelz_get_channel(intptr_t channel_id); - /** Error handling for grpc_call Most grpc_call functions return a grpc_error. If the error is not GRPC_OK then the operation failed due to some unsatisfied precondition. diff --git a/src/core/lib/channel/channel_trace.cc b/src/core/lib/channel/channel_trace.cc index efa034a1887..c82e42d5459 100644 --- a/src/core/lib/channel/channel_trace.cc +++ b/src/core/lib/channel/channel_trace.cc @@ -28,7 +28,6 @@ #include #include -#include "src/core/lib/channel/channelz_registry.h" #include "src/core/lib/channel/status_util.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/useful.h" @@ -63,15 +62,13 @@ ChannelTrace::TraceEvent::TraceEvent(Severity severity, grpc_slice data) ChannelTrace::TraceEvent::~TraceEvent() { grpc_slice_unref_internal(data_); } ChannelTrace::ChannelTrace(size_t max_events) - : channel_uuid_(-1), - num_events_logged_(0), + : num_events_logged_(0), list_size_(0), max_list_size_(max_events), head_trace_(nullptr), tail_trace_(nullptr) { if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0 gpr_mu_init(&tracer_mu_); - channel_uuid_ = ChannelzRegistry::Register(this); time_created_ = grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(), GPR_CLOCK_REALTIME); } @@ -84,12 +81,9 @@ ChannelTrace::~ChannelTrace() { it = it->next(); Delete(to_free); } - ChannelzRegistry::Unregister(channel_uuid_); gpr_mu_destroy(&tracer_mu_); } -intptr_t ChannelTrace::GetUuid() const { return channel_uuid_; } - void ChannelTrace::AddTraceEventHelper(TraceEvent* new_trace_event) { ++num_events_logged_; // first event case @@ -212,7 +206,7 @@ void ChannelTrace::TraceEvent::RenderTraceEvent(grpc_json* json) const { } } -char* ChannelTrace::RenderTrace() const { +grpc_json* ChannelTrace::RenderJSON() const { if (!max_list_size_) return nullptr; // tracing is disabled if max_events == 0 grpc_json* json = grpc_json_create(GRPC_JSON_OBJECT); @@ -235,6 +229,12 @@ char* ChannelTrace::RenderTrace() const { it->RenderTraceEvent(json_iterator); it = it->next(); } + return json; +} + +char* ChannelTrace::RenderTrace() const { + grpc_json* json = RenderJSON(); + if (json == nullptr) return nullptr; char* json_str = grpc_json_dump_to_string(json, 0); grpc_json_destroy(json); return json_str; diff --git a/src/core/lib/channel/channel_trace.h b/src/core/lib/channel/channel_trace.h index 687c6bc0630..b1224bb96c4 100644 --- a/src/core/lib/channel/channel_trace.h +++ b/src/core/lib/channel/channel_trace.h @@ -40,9 +40,6 @@ class ChannelTrace { ChannelTrace(size_t max_events); ~ChannelTrace(); - // returns the tracer's uuid - intptr_t GetUuid() const; - enum Severity { Unset = 0, // never to be used Info, // we start at 1 to avoid using proto default values @@ -72,8 +69,13 @@ class ChannelTrace { Severity severity, grpc_slice data, RefCountedPtr referenced_tracer); - // Returns the tracing data rendered as a grpc json string. - // The string is owned by the caller and must be freed. + // Creates and returns the raw grpc_json object, so a parent channelz + // object may incorporate the json before rendering. + grpc_json* RenderJSON() const; + + // Returns the tracing data rendered as a grpc json string. The string + // is owned by the caller and must be freed. This is used for testing only + // so that we may unit test ChannelTrace in isolation. char* RenderTrace() const; private: @@ -117,7 +119,6 @@ class ChannelTrace { void AddTraceEventHelper(TraceEvent* new_trace_event); gpr_mu tracer_mu_; - intptr_t channel_uuid_; uint64_t num_events_logged_; size_t list_size_; size_t max_list_size_; diff --git a/src/core/lib/channel/channelz.cc b/src/core/lib/channel/channelz.cc index cf7545621e5..5c3dc97e690 100644 --- a/src/core/lib/channel/channelz.cc +++ b/src/core/lib/channel/channelz.cc @@ -39,9 +39,6 @@ #include "src/core/lib/transport/connectivity_state.h" #include "src/core/lib/transport/error_utils.h" -// TODO(ncteisen): actually implement this -char* grpc_channelz_get_channel(intptr_t channel_id) { return nullptr; } - namespace grpc_core { namespace channelz { @@ -82,9 +79,9 @@ char* fmt_time(gpr_timespec tm) { // TODO(ncteisen); move this to json library grpc_json* add_num_str(grpc_json* parent, grpc_json* it, const char* name, - uint64_t num) { + int64_t num) { char* num_str; - gpr_asprintf(&num_str, "%" PRIu64, num); + gpr_asprintf(&num_str, "%" PRId64, num); return grpc_json_create_child(it, parent, name, num_str, GRPC_JSON_STRING, true); } @@ -96,10 +93,13 @@ Channel::Channel(grpc_channel* channel, size_t channel_tracer_max_nodes) trace_.Init(channel_tracer_max_nodes); target_ = grpc_channel_get_target(channel_); channel_uuid_ = ChannelzRegistry::Register(this); + last_call_started_timestamp_ = + grpc_millis_to_timespec(ExecCtx::Get()->Now(), GPR_CLOCK_REALTIME); } Channel::~Channel() { gpr_free(const_cast(target_)); + trace_.Destroy(); ChannelzRegistry::Unregister(channel_uuid_); } @@ -125,7 +125,7 @@ char* Channel::RenderJSON() { // create and fill the ref child json_iterator = grpc_json_create_child(json_iterator, json, "ref", nullptr, - GRPC_JSON_OBJECT, true); + GRPC_JSON_OBJECT, false); json = json_iterator; json_iterator = nullptr; json_iterator = add_num_str(json, json_iterator, "channelId", channel_uuid_); @@ -134,33 +134,55 @@ char* Channel::RenderJSON() { json = top_level_json; json_iterator = nullptr; - // create and fill the data child - json_iterator = grpc_json_create_child(json_iterator, json, "data", nullptr, - GRPC_JSON_OBJECT, true); - json = json_iterator; + // create and fill the data child. + grpc_json* data = grpc_json_create_child(json_iterator, json, "data", nullptr, + GRPC_JSON_OBJECT, false); + + json = data; json_iterator = nullptr; - json_iterator = - add_num_str(json, json_iterator, "callsStarted", calls_started_); - json_iterator = - add_num_str(json, json_iterator, "callsSucceeded", calls_succeeded_); - json_iterator = - add_num_str(json, json_iterator, "callsFailed", calls_failed_); - json_iterator = grpc_json_create_child( - json_iterator, json, "lastCallStartedTimestamp", - fmt_time(last_call_started_timestamp_), GRPC_JSON_STRING, true); + + // create and fill the connectivity state child. + grpc_connectivity_state connectivity_state = GetConnectivityState(); + json_iterator = grpc_json_create_child(json_iterator, json, "state", nullptr, + GRPC_JSON_OBJECT, false); + json = json_iterator; + grpc_json_create_child(nullptr, json, "state", + grpc_connectivity_state_name(connectivity_state), + GRPC_JSON_STRING, false); + + // reset the parent to be the data object. + json = data; json_iterator = grpc_json_create_child(json_iterator, json, "target", target_, GRPC_JSON_STRING, false); - grpc_connectivity_state connectivity_state = GetConnectivityState(); - json_iterator = - grpc_json_create_child(json_iterator, json, "state", - grpc_connectivity_state_name(connectivity_state), - GRPC_JSON_STRING, false); - char* trace = trace_->RenderTrace(); + + // fill in the channel trace if applicable + grpc_json* trace = trace_->RenderJSON(); if (trace != nullptr) { - json_iterator = grpc_json_create_child(json_iterator, json, "trace", trace, - GRPC_JSON_STRING, true); + // we manuall link up and fill the child since it was created for us in + // ChannelTrace::RenderJSON + json_iterator = grpc_json_link_child(json, trace, json_iterator); + trace->parent = json; + trace->value = nullptr; + trace->key = "trace"; + trace->owns_value = false; } + // reset the parent to be the data object. + json = data; + json_iterator = nullptr; + + // We use -1 as sentinel values since proto default value for integers is + // zero, and the confuses the parser into thinking the value weren't present + json_iterator = add_num_str(json, json_iterator, "callsStarted", + calls_started_ ? calls_started_ : -1); + json_iterator = add_num_str(json, json_iterator, "callsSucceeded", + calls_succeeded_ ? calls_succeeded_ : -1); + json_iterator = add_num_str(json, json_iterator, "callsFailed", + calls_failed_ ? calls_failed_ : -1); + json_iterator = grpc_json_create_child( + json_iterator, json, "lastCallStartedTimestamp", + fmt_time(last_call_started_timestamp_), GRPC_JSON_STRING, true); + // render and return the over json object char* json_str = grpc_json_dump_to_string(top_level_json, 0); grpc_json_destroy(top_level_json); diff --git a/src/core/lib/channel/channelz.h b/src/core/lib/channel/channelz.h index 7cea00392f5..63b90e90a0c 100644 --- a/src/core/lib/channel/channelz.h +++ b/src/core/lib/channel/channelz.h @@ -59,9 +59,9 @@ class Channel : public RefCounted { bool channel_destroyed_ = false; grpc_channel* channel_; const char* target_; - uint64_t calls_started_ = 0; - uint64_t calls_succeeded_ = 0; - uint64_t calls_failed_ = 0; + int64_t calls_started_ = 0; + int64_t calls_succeeded_ = 0; + int64_t calls_failed_ = 0; gpr_timespec last_call_started_timestamp_; intptr_t channel_uuid_; ManualConstructor trace_; diff --git a/src/core/lib/surface/channel.cc b/src/core/lib/surface/channel.cc index 22760f4ea93..be9869b08c4 100644 --- a/src/core/lib/surface/channel.cc +++ b/src/core/lib/surface/channel.cc @@ -146,7 +146,6 @@ grpc_channel* grpc_channel_create_with_builder( } grpc_channel_args_destroy(args); - channel_tracer_max_nodes = 10; channel->channelz_channel = grpc_core::MakeRefCounted( channel, channel_tracer_max_nodes); @@ -201,7 +200,7 @@ grpc_core::channelz::Channel* grpc_channel_get_channelz_channel( } intptr_t grpc_channel_get_uuid(grpc_channel* channel) { - return channel->channelz_channel->Trace()->GetUuid(); + return channel->channelz_channel->channel_uuid(); } grpc_channel* grpc_channel_create(const char* target, @@ -430,6 +429,8 @@ void grpc_channel_destroy(grpc_channel* channel) { GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel Destroyed"); elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CHANNEL(channel), 0); elem->filter->start_transport_op(elem, op); + channel->channelz_channel->set_channel_destroyed(); + channel->channelz_channel.reset(); GRPC_CHANNEL_INTERNAL_UNREF(channel, "channel"); } diff --git a/test/core/channel/BUILD b/test/core/channel/BUILD index c336688209d..81c43531293 100644 --- a/test/core/channel/BUILD +++ b/test/core/channel/BUILD @@ -84,13 +84,8 @@ grpc_cc_test( ) grpc_cc_test( -<<<<<<< HEAD - name = "channelz_registry_test", - srcs = ["channelz_registry_test.cc"], -======= name = "channelz_test", srcs = ["channelz_test.cc"], ->>>>>>> Add channelz test language = "C++", deps = [ "//:gpr", @@ -98,10 +93,23 @@ grpc_cc_test( "//:grpc++", "//test/core/util:gpr_test_util", "//test/core/util:grpc_test_util", -<<<<<<< HEAD -======= "//test/cpp/util:channel_trace_proto_helper", ->>>>>>> Add channelz test + ], + external_deps = [ + "gtest", + ], +) + +grpc_cc_test( + name = "channelz_registry_test", + srcs = ["channelz_registry_test.cc"], + language = "C++", + deps = [ + "//:gpr", + "//:grpc", + "//:grpc++", + "//test/core/util:gpr_test_util", + "//test/core/util:grpc_test_util", ], external_deps = [ "gtest", diff --git a/test/core/channel/channel_trace_test.cc b/test/core/channel/channel_trace_test.cc index 9befdb4fa37..c8619be0074 100644 --- a/test/core/channel/channel_trace_test.cc +++ b/test/core/channel/channel_trace_test.cc @@ -25,6 +25,7 @@ #include #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/gpr/useful.h" #include "src/core/lib/iomgr/exec_ctx.h" @@ -39,6 +40,7 @@ #include namespace grpc_core { +namespace channelz { namespace testing { namespace { @@ -77,13 +79,13 @@ void ValidateChannelTraceData(grpc_json* json, ValidateJsonArraySize(json, "events", actual_num_events_expected); } -void AddSimpleTrace(RefCountedPtr tracer) { +void AddSimpleTrace(ChannelTrace* tracer) { tracer->AddTraceEvent(ChannelTrace::Severity::Info, grpc_slice_from_static_string("simple trace")); } // checks for the existence of all the required members of the tracer. -void ValidateChannelTrace(RefCountedPtr tracer, +void ValidateChannelTrace(ChannelTrace* tracer, size_t expected_num_event_logged, size_t max_nodes) { if (!max_nodes) return; char* json_str = tracer->RenderTrace(); @@ -95,16 +97,26 @@ void ValidateChannelTrace(RefCountedPtr tracer, gpr_free(json_str); } -void ValidateTraceDataMatchedUuidLookup(RefCountedPtr tracer) { - intptr_t uuid = tracer->GetUuid(); - if (uuid == -1) return; // Doesn't make sense to lookup if tracing disabled - char* tracer_json_str = tracer->RenderTrace(); - ChannelTrace* uuid_lookup = ChannelzRegistry::Get(uuid); - char* uuid_lookup_json_str = uuid_lookup->RenderTrace(); - EXPECT_EQ(strcmp(tracer_json_str, uuid_lookup_json_str), 0); - gpr_free(tracer_json_str); - gpr_free(uuid_lookup_json_str); -} +class ChannelFixture { + public: + ChannelFixture(int max_trace_nodes) { + grpc_arg client_a; + client_a.type = GRPC_ARG_INTEGER; + client_a.key = + const_cast(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE); + client_a.value.integer = max_trace_nodes; + grpc_channel_args client_args = {1, &client_a}; + channel_ = + grpc_insecure_channel_create("fake_target", &client_args, nullptr); + } + + ~ChannelFixture() { grpc_channel_destroy(channel_); } + + grpc_channel* channel() { return channel_; } + + private: + grpc_channel* channel_; +}; } // anonymous namespace @@ -114,25 +126,22 @@ class ChannelTracerTest : public ::testing::TestWithParam {}; // lookups by uuid. TEST_P(ChannelTracerTest, BasicTest) { grpc_core::ExecCtx exec_ctx; - RefCountedPtr tracer = MakeRefCounted(GetParam()); - AddSimpleTrace(tracer); - AddSimpleTrace(tracer); - ValidateTraceDataMatchedUuidLookup(tracer); - tracer->AddTraceEvent(ChannelTrace::Severity::Info, - grpc_slice_from_static_string("trace three")); - tracer->AddTraceEvent(ChannelTrace::Severity::Error, - grpc_slice_from_static_string("trace four error")); - ValidateChannelTrace(tracer, 4, GetParam()); - AddSimpleTrace(tracer); - AddSimpleTrace(tracer); - ValidateChannelTrace(tracer, 6, GetParam()); - AddSimpleTrace(tracer); - AddSimpleTrace(tracer); - AddSimpleTrace(tracer); - AddSimpleTrace(tracer); - ValidateChannelTrace(tracer, 10, GetParam()); - ValidateTraceDataMatchedUuidLookup(tracer); - tracer.reset(nullptr); + ChannelTrace tracer(GetParam()); + AddSimpleTrace(&tracer); + AddSimpleTrace(&tracer); + tracer.AddTraceEvent(ChannelTrace::Severity::Info, + grpc_slice_from_static_string("trace three")); + tracer.AddTraceEvent(ChannelTrace::Severity::Error, + grpc_slice_from_static_string("trace four error")); + ValidateChannelTrace(&tracer, 4, GetParam()); + AddSimpleTrace(&tracer); + AddSimpleTrace(&tracer); + ValidateChannelTrace(&tracer, 6, GetParam()); + AddSimpleTrace(&tracer); + AddSimpleTrace(&tracer); + AddSimpleTrace(&tracer); + AddSimpleTrace(&tracer); + ValidateChannelTrace(&tracer, 10, GetParam()); } // Tests more complex functionality, like a parent channel tracking @@ -140,42 +149,43 @@ TEST_P(ChannelTracerTest, BasicTest) { // and this function will both hold refs to the subchannel. TEST_P(ChannelTracerTest, ComplexTest) { grpc_core::ExecCtx exec_ctx; - RefCountedPtr tracer = MakeRefCounted(GetParam()); - AddSimpleTrace(tracer); - AddSimpleTrace(tracer); - RefCountedPtr sc1 = MakeRefCounted(GetParam()); - tracer->AddTraceEventReferencingSubchannel( + ChannelTrace tracer(GetParam()); + AddSimpleTrace(&tracer); + AddSimpleTrace(&tracer); + ChannelFixture channel1(GetParam()); + RefCountedPtr sc1 = + MakeRefCounted(channel1.channel(), GetParam()); + tracer.AddTraceEventReferencingSubchannel( ChannelTrace::Severity::Info, grpc_slice_from_static_string("subchannel one created"), sc1); - ValidateChannelTrace(tracer, 3, GetParam()); - AddSimpleTrace(sc1); - AddSimpleTrace(sc1); - AddSimpleTrace(sc1); - ValidateChannelTrace(sc1, 3, GetParam()); - AddSimpleTrace(sc1); - AddSimpleTrace(sc1); - AddSimpleTrace(sc1); - ValidateChannelTrace(sc1, 6, GetParam()); - AddSimpleTrace(tracer); - AddSimpleTrace(tracer); - ValidateChannelTrace(tracer, 5, GetParam()); - ValidateTraceDataMatchedUuidLookup(tracer); - RefCountedPtr sc2 = MakeRefCounted(GetParam()); - tracer->AddTraceEventReferencingChannel( + ValidateChannelTrace(&tracer, 3, GetParam()); + AddSimpleTrace(sc1->Trace()); + AddSimpleTrace(sc1->Trace()); + AddSimpleTrace(sc1->Trace()); + ValidateChannelTrace(sc1->Trace(), 3, GetParam()); + AddSimpleTrace(sc1->Trace()); + AddSimpleTrace(sc1->Trace()); + AddSimpleTrace(sc1->Trace()); + ValidateChannelTrace(sc1->Trace(), 6, GetParam()); + AddSimpleTrace(&tracer); + AddSimpleTrace(&tracer); + ValidateChannelTrace(&tracer, 5, GetParam()); + ChannelFixture channel2(GetParam()); + RefCountedPtr sc2 = + MakeRefCounted(channel2.channel(), GetParam()); + tracer.AddTraceEventReferencingChannel( ChannelTrace::Severity::Info, grpc_slice_from_static_string("LB channel two created"), sc2); - tracer->AddTraceEventReferencingSubchannel( + tracer.AddTraceEventReferencingSubchannel( ChannelTrace::Severity::Warning, grpc_slice_from_static_string("subchannel one inactive"), sc1); - ValidateChannelTrace(tracer, 7, GetParam()); - AddSimpleTrace(tracer); - AddSimpleTrace(tracer); - AddSimpleTrace(tracer); - AddSimpleTrace(tracer); - AddSimpleTrace(tracer); - AddSimpleTrace(tracer); - ValidateTraceDataMatchedUuidLookup(tracer); - tracer.reset(nullptr); + ValidateChannelTrace(&tracer, 7, GetParam()); + AddSimpleTrace(&tracer); + AddSimpleTrace(&tracer); + AddSimpleTrace(&tracer); + AddSimpleTrace(&tracer); + AddSimpleTrace(&tracer); + AddSimpleTrace(&tracer); sc1.reset(nullptr); sc2.reset(nullptr); } @@ -185,39 +195,44 @@ TEST_P(ChannelTracerTest, ComplexTest) { // gets deleted. TEST_P(ChannelTracerTest, TestNesting) { grpc_core::ExecCtx exec_ctx; - RefCountedPtr tracer = MakeRefCounted(GetParam()); - AddSimpleTrace(tracer); - AddSimpleTrace(tracer); - ValidateChannelTrace(tracer, 2, GetParam()); - RefCountedPtr sc1 = MakeRefCounted(GetParam()); - tracer->AddTraceEventReferencingChannel( + ChannelTrace tracer(GetParam()); + AddSimpleTrace(&tracer); + AddSimpleTrace(&tracer); + ValidateChannelTrace(&tracer, 2, GetParam()); + ChannelFixture channel1(GetParam()); + RefCountedPtr sc1 = + MakeRefCounted(channel1.channel(), GetParam()); + tracer.AddTraceEventReferencingChannel( ChannelTrace::Severity::Info, grpc_slice_from_static_string("subchannel one created"), sc1); - ValidateChannelTrace(tracer, 3, GetParam()); - AddSimpleTrace(sc1); - RefCountedPtr conn1 = MakeRefCounted(GetParam()); + ValidateChannelTrace(&tracer, 3, GetParam()); + AddSimpleTrace(sc1->Trace()); + ChannelFixture channel2(GetParam()); + RefCountedPtr conn1 = + MakeRefCounted(channel2.channel(), GetParam()); // nesting one level deeper. - sc1->AddTraceEventReferencingSubchannel( + sc1->Trace()->AddTraceEventReferencingSubchannel( ChannelTrace::Severity::Info, grpc_slice_from_static_string("connection one created"), conn1); - ValidateChannelTrace(tracer, 3, GetParam()); - AddSimpleTrace(conn1); - AddSimpleTrace(tracer); - AddSimpleTrace(tracer); - ValidateChannelTrace(tracer, 5, GetParam()); - ValidateChannelTrace(conn1, 1, GetParam()); - RefCountedPtr sc2 = MakeRefCounted(GetParam()); - tracer->AddTraceEventReferencingSubchannel( + ValidateChannelTrace(&tracer, 3, GetParam()); + AddSimpleTrace(conn1->Trace()); + AddSimpleTrace(&tracer); + AddSimpleTrace(&tracer); + ValidateChannelTrace(&tracer, 5, GetParam()); + ValidateChannelTrace(conn1->Trace(), 1, GetParam()); + ChannelFixture channel3(GetParam()); + RefCountedPtr sc2 = + MakeRefCounted(channel3.channel(), GetParam()); + tracer.AddTraceEventReferencingSubchannel( ChannelTrace::Severity::Info, grpc_slice_from_static_string("subchannel two created"), sc2); // this trace should not get added to the parents children since it is already // present in the tracer. - tracer->AddTraceEventReferencingChannel( + tracer.AddTraceEventReferencingChannel( ChannelTrace::Severity::Warning, grpc_slice_from_static_string("subchannel one inactive"), sc1); - AddSimpleTrace(tracer); - ValidateChannelTrace(tracer, 8, GetParam()); - tracer.reset(nullptr); + AddSimpleTrace(&tracer); + ValidateChannelTrace(&tracer, 8, GetParam()); sc1.reset(nullptr); sc2.reset(nullptr); conn1.reset(nullptr); @@ -227,6 +242,7 @@ INSTANTIATE_TEST_CASE_P(ChannelTracerTestSweep, ChannelTracerTest, ::testing::Values(0, 1, 2, 6, 10, 15)); } // namespace testing +} // namespace channelz } // namespace grpc_core int main(int argc, char** argv) { diff --git a/test/core/channel/channelz_test.cc b/test/core/channel/channelz_test.cc index 503bb9065ba..c4606426095 100644 --- a/test/core/channel/channelz_test.cc +++ b/test/core/channel/channelz_test.cc @@ -25,26 +25,170 @@ #include #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/gpr/useful.h" #include "src/core/lib/iomgr/exec_ctx.h" #include "src/core/lib/json/json.h" +#include "src/core/lib/surface/channel.h" #include "test/core/util/test_config.h" #include "test/cpp/util/channel_trace_proto_helper.h" -// remove me #include #include #include namespace grpc_core { +namespace channelz { namespace testing { -namespace {} // anonymous namespace +namespace { -TEST(ChannelzTest, Channel) {} +grpc_json* GetJsonChild(grpc_json* parent, const char* key) { + EXPECT_NE(parent, nullptr); + for (grpc_json* child = parent->child; child != nullptr; + child = child->next) { + if (child->key != nullptr && strcmp(child->key, key) == 0) return child; + } + return nullptr; +} + +class ChannelFixture { + public: + ChannelFixture(int max_trace_nodes) { + grpc_arg client_a; + client_a.type = GRPC_ARG_INTEGER; + client_a.key = + const_cast(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE); + client_a.value.integer = max_trace_nodes; + grpc_channel_args client_args = {1, &client_a}; + channel_ = + grpc_insecure_channel_create("fake_target", &client_args, nullptr); + } + + ~ChannelFixture() { grpc_channel_destroy(channel_); } + + grpc_channel* channel() { return channel_; } + + private: + grpc_channel* channel_; +}; + +struct validate_channel_data_args { + int64_t calls_started; + int64_t calls_failed; + int64_t calls_succeeded; +}; + +void ValidateChildInteger(grpc_json* json, int64_t expect, const char* key) { + grpc_json* gotten_json = GetJsonChild(json, key); + EXPECT_NE(gotten_json, nullptr); + int64_t gotten_number = (int64_t)strtol(gotten_json->value, nullptr, 0); + EXPECT_EQ(gotten_number, expect); +} + +void ValidateChannel(Channel* channel, validate_channel_data_args args) { + char* json_str = channel->RenderJSON(); + grpc::testing::ValidateChannelProtoJsonTranslation(json_str); + grpc_json* json = grpc_json_parse_string(json_str); + EXPECT_NE(json, nullptr); + grpc_json* data = GetJsonChild(json, "data"); + ValidateChildInteger(data, args.calls_started, "callsStarted"); + ValidateChildInteger(data, args.calls_failed, "callsFailed"); + ValidateChildInteger(data, args.calls_succeeded, "callsSucceeded"); + grpc_json_destroy(json); + gpr_free(json_str); +} + +char* GetLastCallStartedTimestamp(Channel* channel) { + char* json_str = channel->RenderJSON(); + grpc_json* json = grpc_json_parse_string(json_str); + grpc_json* data = GetJsonChild(json, "data"); + grpc_json* timestamp = GetJsonChild(data, "lastCallStartedTimestamp"); + char* ts_str = grpc_json_dump_to_string(timestamp, 0); + grpc_json_destroy(json); + gpr_free(json_str); + return ts_str; +} + +void ChannelzSleep(int64_t sleep_us) { + gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), + gpr_time_from_micros(sleep_us, GPR_TIMESPAN))); + grpc_core::ExecCtx::Get()->InvalidateNow(); +} + +} // anonymous namespace + +class ChannelzChannelTest : public ::testing::TestWithParam {}; + +TEST_P(ChannelzChannelTest, BasicChannel) { + grpc_core::ExecCtx exec_ctx; + ChannelFixture channel(GetParam()); + intptr_t uuid = grpc_channel_get_uuid(channel.channel()); + Channel* channelz_channel = ChannelzRegistry::Get(uuid); + ValidateChannel(channelz_channel, {-1, -1, -1}); +} + +TEST_P(ChannelzChannelTest, BasicChannelAPIFunctionality) { + grpc_core::ExecCtx exec_ctx; + ChannelFixture channel(GetParam()); + intptr_t uuid = grpc_channel_get_uuid(channel.channel()); + Channel* channelz_channel = ChannelzRegistry::Get(uuid); + channelz_channel->CallStarted(); + channelz_channel->CallFailed(); + channelz_channel->CallSucceeded(); + ValidateChannel(channelz_channel, {1, 1, 1}); + channelz_channel->CallStarted(); + channelz_channel->CallFailed(); + channelz_channel->CallSucceeded(); + channelz_channel->CallStarted(); + channelz_channel->CallFailed(); + channelz_channel->CallSucceeded(); + ValidateChannel(channelz_channel, {3, 3, 3}); +} + +TEST_P(ChannelzChannelTest, LastCallStartedTimestamp) { + grpc_core::ExecCtx exec_ctx; + ChannelFixture channel(GetParam()); + intptr_t uuid = grpc_channel_get_uuid(channel.channel()); + Channel* channelz_channel = ChannelzRegistry::Get(uuid); + + // start a call to set the last call started timestamp + channelz_channel->CallStarted(); + char* ts1 = GetLastCallStartedTimestamp(channelz_channel); + + // time gone by should not affect the timestamp + ChannelzSleep(100); + char* ts2 = GetLastCallStartedTimestamp(channelz_channel); + EXPECT_STREQ(ts1, ts2); + + // calls succeeded or failed should not affect the timestamp + ChannelzSleep(100); + channelz_channel->CallFailed(); + channelz_channel->CallSucceeded(); + char* ts3 = GetLastCallStartedTimestamp(channelz_channel); + EXPECT_STREQ(ts1, ts3); + + // another call started should affect the timestamp + // sleep for extra long to avoid flakes (since we cache Now()) + ChannelzSleep(5000); + grpc_core::ExecCtx::Get()->InvalidateNow(); + channelz_channel->CallStarted(); + char* ts4 = GetLastCallStartedTimestamp(channelz_channel); + EXPECT_STRNE(ts1, ts4); + + // clean up + gpr_free(ts1); + gpr_free(ts2); + gpr_free(ts3); + gpr_free(ts4); +} + +INSTANTIATE_TEST_CASE_P(ChannelzChannelTestSweep, ChannelzChannelTest, + ::testing::Values(0, 1, 2, 6, 10, 15)); } // namespace testing +} // namespace channelz } // namespace grpc_core int main(int argc, char** argv) { diff --git a/test/cpp/util/channel_trace_proto_helper.cc b/test/cpp/util/channel_trace_proto_helper.cc index db9390163bc..ee310784c21 100644 --- a/test/cpp/util/channel_trace_proto_helper.cc +++ b/test/cpp/util/channel_trace_proto_helper.cc @@ -45,16 +45,21 @@ void VaidateProtoJsonTranslation(char* json_c_str) { // then compare the output, and determine what fields are missing. // // parse_options.ignore_unknown_fields = true; - ASSERT_EQ(google::protobuf::util::JsonStringToMessage(json_str, &msg, + EXPECT_EQ(google::protobuf::util::JsonStringToMessage(json_str, &msg, parse_options), google::protobuf::util::Status::OK); std::string proto_json_str; - ASSERT_EQ(google::protobuf::util::MessageToJsonString(msg, &proto_json_str), + google::protobuf::util::JsonPrintOptions print_options; + // We usually do not want this to be true, however it can be helpful to + // uncomment and see the output produced then all fields are printed. + // print_options.always_print_primitive_fields = true; + EXPECT_EQ(google::protobuf::util::MessageToJsonString(msg, &proto_json_str, + print_options), google::protobuf::util::Status::OK); // uncomment these to compare the the json strings. // gpr_log(GPR_ERROR, "tracer json: %s", json_str.c_str()); // gpr_log(GPR_ERROR, "proto json: %s", proto_json_str.c_str()); - ASSERT_EQ(json_str, proto_json_str); + EXPECT_EQ(json_str, proto_json_str); } } // namespace From c03c9685a2461b097c17e2298be506520e15a5b1 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Wed, 30 May 2018 23:21:03 -0700 Subject: [PATCH 05/57] Add sanity channelz test to simple_request --- src/core/lib/channel/channelz.h | 2 -- test/core/end2end/tests/simple_request.cc | 23 ++++++++++++++++++----- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/core/lib/channel/channelz.h b/src/core/lib/channel/channelz.h index 63b90e90a0c..5cfafc9e146 100644 --- a/src/core/lib/channel/channelz.h +++ b/src/core/lib/channel/channelz.h @@ -23,7 +23,6 @@ #include -#include "src/core/ext/filters/client_channel/client_channel.h" #include "src/core/lib/channel/channel_trace.h" #include "src/core/lib/gprpp/manual_constructor.h" #include "src/core/lib/gprpp/ref_counted.h" @@ -34,7 +33,6 @@ namespace grpc_core { namespace channelz { -// owned by the client_channel that it points to and tracks class Channel : public RefCounted { public: Channel(grpc_channel* channel, size_t channel_tracer_max_nodes); diff --git a/test/core/end2end/tests/simple_request.cc b/test/core/end2end/tests/simple_request.cc index 6e36e54cd37..a9341edff96 100644 --- a/test/core/end2end/tests/simple_request.cc +++ b/test/core/end2end/tests/simple_request.cc @@ -21,7 +21,6 @@ #include #include -#include "src/core/ext/filters/client_channel/client_channel.h" #include "src/core/lib/surface/channel.h" #include @@ -201,10 +200,6 @@ static void simple_request_body(grpc_end2end_test_config config, CQ_EXPECT_COMPLETION(cqv, tag(1), 1); cq_verify(cqv); - char* json = grpc_channel_render_channelz(f.client); - gpr_log(GPR_ERROR, "%s", json); - gpr_free(json); - GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED); GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz")); // the following sanity check makes sure that the requested error string is @@ -259,6 +254,16 @@ static void test_invoke_simple_request(grpc_end2end_test_config config) { f = begin_test(config, "test_invoke_simple_request", nullptr, nullptr); simple_request_body(config, f); + + // The following is a quick sanity check on channelz functionality. It + // ensures that core properly tracked the one call that occurred in this + // simple end2end test. + char* json = grpc_channel_render_channelz(f.client); + GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"1\"")); + GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"1\"")); + GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"-1\"")); + gpr_free(json); + end_test(&f); config.tear_down_data(&f); } @@ -271,6 +276,14 @@ static void test_invoke_10_simple_requests(grpc_end2end_test_config config) { simple_request_body(config, f); gpr_log(GPR_INFO, "Running test: Passed simple request %d", i); } + + // The following is a quick sanity check on channelz functionality. It + // ensures that core properly tracked the ten calls that occurred. + char* json = grpc_channel_render_channelz(f.client); + GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"10\"")); + GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"10\"")); + GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"-1\"")); + gpr_free(json); end_test(&f); config.tear_down_data(&f); } From ec482847b29e4efb07e1eb23fc0fed1ea4a5aebc Mon Sep 17 00:00:00 2001 From: ncteisen Date: Wed, 30 May 2018 23:31:15 -0700 Subject: [PATCH 06/57] re run generate projects --- CMakeLists.txt | 7 +++++++ Makefile | 4 ++++ build.yaml | 4 ++++ grpc.def | 1 - src/ruby/ext/grpc/rb_grpc_imports.generated.c | 2 -- src/ruby/ext/grpc/rb_grpc_imports.generated.h | 3 --- test/core/surface/public_headers_must_be_c89.c | 1 - tools/run_tests/generated/sources_and_headers.json | 2 ++ 8 files changed, 17 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 37bde81a9d0..29352da5f6c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10479,10 +10479,17 @@ if (gRPC_BUILD_TESTS) add_executable(channel_trace_test test/core/channel/channel_trace_test.cc + ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/channelz/channelz.pb.cc + ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/channelz/channelz.grpc.pb.cc + ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/channelz/channelz.pb.h + ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/channelz/channelz.grpc.pb.h third_party/googletest/googletest/src/gtest-all.cc third_party/googletest/googlemock/src/gmock-all.cc ) +protobuf_generate_grpc_cpp( + src/proto/grpc/channelz/channelz.proto +) target_include_directories(channel_trace_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} diff --git a/Makefile b/Makefile index f5423ea6435..7d56686fe28 100644 --- a/Makefile +++ b/Makefile @@ -16307,6 +16307,7 @@ endif CHANNEL_TRACE_TEST_SRC = \ test/core/channel/channel_trace_test.cc \ + $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc \ CHANNEL_TRACE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CHANNEL_TRACE_TEST_SRC)))) ifeq ($(NO_SECURE),true) @@ -16339,6 +16340,8 @@ endif $(OBJDIR)/$(CONFIG)/test/core/channel/channel_trace_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a +$(OBJDIR)/$(CONFIG)/src/proto/grpc/channelz/channelz.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + deps_channel_trace_test: $(CHANNEL_TRACE_TEST_OBJS:.o=.dep) ifneq ($(NO_SECURE),true) @@ -16346,6 +16349,7 @@ ifneq ($(NO_DEPS),true) -include $(CHANNEL_TRACE_TEST_OBJS:.o=.dep) endif endif +$(OBJDIR)/$(CONFIG)/test/core/channel/channel_trace_test.o: $(GENDIR)/src/proto/grpc/channelz/channelz.pb.cc $(GENDIR)/src/proto/grpc/channelz/channelz.grpc.pb.cc CHANNELZ_REGISTRY_TEST_SRC = \ diff --git a/build.yaml b/build.yaml index 3df140e9222..90a9f9c5a76 100644 --- a/build.yaml +++ b/build.yaml @@ -4205,6 +4205,10 @@ targets: - grpc - gpr_test_util - gpr + filegroups: + - grpc++_channelz_proto + uses: + - grpc++_test - name: channelz_registry_test gtest: true build: test diff --git a/grpc.def b/grpc.def index 1a8c40f9509..6a91214e8c3 100644 --- a/grpc.def +++ b/grpc.def @@ -47,7 +47,6 @@ EXPORTS grpc_channel_destroy grpc_channel_get_trace grpc_channel_get_uuid - grpc_channelz_get_channel grpc_call_cancel grpc_call_cancel_with_status grpc_call_ref diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c index 075219a3af3..02f84c0b962 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c @@ -70,7 +70,6 @@ grpc_lame_client_channel_create_type grpc_lame_client_channel_create_import; grpc_channel_destroy_type grpc_channel_destroy_import; grpc_channel_get_trace_type grpc_channel_get_trace_import; grpc_channel_get_uuid_type grpc_channel_get_uuid_import; -grpc_channelz_get_channel_type grpc_channelz_get_channel_import; grpc_call_cancel_type grpc_call_cancel_import; grpc_call_cancel_with_status_type grpc_call_cancel_with_status_import; grpc_call_ref_type grpc_call_ref_import; @@ -319,7 +318,6 @@ void grpc_rb_load_imports(HMODULE library) { grpc_channel_destroy_import = (grpc_channel_destroy_type) GetProcAddress(library, "grpc_channel_destroy"); grpc_channel_get_trace_import = (grpc_channel_get_trace_type) GetProcAddress(library, "grpc_channel_get_trace"); grpc_channel_get_uuid_import = (grpc_channel_get_uuid_type) GetProcAddress(library, "grpc_channel_get_uuid"); - grpc_channelz_get_channel_import = (grpc_channelz_get_channel_type) GetProcAddress(library, "grpc_channelz_get_channel"); grpc_call_cancel_import = (grpc_call_cancel_type) GetProcAddress(library, "grpc_call_cancel"); grpc_call_cancel_with_status_import = (grpc_call_cancel_with_status_type) GetProcAddress(library, "grpc_call_cancel_with_status"); grpc_call_ref_import = (grpc_call_ref_type) GetProcAddress(library, "grpc_call_ref"); diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h index 590a6b2439b..b2186a69aa9 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h @@ -185,9 +185,6 @@ extern grpc_channel_get_trace_type grpc_channel_get_trace_import; typedef intptr_t(*grpc_channel_get_uuid_type)(grpc_channel* channel); extern grpc_channel_get_uuid_type grpc_channel_get_uuid_import; #define grpc_channel_get_uuid grpc_channel_get_uuid_import -typedef char*(*grpc_channelz_get_channel_type)(intptr_t channel_id); -extern grpc_channelz_get_channel_type grpc_channelz_get_channel_import; -#define grpc_channelz_get_channel grpc_channelz_get_channel_import typedef grpc_call_error(*grpc_call_cancel_type)(grpc_call* call, void* reserved); extern grpc_call_cancel_type grpc_call_cancel_import; #define grpc_call_cancel grpc_call_cancel_import diff --git a/test/core/surface/public_headers_must_be_c89.c b/test/core/surface/public_headers_must_be_c89.c index bc9c2f2a13e..52a1b039980 100644 --- a/test/core/surface/public_headers_must_be_c89.c +++ b/test/core/surface/public_headers_must_be_c89.c @@ -108,7 +108,6 @@ int main(int argc, char **argv) { printf("%lx", (unsigned long) grpc_channel_destroy); printf("%lx", (unsigned long) grpc_channel_get_trace); printf("%lx", (unsigned long) grpc_channel_get_uuid); - printf("%lx", (unsigned long) grpc_channelz_get_channel); printf("%lx", (unsigned long) grpc_call_cancel); printf("%lx", (unsigned long) grpc_call_cancel_with_status); printf("%lx", (unsigned long) grpc_call_ref); diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index 46508d47494..efe53d7da5c 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -3068,6 +3068,8 @@ "gpr_test_util", "grpc", "grpc++", + "grpc++_channelz_proto", + "grpc++_test", "grpc++_test_util", "grpc_test_util" ], From a8717043515fd1fdb661cb684fb952109a547660 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Tue, 5 Jun 2018 08:26:34 -0700 Subject: [PATCH 07/57] Make operations atomic --- src/core/lib/channel/channelz.cc | 28 ++++++++++++++++++++++------ src/core/lib/channel/channelz.h | 27 +++++++++++++++++++++------ 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/src/core/lib/channel/channelz.cc b/src/core/lib/channel/channelz.cc index 5c3dc97e690..9e153a3f4f5 100644 --- a/src/core/lib/channel/channelz.cc +++ b/src/core/lib/channel/channelz.cc @@ -93,8 +93,6 @@ Channel::Channel(grpc_channel* channel, size_t channel_tracer_max_nodes) trace_.Init(channel_tracer_max_nodes); target_ = grpc_channel_get_target(channel_); channel_uuid_ = ChannelzRegistry::Register(this); - last_call_started_timestamp_ = - grpc_millis_to_timespec(ExecCtx::Get()->Now(), GPR_CLOCK_REALTIME); } Channel::~Channel() { @@ -103,10 +101,28 @@ Channel::~Channel() { ChannelzRegistry::Unregister(channel_uuid_); } +Channel::AtomicTimespec::AtomicTimespec() { + gpr_atm_no_barrier_store(&tv_sec_, (gpr_atm)0); + gpr_atm_no_barrier_store(&tv_nsec_, (gpr_atm)0); +} + +void Channel::AtomicTimespec::Update(gpr_timespec ts) { + gpr_atm_no_barrier_store(&tv_sec_, (gpr_atm)ts.tv_sec); + gpr_atm_no_barrier_store(&tv_nsec_, (gpr_atm)ts.tv_nsec); +} + +gpr_timespec Channel::AtomicTimespec::Get() { + gpr_timespec out; + out.clock_type = GPR_CLOCK_REALTIME; + out.tv_sec = static_cast(gpr_atm_no_barrier_load(&tv_sec_)); + out.tv_nsec = static_cast(gpr_atm_no_barrier_load(&tv_nsec_)); + return out; +} + void Channel::CallStarted() { - calls_started_++; - last_call_started_timestamp_ = - grpc_millis_to_timespec(ExecCtx::Get()->Now(), GPR_CLOCK_REALTIME); + gpr_atm_no_barrier_fetch_add(&calls_started_, (gpr_atm)1); + last_call_started_timestamp_.Update( + grpc_millis_to_timespec(ExecCtx::Get()->Now(), GPR_CLOCK_REALTIME)); } grpc_connectivity_state Channel::GetConnectivityState() { @@ -181,7 +197,7 @@ char* Channel::RenderJSON() { calls_failed_ ? calls_failed_ : -1); json_iterator = grpc_json_create_child( json_iterator, json, "lastCallStartedTimestamp", - fmt_time(last_call_started_timestamp_), GRPC_JSON_STRING, true); + fmt_time(last_call_started_timestamp_.Get()), GRPC_JSON_STRING, true); // render and return the over json object char* json_str = grpc_json_dump_to_string(top_level_json, 0); diff --git a/src/core/lib/channel/channelz.h b/src/core/lib/channel/channelz.h index 5cfafc9e146..684402e08fc 100644 --- a/src/core/lib/channel/channelz.h +++ b/src/core/lib/channel/channelz.h @@ -39,8 +39,12 @@ class Channel : public RefCounted { ~Channel(); void CallStarted(); - void CallFailed() { calls_failed_++; } - void CallSucceeded() { calls_succeeded_++; } + void CallFailed() { + gpr_atm_no_barrier_fetch_add(&calls_failed_, (gpr_atm(1))); + } + void CallSucceeded() { + gpr_atm_no_barrier_fetch_add(&calls_succeeded_, (gpr_atm(1))); + } char* RenderJSON(); @@ -54,13 +58,24 @@ class Channel : public RefCounted { intptr_t channel_uuid() { return channel_uuid_; } private: + class AtomicTimespec { + public: + AtomicTimespec(); + void Update(gpr_timespec ts); + gpr_timespec Get(); + + private: + gpr_atm tv_sec_; + gpr_atm tv_nsec_; + }; + bool channel_destroyed_ = false; grpc_channel* channel_; const char* target_; - int64_t calls_started_ = 0; - int64_t calls_succeeded_ = 0; - int64_t calls_failed_ = 0; - gpr_timespec last_call_started_timestamp_; + gpr_atm calls_started_ = 0; + gpr_atm calls_succeeded_ = 0; + gpr_atm calls_failed_ = 0; + AtomicTimespec last_call_started_timestamp_; intptr_t channel_uuid_; ManualConstructor trace_; From c845ba66f30c44120f80098774652ba644ed7652 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Thu, 7 Jun 2018 10:14:55 -0700 Subject: [PATCH 08/57] Reviewer feedback --- src/core/lib/channel/channel_trace.cc | 12 +---- src/core/lib/channel/channel_trace.h | 13 ++--- src/core/lib/channel/channelz.cc | 26 ++-------- src/core/lib/channel/channelz.h | 27 +++++----- src/core/lib/surface/call.cc | 6 +-- src/core/lib/surface/channel.cc | 7 ++- test/core/channel/channel_trace_test.cc | 35 +++++++------ test/core/channel/channelz_test.cc | 68 ++++++++++++------------- 8 files changed, 83 insertions(+), 111 deletions(-) diff --git a/src/core/lib/channel/channel_trace.cc b/src/core/lib/channel/channel_trace.cc index c82e42d5459..4c29df42f42 100644 --- a/src/core/lib/channel/channel_trace.cc +++ b/src/core/lib/channel/channel_trace.cc @@ -121,11 +121,11 @@ void ChannelTrace::AddTraceEventReferencingChannel( void ChannelTrace::AddTraceEventReferencingSubchannel( Severity severity, grpc_slice data, - RefCountedPtr referenced_channel) { + RefCountedPtr referenced_subchannel) { if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0 // create and fill up the new event AddTraceEventHelper(New(severity, data, - std::move(referenced_channel), + std::move(referenced_subchannel), ReferencedType::Subchannel)); } @@ -232,13 +232,5 @@ grpc_json* ChannelTrace::RenderJSON() const { return json; } -char* ChannelTrace::RenderTrace() const { - grpc_json* json = RenderJSON(); - if (json == nullptr) return nullptr; - char* json_str = grpc_json_dump_to_string(json, 0); - grpc_json_destroy(json); - return json_str; -} - } // namespace channelz } // namespace grpc_core diff --git a/src/core/lib/channel/channel_trace.h b/src/core/lib/channel/channel_trace.h index b1224bb96c4..17e95a32ee4 100644 --- a/src/core/lib/channel/channel_trace.h +++ b/src/core/lib/channel/channel_trace.h @@ -22,11 +22,13 @@ #include #include +// #include "src/core/lib/channel/channelz.h" #include "src/core/lib/gprpp/ref_counted.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/iomgr/error.h" #include "src/core/lib/json/json.h" + namespace grpc_core { namespace channelz { @@ -64,20 +66,15 @@ class ChannelTrace { // slice. void AddTraceEventReferencingChannel( Severity severity, grpc_slice data, - RefCountedPtr referenced_tracer); + RefCountedPtr referenced_channel); void AddTraceEventReferencingSubchannel( Severity severity, grpc_slice data, - RefCountedPtr referenced_tracer); + RefCountedPtr referenced_subchannel); // Creates and returns the raw grpc_json object, so a parent channelz // object may incorporate the json before rendering. grpc_json* RenderJSON() const; - // Returns the tracing data rendered as a grpc json string. The string - // is owned by the caller and must be freed. This is used for testing only - // so that we may unit test ChannelTrace in isolation. - char* RenderTrace() const; - private: // Types of objects that can be references by trace events. enum class ReferencedType { Channel, Subchannel }; @@ -87,7 +84,7 @@ class ChannelTrace { public: // Constructor for a TraceEvent that references a different channel. TraceEvent(Severity severity, grpc_slice data, - RefCountedPtr referenced_tracer, ReferencedType type); + RefCountedPtr referenced_channel, ReferencedType type); // Constructor for a TraceEvent that does not reverence a different // channel. diff --git a/src/core/lib/channel/channelz.cc b/src/core/lib/channel/channelz.cc index 9e153a3f4f5..41b3c4527ec 100644 --- a/src/core/lib/channel/channelz.cc +++ b/src/core/lib/channel/channelz.cc @@ -101,28 +101,9 @@ Channel::~Channel() { ChannelzRegistry::Unregister(channel_uuid_); } -Channel::AtomicTimespec::AtomicTimespec() { - gpr_atm_no_barrier_store(&tv_sec_, (gpr_atm)0); - gpr_atm_no_barrier_store(&tv_nsec_, (gpr_atm)0); -} - -void Channel::AtomicTimespec::Update(gpr_timespec ts) { - gpr_atm_no_barrier_store(&tv_sec_, (gpr_atm)ts.tv_sec); - gpr_atm_no_barrier_store(&tv_nsec_, (gpr_atm)ts.tv_nsec); -} - -gpr_timespec Channel::AtomicTimespec::Get() { - gpr_timespec out; - out.clock_type = GPR_CLOCK_REALTIME; - out.tv_sec = static_cast(gpr_atm_no_barrier_load(&tv_sec_)); - out.tv_nsec = static_cast(gpr_atm_no_barrier_load(&tv_nsec_)); - return out; -} - -void Channel::CallStarted() { +void Channel::RecordCallStarted() { gpr_atm_no_barrier_fetch_add(&calls_started_, (gpr_atm)1); - last_call_started_timestamp_.Update( - grpc_millis_to_timespec(ExecCtx::Get()->Now(), GPR_CLOCK_REALTIME)); + gpr_atm_no_barrier_store(&last_call_started_millis_, (gpr_atm)ExecCtx::Get()->Now()); } grpc_connectivity_state Channel::GetConnectivityState() { @@ -195,9 +176,10 @@ char* Channel::RenderJSON() { calls_succeeded_ ? calls_succeeded_ : -1); json_iterator = add_num_str(json, json_iterator, "callsFailed", calls_failed_ ? calls_failed_ : -1); + gpr_timespec ts = grpc_millis_to_timespec(last_call_started_millis_, GPR_CLOCK_REALTIME); json_iterator = grpc_json_create_child( json_iterator, json, "lastCallStartedTimestamp", - fmt_time(last_call_started_timestamp_.Get()), GRPC_JSON_STRING, true); + fmt_time(ts), GRPC_JSON_STRING, true); // render and return the over json object char* json_str = grpc_json_dump_to_string(top_level_json, 0); diff --git a/src/core/lib/channel/channelz.h b/src/core/lib/channel/channelz.h index 684402e08fc..2d4c1a058a1 100644 --- a/src/core/lib/channel/channelz.h +++ b/src/core/lib/channel/channelz.h @@ -28,27 +28,32 @@ #include "src/core/lib/gprpp/ref_counted.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/iomgr/error.h" +#include "src/core/lib/iomgr/exec_ctx.h" #include "src/core/lib/json/json.h" namespace grpc_core { namespace channelz { +namespace testing { + class ChannelPeer; +} + class Channel : public RefCounted { public: Channel(grpc_channel* channel, size_t channel_tracer_max_nodes); ~Channel(); - void CallStarted(); - void CallFailed() { + void RecordCallStarted(); + void RecordCallFailed() { gpr_atm_no_barrier_fetch_add(&calls_failed_, (gpr_atm(1))); } - void CallSucceeded() { + void RecordCallSucceeded() { gpr_atm_no_barrier_fetch_add(&calls_succeeded_, (gpr_atm(1))); } char* RenderJSON(); - ChannelTrace* Trace() { return trace_.get(); } + ChannelTrace* trace() { return trace_.get(); } void set_channel_destroyed() { GPR_ASSERT(!channel_destroyed_); @@ -58,16 +63,8 @@ class Channel : public RefCounted { intptr_t channel_uuid() { return channel_uuid_; } private: - class AtomicTimespec { - public: - AtomicTimespec(); - void Update(gpr_timespec ts); - gpr_timespec Get(); - - private: - gpr_atm tv_sec_; - gpr_atm tv_nsec_; - }; + // testing peer friend. + friend class testing::ChannelPeer; bool channel_destroyed_ = false; grpc_channel* channel_; @@ -75,7 +72,7 @@ class Channel : public RefCounted { gpr_atm calls_started_ = 0; gpr_atm calls_succeeded_ = 0; gpr_atm calls_failed_ = 0; - AtomicTimespec last_call_started_timestamp_; + gpr_atm last_call_started_millis_; intptr_t channel_uuid_; ManualConstructor trace_; diff --git a/src/core/lib/surface/call.cc b/src/core/lib/surface/call.cc index 924d633cb27..e2212baa8c2 100644 --- a/src/core/lib/surface/call.cc +++ b/src/core/lib/surface/call.cc @@ -1084,11 +1084,11 @@ static void recv_trailing_filter(void* args, grpc_metadata_batch* b) { : nullptr; if (status_code == GRPC_STATUS_OK) { if (channelz_channel != nullptr) { - channelz_channel->CallSucceeded(); + channelz_channel->RecordCallSucceeded(); } } else { if (channelz_channel != nullptr) { - channelz_channel->CallFailed(); + channelz_channel->RecordCallFailed(); } error = grpc_error_set_int( GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error received from peer"), @@ -1677,7 +1677,7 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops, } grpc_core::channelz::Channel* channelz_channel = grpc_channel_get_channelz_channel(call->channel); - channelz_channel->CallStarted(); + channelz_channel->RecordCallStarted(); break; } case GRPC_OP_SEND_MESSAGE: { diff --git a/src/core/lib/surface/channel.cc b/src/core/lib/surface/channel.cc index be9869b08c4..5189c54b866 100644 --- a/src/core/lib/surface/channel.cc +++ b/src/core/lib/surface/channel.cc @@ -149,7 +149,7 @@ grpc_channel* grpc_channel_create_with_builder( channel->channelz_channel = grpc_core::MakeRefCounted( channel, channel_tracer_max_nodes); - channel->channelz_channel->Trace()->AddTraceEvent( + channel->channelz_channel->trace()->AddTraceEvent( grpc_core::channelz::ChannelTrace::Severity::Info, grpc_slice_from_static_string("Channel created")); return channel; @@ -187,7 +187,10 @@ static grpc_channel_args* build_channel_args( } char* grpc_channel_get_trace(grpc_channel* channel) { - return channel->channelz_channel->Trace()->RenderTrace(); + grpc_json* json = channel->channelz_channel->trace()->RenderJSON(); + char* json_str = grpc_json_dump_to_string(json, 0); + grpc_json_destroy(json); + return json_str; } char* grpc_channel_render_channelz(grpc_channel* channel) { diff --git a/test/core/channel/channel_trace_test.cc b/test/core/channel/channel_trace_test.cc index c8619be0074..ef69e631410 100644 --- a/test/core/channel/channel_trace_test.cc +++ b/test/core/channel/channel_trace_test.cc @@ -88,12 +88,15 @@ void AddSimpleTrace(ChannelTrace* tracer) { void ValidateChannelTrace(ChannelTrace* tracer, size_t expected_num_event_logged, size_t max_nodes) { if (!max_nodes) return; - char* json_str = tracer->RenderTrace(); + grpc_json* json = tracer->RenderJSON(); + EXPECT_NE(json, nullptr); + char* json_str = grpc_json_dump_to_string(json, 0); + grpc_json_destroy(json); grpc::testing::ValidateChannelTraceProtoJsonTranslation(json_str); - grpc_json* json = grpc_json_parse_string(json_str); - ValidateChannelTraceData(json, expected_num_event_logged, + grpc_json* parsed_json = grpc_json_parse_string(json_str); + ValidateChannelTraceData(parsed_json, expected_num_event_logged, GPR_MIN(expected_num_event_logged, max_nodes)); - grpc_json_destroy(json); + grpc_json_destroy(parsed_json); gpr_free(json_str); } @@ -159,14 +162,14 @@ TEST_P(ChannelTracerTest, ComplexTest) { ChannelTrace::Severity::Info, grpc_slice_from_static_string("subchannel one created"), sc1); ValidateChannelTrace(&tracer, 3, GetParam()); - AddSimpleTrace(sc1->Trace()); - AddSimpleTrace(sc1->Trace()); - AddSimpleTrace(sc1->Trace()); - ValidateChannelTrace(sc1->Trace(), 3, GetParam()); - AddSimpleTrace(sc1->Trace()); - AddSimpleTrace(sc1->Trace()); - AddSimpleTrace(sc1->Trace()); - ValidateChannelTrace(sc1->Trace(), 6, GetParam()); + AddSimpleTrace(sc1->trace()); + AddSimpleTrace(sc1->trace()); + AddSimpleTrace(sc1->trace()); + ValidateChannelTrace(sc1->trace(), 3, GetParam()); + AddSimpleTrace(sc1->trace()); + AddSimpleTrace(sc1->trace()); + AddSimpleTrace(sc1->trace()); + ValidateChannelTrace(sc1->trace(), 6, GetParam()); AddSimpleTrace(&tracer); AddSimpleTrace(&tracer); ValidateChannelTrace(&tracer, 5, GetParam()); @@ -206,20 +209,20 @@ TEST_P(ChannelTracerTest, TestNesting) { ChannelTrace::Severity::Info, grpc_slice_from_static_string("subchannel one created"), sc1); ValidateChannelTrace(&tracer, 3, GetParam()); - AddSimpleTrace(sc1->Trace()); + AddSimpleTrace(sc1->trace()); ChannelFixture channel2(GetParam()); RefCountedPtr conn1 = MakeRefCounted(channel2.channel(), GetParam()); // nesting one level deeper. - sc1->Trace()->AddTraceEventReferencingSubchannel( + sc1->trace()->AddTraceEventReferencingSubchannel( ChannelTrace::Severity::Info, grpc_slice_from_static_string("connection one created"), conn1); ValidateChannelTrace(&tracer, 3, GetParam()); - AddSimpleTrace(conn1->Trace()); + AddSimpleTrace(conn1->trace()); AddSimpleTrace(&tracer); AddSimpleTrace(&tracer); ValidateChannelTrace(&tracer, 5, GetParam()); - ValidateChannelTrace(conn1->Trace(), 1, GetParam()); + ValidateChannelTrace(conn1->trace(), 1, GetParam()); ChannelFixture channel3(GetParam()); RefCountedPtr sc2 = MakeRefCounted(channel3.channel(), GetParam()); diff --git a/test/core/channel/channelz_test.cc b/test/core/channel/channelz_test.cc index c4606426095..1c676e51cfe 100644 --- a/test/core/channel/channelz_test.cc +++ b/test/core/channel/channelz_test.cc @@ -42,6 +42,16 @@ namespace grpc_core { namespace channelz { namespace testing { + +// testing peer to access channel internals +class ChannelPeer { + public: + ChannelPeer (Channel* channel) : channel_(channel) {} + grpc_millis last_call_started_millis() { return (grpc_millis)gpr_atm_no_barrier_load(&channel_->last_call_started_millis_); } + private: + Channel* channel_; +}; + namespace { grpc_json* GetJsonChild(grpc_json* parent, const char* key) { @@ -100,15 +110,9 @@ void ValidateChannel(Channel* channel, validate_channel_data_args args) { gpr_free(json_str); } -char* GetLastCallStartedTimestamp(Channel* channel) { - char* json_str = channel->RenderJSON(); - grpc_json* json = grpc_json_parse_string(json_str); - grpc_json* data = GetJsonChild(json, "data"); - grpc_json* timestamp = GetJsonChild(data, "lastCallStartedTimestamp"); - char* ts_str = grpc_json_dump_to_string(timestamp, 0); - grpc_json_destroy(json); - gpr_free(json_str); - return ts_str; +grpc_millis GetLastCallStartedMillis(Channel* channel) { + ChannelPeer peer(channel); + return peer.last_call_started_millis(); } void ChannelzSleep(int64_t sleep_us) { @@ -134,16 +138,16 @@ TEST_P(ChannelzChannelTest, BasicChannelAPIFunctionality) { ChannelFixture channel(GetParam()); intptr_t uuid = grpc_channel_get_uuid(channel.channel()); Channel* channelz_channel = ChannelzRegistry::Get(uuid); - channelz_channel->CallStarted(); - channelz_channel->CallFailed(); - channelz_channel->CallSucceeded(); + channelz_channel->RecordCallStarted(); + channelz_channel->RecordCallFailed(); + channelz_channel->RecordCallSucceeded(); ValidateChannel(channelz_channel, {1, 1, 1}); - channelz_channel->CallStarted(); - channelz_channel->CallFailed(); - channelz_channel->CallSucceeded(); - channelz_channel->CallStarted(); - channelz_channel->CallFailed(); - channelz_channel->CallSucceeded(); + channelz_channel->RecordCallStarted(); + channelz_channel->RecordCallFailed(); + channelz_channel->RecordCallSucceeded(); + channelz_channel->RecordCallStarted(); + channelz_channel->RecordCallFailed(); + channelz_channel->RecordCallSucceeded(); ValidateChannel(channelz_channel, {3, 3, 3}); } @@ -154,34 +158,28 @@ TEST_P(ChannelzChannelTest, LastCallStartedTimestamp) { Channel* channelz_channel = ChannelzRegistry::Get(uuid); // start a call to set the last call started timestamp - channelz_channel->CallStarted(); - char* ts1 = GetLastCallStartedTimestamp(channelz_channel); + channelz_channel->RecordCallStarted(); + grpc_millis millis1 = GetLastCallStartedMillis(channelz_channel); // time gone by should not affect the timestamp ChannelzSleep(100); - char* ts2 = GetLastCallStartedTimestamp(channelz_channel); - EXPECT_STREQ(ts1, ts2); + grpc_millis millis2 = GetLastCallStartedMillis(channelz_channel); + EXPECT_EQ(millis1, millis2); // calls succeeded or failed should not affect the timestamp ChannelzSleep(100); - channelz_channel->CallFailed(); - channelz_channel->CallSucceeded(); - char* ts3 = GetLastCallStartedTimestamp(channelz_channel); - EXPECT_STREQ(ts1, ts3); + channelz_channel->RecordCallFailed(); + channelz_channel->RecordCallSucceeded(); + grpc_millis millis3 = GetLastCallStartedMillis(channelz_channel); + EXPECT_EQ(millis1, millis3); // another call started should affect the timestamp // sleep for extra long to avoid flakes (since we cache Now()) ChannelzSleep(5000); grpc_core::ExecCtx::Get()->InvalidateNow(); - channelz_channel->CallStarted(); - char* ts4 = GetLastCallStartedTimestamp(channelz_channel); - EXPECT_STRNE(ts1, ts4); - - // clean up - gpr_free(ts1); - gpr_free(ts2); - gpr_free(ts3); - gpr_free(ts4); + channelz_channel->RecordCallStarted(); + grpc_millis millis4 = GetLastCallStartedMillis(channelz_channel); + EXPECT_NE(millis1, millis4); } INSTANTIATE_TEST_CASE_P(ChannelzChannelTestSweep, ChannelzChannelTest, From d23739eda3081a274fad4f3a6af400fbca39dee1 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Thu, 7 Jun 2018 12:55:15 -0700 Subject: [PATCH 09/57] Reviewer feedback --- include/grpc/grpc.h | 4 --- src/core/lib/channel/channel_trace.h | 1 - src/core/lib/channel/channelz.cc | 23 +++++------------ src/core/lib/channel/channelz.h | 15 ++++++------ src/core/lib/surface/call.cc | 30 +++++++++++------------ src/core/lib/surface/channel.cc | 10 +------- src/core/lib/surface/channel.h | 3 +-- test/core/channel/channelz_test.cc | 7 +----- test/core/end2end/tests/simple_request.cc | 6 +++-- 9 files changed, 36 insertions(+), 63 deletions(-) diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h index dd8a5d7d5f8..bb4a70f7b9f 100644 --- a/include/grpc/grpc.h +++ b/include/grpc/grpc.h @@ -286,10 +286,6 @@ GRPCAPI grpc_channel* grpc_lame_client_channel_create( /** Close and destroy a grpc channel */ GRPCAPI void grpc_channel_destroy(grpc_channel* channel); -/** Returns the JSON formatted channel trace for this channel. The caller - owns the returned string and is responsible for freeing it. */ -GRPCAPI char* grpc_channel_get_trace(grpc_channel* channel); - /** Returns the channel uuid, which can be used to look up its trace at a later time. */ GRPCAPI intptr_t grpc_channel_get_uuid(grpc_channel* channel); diff --git a/src/core/lib/channel/channel_trace.h b/src/core/lib/channel/channel_trace.h index 17e95a32ee4..499cebd721b 100644 --- a/src/core/lib/channel/channel_trace.h +++ b/src/core/lib/channel/channel_trace.h @@ -22,7 +22,6 @@ #include #include -// #include "src/core/lib/channel/channelz.h" #include "src/core/lib/gprpp/ref_counted.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/iomgr/error.h" diff --git a/src/core/lib/channel/channelz.cc b/src/core/lib/channel/channelz.cc index 41b3c4527ec..06e2c0e13c9 100644 --- a/src/core/lib/channel/channelz.cc +++ b/src/core/lib/channel/channelz.cc @@ -42,9 +42,10 @@ namespace grpc_core { namespace channelz { -// TODO(ncteisen): more this functions to a loc where it can be used namespace { +// TODO(ncteisen): move this function to a common helper location. +// // returns an allocated string that represents tm according to RFC-3339, and, // more specifically, follows: // https://developers.google.com/protocol-buffers/docs/proto3#json @@ -89,14 +90,12 @@ grpc_json* add_num_str(grpc_json* parent, grpc_json* it, const char* name, } // namespace Channel::Channel(grpc_channel* channel, size_t channel_tracer_max_nodes) - : channel_(channel) { + : channel_(channel), target_(UniquePtr(grpc_channel_get_target(channel_))), channel_uuid_(ChannelzRegistry::Register(this)) { trace_.Init(channel_tracer_max_nodes); - target_ = grpc_channel_get_target(channel_); - channel_uuid_ = ChannelzRegistry::Register(this); + gpr_atm_no_barrier_store(&last_call_started_millis_, (gpr_atm)ExecCtx::Get()->Now()); } Channel::~Channel() { - gpr_free(const_cast(target_)); trace_.Destroy(); ChannelzRegistry::Unregister(channel_uuid_); } @@ -107,7 +106,7 @@ void Channel::RecordCallStarted() { } grpc_connectivity_state Channel::GetConnectivityState() { - if (channel_destroyed_) { + if (channel_ == nullptr) { return GRPC_CHANNEL_SHUTDOWN; } else { return grpc_channel_check_connectivity_state(channel_, false); @@ -119,25 +118,20 @@ char* Channel::RenderJSON() { grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT); grpc_json* json = top_level_json; grpc_json* json_iterator = nullptr; - // create and fill the ref child json_iterator = grpc_json_create_child(json_iterator, json, "ref", nullptr, GRPC_JSON_OBJECT, false); json = json_iterator; json_iterator = nullptr; json_iterator = add_num_str(json, json_iterator, "channelId", channel_uuid_); - // reset json iterators to top level object json = top_level_json; json_iterator = nullptr; - // create and fill the data child. grpc_json* data = grpc_json_create_child(json_iterator, json, "data", nullptr, GRPC_JSON_OBJECT, false); - json = data; json_iterator = nullptr; - // create and fill the connectivity state child. grpc_connectivity_state connectivity_state = GetConnectivityState(); json_iterator = grpc_json_create_child(json_iterator, json, "state", nullptr, @@ -146,12 +140,10 @@ char* Channel::RenderJSON() { grpc_json_create_child(nullptr, json, "state", grpc_connectivity_state_name(connectivity_state), GRPC_JSON_STRING, false); - // reset the parent to be the data object. json = data; - json_iterator = grpc_json_create_child(json_iterator, json, "target", target_, + json_iterator = grpc_json_create_child(json_iterator, json, "target", target_.get(), GRPC_JSON_STRING, false); - // fill in the channel trace if applicable grpc_json* trace = trace_->RenderJSON(); if (trace != nullptr) { @@ -163,11 +155,9 @@ char* Channel::RenderJSON() { trace->key = "trace"; trace->owns_value = false; } - // reset the parent to be the data object. json = data; json_iterator = nullptr; - // We use -1 as sentinel values since proto default value for integers is // zero, and the confuses the parser into thinking the value weren't present json_iterator = add_num_str(json, json_iterator, "callsStarted", @@ -180,7 +170,6 @@ char* Channel::RenderJSON() { json_iterator = grpc_json_create_child( json_iterator, json, "lastCallStartedTimestamp", fmt_time(ts), GRPC_JSON_STRING, true); - // render and return the over json object char* json_str = grpc_json_dump_to_string(top_level_json, 0); grpc_json_destroy(top_level_json); diff --git a/src/core/lib/channel/channelz.h b/src/core/lib/channel/channelz.h index 2d4c1a058a1..863447a5a46 100644 --- a/src/core/lib/channel/channelz.h +++ b/src/core/lib/channel/channelz.h @@ -56,8 +56,8 @@ class Channel : public RefCounted { ChannelTrace* trace() { return trace_.get(); } void set_channel_destroyed() { - GPR_ASSERT(!channel_destroyed_); - channel_destroyed_ = true; + GPR_ASSERT(channel_ != nullptr); + channel_ = nullptr; } intptr_t channel_uuid() { return channel_uuid_; } @@ -66,17 +66,18 @@ class Channel : public RefCounted { // testing peer friend. friend class testing::ChannelPeer; - bool channel_destroyed_ = false; + // helper for getting connectivity state. + grpc_connectivity_state GetConnectivityState(); + + // Not owned. Will be set to nullptr when the channel is destroyed. grpc_channel* channel_; - const char* target_; + UniquePtr target_; gpr_atm calls_started_ = 0; gpr_atm calls_succeeded_ = 0; gpr_atm calls_failed_ = 0; gpr_atm last_call_started_millis_; - intptr_t channel_uuid_; + const intptr_t channel_uuid_; ManualConstructor trace_; - - grpc_connectivity_state GetConnectivityState(); }; } // namespace channelz diff --git a/src/core/lib/surface/call.cc b/src/core/lib/surface/call.cc index e2212baa8c2..2e7d9360a98 100644 --- a/src/core/lib/surface/call.cc +++ b/src/core/lib/surface/call.cc @@ -478,6 +478,10 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args, &call->pollent); } + grpc_core::channelz::Channel* channelz_channel = + grpc_channel_get_channelz_channel_node(call->channel); + channelz_channel->RecordCallStarted(); + grpc_slice_unref_internal(path); return error; @@ -1078,18 +1082,7 @@ static void recv_trailing_filter(void* args, grpc_metadata_batch* b) { grpc_status_code status_code = grpc_get_status_code_from_metadata(b->idx.named.grpc_status->md); grpc_error* error = GRPC_ERROR_NONE; - grpc_core::channelz::Channel* channelz_channel = - call->channel != nullptr - ? grpc_channel_get_channelz_channel(call->channel) - : nullptr; - if (status_code == GRPC_STATUS_OK) { - if (channelz_channel != nullptr) { - channelz_channel->RecordCallSucceeded(); - } - } else { - if (channelz_channel != nullptr) { - channelz_channel->RecordCallFailed(); - } + if (status_code != GRPC_STATUS_OK) { error = grpc_error_set_int( GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error received from peer"), GRPC_ERROR_INT_GRPC_STATUS, static_cast(status_code)); @@ -1268,6 +1261,16 @@ static void post_batch_completion(batch_control* bctl) { call->final_op.server.cancelled, nullptr, nullptr); } + if (call->channel != nullptr) { + grpc_core::channelz::Channel* channelz_channel = grpc_channel_get_channelz_channel_node(call->channel); + if (*call->final_op.client.status != GRPC_STATUS_OK) { + channelz_channel->RecordCallFailed(); + } else { + channelz_channel->RecordCallSucceeded(); + } + } + + GRPC_ERROR_UNREF(error); error = GRPC_ERROR_NONE; } @@ -1675,9 +1678,6 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops, stream_op_payload->send_initial_metadata.peer_string = &call->peer_string; } - grpc_core::channelz::Channel* channelz_channel = - grpc_channel_get_channelz_channel(call->channel); - channelz_channel->RecordCallStarted(); break; } case GRPC_OP_SEND_MESSAGE: { diff --git a/src/core/lib/surface/channel.cc b/src/core/lib/surface/channel.cc index 5189c54b866..c95af0f2bdf 100644 --- a/src/core/lib/surface/channel.cc +++ b/src/core/lib/surface/channel.cc @@ -186,18 +186,11 @@ static grpc_channel_args* build_channel_args( return grpc_channel_args_copy_and_add(input_args, new_args, num_new_args); } -char* grpc_channel_get_trace(grpc_channel* channel) { - grpc_json* json = channel->channelz_channel->trace()->RenderJSON(); - char* json_str = grpc_json_dump_to_string(json, 0); - grpc_json_destroy(json); - return json_str; -} - char* grpc_channel_render_channelz(grpc_channel* channel) { return channel->channelz_channel->RenderJSON(); } -grpc_core::channelz::Channel* grpc_channel_get_channelz_channel( +grpc_core::channelz::Channel* grpc_channel_get_channelz_channel_node( grpc_channel* channel) { return channel->channelz_channel.get(); } @@ -417,7 +410,6 @@ static void destroy_channel(void* arg, grpc_error* error) { GRPC_MDELEM_UNREF(rc->authority); gpr_free(rc); } - channel->channelz_channel.reset(); gpr_mu_destroy(&channel->registered_call_mu); gpr_free(channel->target); gpr_free(channel); diff --git a/src/core/lib/surface/channel.h b/src/core/lib/surface/channel.h index 52290f05f7a..bfeec9ec9be 100644 --- a/src/core/lib/surface/channel.h +++ b/src/core/lib/surface/channel.h @@ -51,9 +51,8 @@ grpc_call* grpc_channel_create_pollset_set_call( /** Get a (borrowed) pointer to this channels underlying channel stack */ grpc_channel_stack* grpc_channel_get_channel_stack(grpc_channel* channel); -grpc_core::channelz::Channel* grpc_channel_get_channelz_channel( +grpc_core::channelz::Channel* grpc_channel_get_channelz_channel_node( grpc_channel* channel); -char* grpc_channel_render_channelz(grpc_channel* channel); /** Get a grpc_mdelem of grpc-status: X where X is the numeric value of status_code. diff --git a/test/core/channel/channelz_test.cc b/test/core/channel/channelz_test.cc index 1c676e51cfe..537f1c5b189 100644 --- a/test/core/channel/channelz_test.cc +++ b/test/core/channel/channelz_test.cc @@ -151,32 +151,27 @@ TEST_P(ChannelzChannelTest, BasicChannelAPIFunctionality) { ValidateChannel(channelz_channel, {3, 3, 3}); } -TEST_P(ChannelzChannelTest, LastCallStartedTimestamp) { +TEST_P(ChannelzChannelTest, LastCallStartedMillis) { grpc_core::ExecCtx exec_ctx; ChannelFixture channel(GetParam()); intptr_t uuid = grpc_channel_get_uuid(channel.channel()); Channel* channelz_channel = ChannelzRegistry::Get(uuid); - // start a call to set the last call started timestamp channelz_channel->RecordCallStarted(); grpc_millis millis1 = GetLastCallStartedMillis(channelz_channel); - // time gone by should not affect the timestamp ChannelzSleep(100); grpc_millis millis2 = GetLastCallStartedMillis(channelz_channel); EXPECT_EQ(millis1, millis2); - // calls succeeded or failed should not affect the timestamp ChannelzSleep(100); channelz_channel->RecordCallFailed(); channelz_channel->RecordCallSucceeded(); grpc_millis millis3 = GetLastCallStartedMillis(channelz_channel); EXPECT_EQ(millis1, millis3); - // another call started should affect the timestamp // sleep for extra long to avoid flakes (since we cache Now()) ChannelzSleep(5000); - grpc_core::ExecCtx::Get()->InvalidateNow(); channelz_channel->RecordCallStarted(); grpc_millis millis4 = GetLastCallStartedMillis(channelz_channel); EXPECT_NE(millis1, millis4); diff --git a/test/core/end2end/tests/simple_request.cc b/test/core/end2end/tests/simple_request.cc index a9341edff96..57c11616412 100644 --- a/test/core/end2end/tests/simple_request.cc +++ b/test/core/end2end/tests/simple_request.cc @@ -258,7 +258,8 @@ static void test_invoke_simple_request(grpc_end2end_test_config config) { // The following is a quick sanity check on channelz functionality. It // ensures that core properly tracked the one call that occurred in this // simple end2end test. - char* json = grpc_channel_render_channelz(f.client); + grpc_core::channelz::Channel* channelz_channel = grpc_channel_get_channelz_channel_node(f.client); + char* json = channelz_channel->RenderJSON(); GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"1\"")); GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"1\"")); GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"-1\"")); @@ -279,7 +280,8 @@ static void test_invoke_10_simple_requests(grpc_end2end_test_config config) { // The following is a quick sanity check on channelz functionality. It // ensures that core properly tracked the ten calls that occurred. - char* json = grpc_channel_render_channelz(f.client); + grpc_core::channelz::Channel* channelz_channel = grpc_channel_get_channelz_channel_node(f.client); + char* json = channelz_channel->RenderJSON(); GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"10\"")); GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"10\"")); GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"-1\"")); From ea424b88fa8ed07df27cb51d07b8dafc9110a9ec Mon Sep 17 00:00:00 2001 From: Noah Eisen Date: Thu, 7 Jun 2018 13:02:48 -0700 Subject: [PATCH 10/57] clang fmt --- src/core/lib/channel/channel_trace.h | 1 - src/core/lib/channel/channelz.cc | 23 ++++++++++++++--------- src/core/lib/channel/channelz.h | 2 +- src/core/lib/surface/call.cc | 4 ++-- test/core/channel/channelz_test.cc | 8 ++++++-- test/core/end2end/tests/simple_request.cc | 6 ++++-- 6 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/core/lib/channel/channel_trace.h b/src/core/lib/channel/channel_trace.h index 499cebd721b..f6021c32243 100644 --- a/src/core/lib/channel/channel_trace.h +++ b/src/core/lib/channel/channel_trace.h @@ -27,7 +27,6 @@ #include "src/core/lib/iomgr/error.h" #include "src/core/lib/json/json.h" - namespace grpc_core { namespace channelz { diff --git a/src/core/lib/channel/channelz.cc b/src/core/lib/channel/channelz.cc index 06e2c0e13c9..17c3fc35d99 100644 --- a/src/core/lib/channel/channelz.cc +++ b/src/core/lib/channel/channelz.cc @@ -90,9 +90,12 @@ grpc_json* add_num_str(grpc_json* parent, grpc_json* it, const char* name, } // namespace Channel::Channel(grpc_channel* channel, size_t channel_tracer_max_nodes) - : channel_(channel), target_(UniquePtr(grpc_channel_get_target(channel_))), channel_uuid_(ChannelzRegistry::Register(this)) { + : channel_(channel), + target_(UniquePtr(grpc_channel_get_target(channel_))), + channel_uuid_(ChannelzRegistry::Register(this)) { trace_.Init(channel_tracer_max_nodes); - gpr_atm_no_barrier_store(&last_call_started_millis_, (gpr_atm)ExecCtx::Get()->Now()); + gpr_atm_no_barrier_store(&last_call_started_millis_, + (gpr_atm)ExecCtx::Get()->Now()); } Channel::~Channel() { @@ -102,7 +105,8 @@ Channel::~Channel() { void Channel::RecordCallStarted() { gpr_atm_no_barrier_fetch_add(&calls_started_, (gpr_atm)1); - gpr_atm_no_barrier_store(&last_call_started_millis_, (gpr_atm)ExecCtx::Get()->Now()); + gpr_atm_no_barrier_store(&last_call_started_millis_, + (gpr_atm)ExecCtx::Get()->Now()); } grpc_connectivity_state Channel::GetConnectivityState() { @@ -142,8 +146,8 @@ char* Channel::RenderJSON() { GRPC_JSON_STRING, false); // reset the parent to be the data object. json = data; - json_iterator = grpc_json_create_child(json_iterator, json, "target", target_.get(), - GRPC_JSON_STRING, false); + json_iterator = grpc_json_create_child( + json_iterator, json, "target", target_.get(), GRPC_JSON_STRING, false); // fill in the channel trace if applicable grpc_json* trace = trace_->RenderJSON(); if (trace != nullptr) { @@ -166,10 +170,11 @@ char* Channel::RenderJSON() { calls_succeeded_ ? calls_succeeded_ : -1); json_iterator = add_num_str(json, json_iterator, "callsFailed", calls_failed_ ? calls_failed_ : -1); - gpr_timespec ts = grpc_millis_to_timespec(last_call_started_millis_, GPR_CLOCK_REALTIME); - json_iterator = grpc_json_create_child( - json_iterator, json, "lastCallStartedTimestamp", - fmt_time(ts), GRPC_JSON_STRING, true); + gpr_timespec ts = + grpc_millis_to_timespec(last_call_started_millis_, GPR_CLOCK_REALTIME); + json_iterator = + grpc_json_create_child(json_iterator, json, "lastCallStartedTimestamp", + fmt_time(ts), GRPC_JSON_STRING, true); // render and return the over json object char* json_str = grpc_json_dump_to_string(top_level_json, 0); grpc_json_destroy(top_level_json); diff --git a/src/core/lib/channel/channelz.h b/src/core/lib/channel/channelz.h index 863447a5a46..68b7c8d26b9 100644 --- a/src/core/lib/channel/channelz.h +++ b/src/core/lib/channel/channelz.h @@ -35,7 +35,7 @@ namespace grpc_core { namespace channelz { namespace testing { - class ChannelPeer; +class ChannelPeer; } class Channel : public RefCounted { diff --git a/src/core/lib/surface/call.cc b/src/core/lib/surface/call.cc index 2e7d9360a98..807ab7ae436 100644 --- a/src/core/lib/surface/call.cc +++ b/src/core/lib/surface/call.cc @@ -1262,7 +1262,8 @@ static void post_batch_completion(batch_control* bctl) { } if (call->channel != nullptr) { - grpc_core::channelz::Channel* channelz_channel = grpc_channel_get_channelz_channel_node(call->channel); + grpc_core::channelz::Channel* channelz_channel = + grpc_channel_get_channelz_channel_node(call->channel); if (*call->final_op.client.status != GRPC_STATUS_OK) { channelz_channel->RecordCallFailed(); } else { @@ -1270,7 +1271,6 @@ static void post_batch_completion(batch_control* bctl) { } } - GRPC_ERROR_UNREF(error); error = GRPC_ERROR_NONE; } diff --git a/test/core/channel/channelz_test.cc b/test/core/channel/channelz_test.cc index 537f1c5b189..95cf5f83ea3 100644 --- a/test/core/channel/channelz_test.cc +++ b/test/core/channel/channelz_test.cc @@ -46,8 +46,12 @@ namespace testing { // testing peer to access channel internals class ChannelPeer { public: - ChannelPeer (Channel* channel) : channel_(channel) {} - grpc_millis last_call_started_millis() { return (grpc_millis)gpr_atm_no_barrier_load(&channel_->last_call_started_millis_); } + ChannelPeer(Channel* channel) : channel_(channel) {} + grpc_millis last_call_started_millis() { + return (grpc_millis)gpr_atm_no_barrier_load( + &channel_->last_call_started_millis_); + } + private: Channel* channel_; }; diff --git a/test/core/end2end/tests/simple_request.cc b/test/core/end2end/tests/simple_request.cc index 57c11616412..d24f7bc6206 100644 --- a/test/core/end2end/tests/simple_request.cc +++ b/test/core/end2end/tests/simple_request.cc @@ -258,7 +258,8 @@ static void test_invoke_simple_request(grpc_end2end_test_config config) { // The following is a quick sanity check on channelz functionality. It // ensures that core properly tracked the one call that occurred in this // simple end2end test. - grpc_core::channelz::Channel* channelz_channel = grpc_channel_get_channelz_channel_node(f.client); + grpc_core::channelz::Channel* channelz_channel = + grpc_channel_get_channelz_channel_node(f.client); char* json = channelz_channel->RenderJSON(); GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"1\"")); GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"1\"")); @@ -280,7 +281,8 @@ static void test_invoke_10_simple_requests(grpc_end2end_test_config config) { // The following is a quick sanity check on channelz functionality. It // ensures that core properly tracked the ten calls that occurred. - grpc_core::channelz::Channel* channelz_channel = grpc_channel_get_channelz_channel_node(f.client); + grpc_core::channelz::Channel* channelz_channel = + grpc_channel_get_channelz_channel_node(f.client); char* json = channelz_channel->RenderJSON(); GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"10\"")); GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"10\"")); From 70f7558a18fd92320813b6ba4107b94c83cc7b0b Mon Sep 17 00:00:00 2001 From: Noah Eisen Date: Thu, 7 Jun 2018 13:03:32 -0700 Subject: [PATCH 11/57] re generate project --- grpc.def | 1 - src/ruby/ext/grpc/rb_grpc_imports.generated.c | 2 -- src/ruby/ext/grpc/rb_grpc_imports.generated.h | 3 --- test/core/surface/public_headers_must_be_c89.c | 1 - 4 files changed, 7 deletions(-) diff --git a/grpc.def b/grpc.def index 6a91214e8c3..fc1d02a0352 100644 --- a/grpc.def +++ b/grpc.def @@ -45,7 +45,6 @@ EXPORTS grpc_insecure_channel_create grpc_lame_client_channel_create grpc_channel_destroy - grpc_channel_get_trace grpc_channel_get_uuid grpc_call_cancel grpc_call_cancel_with_status diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c index 02f84c0b962..8b67a7ce2d2 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c @@ -68,7 +68,6 @@ grpc_channel_get_info_type grpc_channel_get_info_import; grpc_insecure_channel_create_type grpc_insecure_channel_create_import; grpc_lame_client_channel_create_type grpc_lame_client_channel_create_import; grpc_channel_destroy_type grpc_channel_destroy_import; -grpc_channel_get_trace_type grpc_channel_get_trace_import; grpc_channel_get_uuid_type grpc_channel_get_uuid_import; grpc_call_cancel_type grpc_call_cancel_import; grpc_call_cancel_with_status_type grpc_call_cancel_with_status_import; @@ -316,7 +315,6 @@ void grpc_rb_load_imports(HMODULE library) { grpc_insecure_channel_create_import = (grpc_insecure_channel_create_type) GetProcAddress(library, "grpc_insecure_channel_create"); grpc_lame_client_channel_create_import = (grpc_lame_client_channel_create_type) GetProcAddress(library, "grpc_lame_client_channel_create"); grpc_channel_destroy_import = (grpc_channel_destroy_type) GetProcAddress(library, "grpc_channel_destroy"); - grpc_channel_get_trace_import = (grpc_channel_get_trace_type) GetProcAddress(library, "grpc_channel_get_trace"); grpc_channel_get_uuid_import = (grpc_channel_get_uuid_type) GetProcAddress(library, "grpc_channel_get_uuid"); grpc_call_cancel_import = (grpc_call_cancel_type) GetProcAddress(library, "grpc_call_cancel"); grpc_call_cancel_with_status_import = (grpc_call_cancel_with_status_type) GetProcAddress(library, "grpc_call_cancel_with_status"); diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h index b2186a69aa9..c7919871c86 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h @@ -179,9 +179,6 @@ extern grpc_lame_client_channel_create_type grpc_lame_client_channel_create_impo typedef void(*grpc_channel_destroy_type)(grpc_channel* channel); extern grpc_channel_destroy_type grpc_channel_destroy_import; #define grpc_channel_destroy grpc_channel_destroy_import -typedef char*(*grpc_channel_get_trace_type)(grpc_channel* channel); -extern grpc_channel_get_trace_type grpc_channel_get_trace_import; -#define grpc_channel_get_trace grpc_channel_get_trace_import typedef intptr_t(*grpc_channel_get_uuid_type)(grpc_channel* channel); extern grpc_channel_get_uuid_type grpc_channel_get_uuid_import; #define grpc_channel_get_uuid grpc_channel_get_uuid_import diff --git a/test/core/surface/public_headers_must_be_c89.c b/test/core/surface/public_headers_must_be_c89.c index 52a1b039980..96b25ebdaff 100644 --- a/test/core/surface/public_headers_must_be_c89.c +++ b/test/core/surface/public_headers_must_be_c89.c @@ -106,7 +106,6 @@ int main(int argc, char **argv) { printf("%lx", (unsigned long) grpc_insecure_channel_create); printf("%lx", (unsigned long) grpc_lame_client_channel_create); printf("%lx", (unsigned long) grpc_channel_destroy); - printf("%lx", (unsigned long) grpc_channel_get_trace); printf("%lx", (unsigned long) grpc_channel_get_uuid); printf("%lx", (unsigned long) grpc_call_cancel); printf("%lx", (unsigned long) grpc_call_cancel_with_status); From 7e7edc95b348b30b508cc0da9b09dc6495ce62ef Mon Sep 17 00:00:00 2001 From: ncteisen Date: Thu, 7 Jun 2018 17:25:44 -0700 Subject: [PATCH 12/57] reviewer feedback: --- src/core/lib/surface/call.cc | 17 +++++++---------- src/core/lib/surface/channel.cc | 2 +- src/core/lib/surface/channel.h | 2 +- test/core/end2end/tests/simple_request.cc | 4 ++-- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/core/lib/surface/call.cc b/src/core/lib/surface/call.cc index 807ab7ae436..65071672f27 100644 --- a/src/core/lib/surface/call.cc +++ b/src/core/lib/surface/call.cc @@ -479,7 +479,7 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args, } grpc_core::channelz::Channel* channelz_channel = - grpc_channel_get_channelz_channel_node(call->channel); + grpc_channel_get_channelz_node(call->channel); channelz_channel->RecordCallStarted(); grpc_slice_unref_internal(path); @@ -525,7 +525,6 @@ static void release_call(void* call, grpc_error* error) { GRPC_CHANNEL_INTERNAL_UNREF(channel, "call"); } -static void set_status_value_directly(grpc_status_code status, void* dest); static void destroy_call(void* call, grpc_error* error) { GPR_TIMER_SCOPE("destroy_call", 0); size_t i; @@ -1261,14 +1260,12 @@ static void post_batch_completion(batch_control* bctl) { call->final_op.server.cancelled, nullptr, nullptr); } - if (call->channel != nullptr) { - grpc_core::channelz::Channel* channelz_channel = - grpc_channel_get_channelz_channel_node(call->channel); - if (*call->final_op.client.status != GRPC_STATUS_OK) { - channelz_channel->RecordCallFailed(); - } else { - channelz_channel->RecordCallSucceeded(); - } + grpc_core::channelz::Channel* channelz_channel = + grpc_channel_get_channelz_node(call->channel); + if (*call->final_op.client.status != GRPC_STATUS_OK) { + channelz_channel->RecordCallFailed(); + } else { + channelz_channel->RecordCallSucceeded(); } GRPC_ERROR_UNREF(error); diff --git a/src/core/lib/surface/channel.cc b/src/core/lib/surface/channel.cc index c95af0f2bdf..d2b52dad2fd 100644 --- a/src/core/lib/surface/channel.cc +++ b/src/core/lib/surface/channel.cc @@ -190,7 +190,7 @@ char* grpc_channel_render_channelz(grpc_channel* channel) { return channel->channelz_channel->RenderJSON(); } -grpc_core::channelz::Channel* grpc_channel_get_channelz_channel_node( +grpc_core::channelz::Channel* grpc_channel_get_channelz_node( grpc_channel* channel) { return channel->channelz_channel.get(); } diff --git a/src/core/lib/surface/channel.h b/src/core/lib/surface/channel.h index bfeec9ec9be..6d2e1931e68 100644 --- a/src/core/lib/surface/channel.h +++ b/src/core/lib/surface/channel.h @@ -51,7 +51,7 @@ grpc_call* grpc_channel_create_pollset_set_call( /** Get a (borrowed) pointer to this channels underlying channel stack */ grpc_channel_stack* grpc_channel_get_channel_stack(grpc_channel* channel); -grpc_core::channelz::Channel* grpc_channel_get_channelz_channel_node( +grpc_core::channelz::Channel* grpc_channel_get_channelz_node( grpc_channel* channel); /** Get a grpc_mdelem of grpc-status: X where X is the numeric value of diff --git a/test/core/end2end/tests/simple_request.cc b/test/core/end2end/tests/simple_request.cc index d24f7bc6206..16fa4906085 100644 --- a/test/core/end2end/tests/simple_request.cc +++ b/test/core/end2end/tests/simple_request.cc @@ -259,7 +259,7 @@ static void test_invoke_simple_request(grpc_end2end_test_config config) { // ensures that core properly tracked the one call that occurred in this // simple end2end test. grpc_core::channelz::Channel* channelz_channel = - grpc_channel_get_channelz_channel_node(f.client); + grpc_channel_get_channelz_node(f.client); char* json = channelz_channel->RenderJSON(); GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"1\"")); GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"1\"")); @@ -282,7 +282,7 @@ static void test_invoke_10_simple_requests(grpc_end2end_test_config config) { // The following is a quick sanity check on channelz functionality. It // ensures that core properly tracked the ten calls that occurred. grpc_core::channelz::Channel* channelz_channel = - grpc_channel_get_channelz_channel_node(f.client); + grpc_channel_get_channelz_node(f.client); char* json = channelz_channel->RenderJSON(); GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"10\"")); GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"10\"")); From 9b488f788b2575d737558425ad98279abac9f844 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Thu, 7 Jun 2018 18:38:28 -0700 Subject: [PATCH 13/57] Review feedback --- src/core/lib/channel/channelz.cc | 6 +++--- test/core/channel/channelz_test.cc | 15 +++++++++++---- test/core/end2end/tests/simple_request.cc | 4 ++-- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/core/lib/channel/channelz.cc b/src/core/lib/channel/channelz.cc index 17c3fc35d99..1d2be00f1c4 100644 --- a/src/core/lib/channel/channelz.cc +++ b/src/core/lib/channel/channelz.cc @@ -165,11 +165,11 @@ char* Channel::RenderJSON() { // We use -1 as sentinel values since proto default value for integers is // zero, and the confuses the parser into thinking the value weren't present json_iterator = add_num_str(json, json_iterator, "callsStarted", - calls_started_ ? calls_started_ : -1); + calls_started_); json_iterator = add_num_str(json, json_iterator, "callsSucceeded", - calls_succeeded_ ? calls_succeeded_ : -1); + calls_succeeded_); json_iterator = add_num_str(json, json_iterator, "callsFailed", - calls_failed_ ? calls_failed_ : -1); + calls_failed_); gpr_timespec ts = grpc_millis_to_timespec(last_call_started_millis_, GPR_CLOCK_REALTIME); json_iterator = diff --git a/test/core/channel/channelz_test.cc b/test/core/channel/channelz_test.cc index 95cf5f83ea3..df97d34fd0d 100644 --- a/test/core/channel/channelz_test.cc +++ b/test/core/channel/channelz_test.cc @@ -101,9 +101,7 @@ void ValidateChildInteger(grpc_json* json, int64_t expect, const char* key) { EXPECT_EQ(gotten_number, expect); } -void ValidateChannel(Channel* channel, validate_channel_data_args args) { - char* json_str = channel->RenderJSON(); - grpc::testing::ValidateChannelProtoJsonTranslation(json_str); +void ValidateCounters(char* json_str, validate_channel_data_args args) { grpc_json* json = grpc_json_parse_string(json_str); EXPECT_NE(json, nullptr); grpc_json* data = GetJsonChild(json, "data"); @@ -111,7 +109,14 @@ void ValidateChannel(Channel* channel, validate_channel_data_args args) { ValidateChildInteger(data, args.calls_failed, "callsFailed"); ValidateChildInteger(data, args.calls_succeeded, "callsSucceeded"); grpc_json_destroy(json); +} + +void ValidateChannel(Channel* channel, validate_channel_data_args args) { + char* json_str = channel->RenderJSON(); + grpc::testing::ValidateChannelProtoJsonTranslation(json_str); + ValidateCounters(json_str, args); gpr_free(json_str); + } grpc_millis GetLastCallStartedMillis(Channel* channel) { @@ -134,7 +139,9 @@ TEST_P(ChannelzChannelTest, BasicChannel) { ChannelFixture channel(GetParam()); intptr_t uuid = grpc_channel_get_uuid(channel.channel()); Channel* channelz_channel = ChannelzRegistry::Get(uuid); - ValidateChannel(channelz_channel, {-1, -1, -1}); + char* json_str = channelz_channel->RenderJSON(); + ValidateCounters(json_str, {0, 0, 0}); + gpr_free(json_str); } TEST_P(ChannelzChannelTest, BasicChannelAPIFunctionality) { diff --git a/test/core/end2end/tests/simple_request.cc b/test/core/end2end/tests/simple_request.cc index 16fa4906085..8082bf93d54 100644 --- a/test/core/end2end/tests/simple_request.cc +++ b/test/core/end2end/tests/simple_request.cc @@ -263,7 +263,7 @@ static void test_invoke_simple_request(grpc_end2end_test_config config) { char* json = channelz_channel->RenderJSON(); GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"1\"")); GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"1\"")); - GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"-1\"")); + GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"0\"")); gpr_free(json); end_test(&f); @@ -286,7 +286,7 @@ static void test_invoke_10_simple_requests(grpc_end2end_test_config config) { char* json = channelz_channel->RenderJSON(); GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"10\"")); GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"10\"")); - GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"-1\"")); + GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"0\"")); gpr_free(json); end_test(&f); config.tear_down_data(&f); From b8a52e0cf3e271f80b32f16783c76c065f5c2167 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Thu, 7 Jun 2018 18:58:03 -0700 Subject: [PATCH 14/57] Add new end2end test for channelz --- CMakeLists.txt | 2 + Makefile | 2 + gRPC-Core.podspec | 1 + grpc.gyp | 2 + src/core/lib/channel/channelz.cc | 12 +- test/core/channel/channelz_test.cc | 1 - test/core/end2end/end2end_nosec_tests.cc | 8 + test/core/end2end/end2end_tests.cc | 8 + test/core/end2end/gen_build_yaml.py | 1 + test/core/end2end/generate_tests.bzl | 1 + test/core/end2end/tests/channelz.cc | 263 +++++ test/core/end2end/tests/simple_request.cc | 24 - .../generated/sources_and_headers.json | 2 + tools/run_tests/generated/tests.json | 927 ++++++++++++++++-- 14 files changed, 1154 insertions(+), 100 deletions(-) create mode 100644 test/core/end2end/tests/channelz.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 29352da5f6c..de3cb55fd44 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5281,6 +5281,7 @@ add_library(end2end_tests test/core/end2end/tests/cancel_before_invoke.cc test/core/end2end/tests/cancel_in_a_vacuum.cc test/core/end2end/tests/cancel_with_status.cc + test/core/end2end/tests/channelz.cc test/core/end2end/tests/compressed_payload.cc test/core/end2end/tests/connectivity.cc test/core/end2end/tests/default_host.cc @@ -5399,6 +5400,7 @@ add_library(end2end_nosec_tests test/core/end2end/tests/cancel_before_invoke.cc test/core/end2end/tests/cancel_in_a_vacuum.cc test/core/end2end/tests/cancel_with_status.cc + test/core/end2end/tests/channelz.cc test/core/end2end/tests/compressed_payload.cc test/core/end2end/tests/connectivity.cc test/core/end2end/tests/default_host.cc diff --git a/Makefile b/Makefile index 7d56686fe28..f68ea71df8f 100644 --- a/Makefile +++ b/Makefile @@ -9979,6 +9979,7 @@ LIBEND2END_TESTS_SRC = \ test/core/end2end/tests/cancel_before_invoke.cc \ test/core/end2end/tests/cancel_in_a_vacuum.cc \ test/core/end2end/tests/cancel_with_status.cc \ + test/core/end2end/tests/channelz.cc \ test/core/end2end/tests/compressed_payload.cc \ test/core/end2end/tests/connectivity.cc \ test/core/end2end/tests/default_host.cc \ @@ -10095,6 +10096,7 @@ LIBEND2END_NOSEC_TESTS_SRC = \ test/core/end2end/tests/cancel_before_invoke.cc \ test/core/end2end/tests/cancel_in_a_vacuum.cc \ test/core/end2end/tests/cancel_with_status.cc \ + test/core/end2end/tests/channelz.cc \ test/core/end2end/tests/compressed_payload.cc \ test/core/end2end/tests/connectivity.cc \ test/core/end2end/tests/default_host.cc \ diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index a10cfb5739f..2a9ad86f03c 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -1178,6 +1178,7 @@ Pod::Spec.new do |s| 'test/core/end2end/tests/cancel_before_invoke.cc', 'test/core/end2end/tests/cancel_in_a_vacuum.cc', 'test/core/end2end/tests/cancel_with_status.cc', + 'test/core/end2end/tests/channelz.cc', 'test/core/end2end/tests/compressed_payload.cc', 'test/core/end2end/tests/connectivity.cc', 'test/core/end2end/tests/default_host.cc', diff --git a/grpc.gyp b/grpc.gyp index a3ea8674fc0..6f259b215a9 100644 --- a/grpc.gyp +++ b/grpc.gyp @@ -2611,6 +2611,7 @@ 'test/core/end2end/tests/cancel_before_invoke.cc', 'test/core/end2end/tests/cancel_in_a_vacuum.cc', 'test/core/end2end/tests/cancel_with_status.cc', + 'test/core/end2end/tests/channelz.cc', 'test/core/end2end/tests/compressed_payload.cc', 'test/core/end2end/tests/connectivity.cc', 'test/core/end2end/tests/default_host.cc', @@ -2701,6 +2702,7 @@ 'test/core/end2end/tests/cancel_before_invoke.cc', 'test/core/end2end/tests/cancel_in_a_vacuum.cc', 'test/core/end2end/tests/cancel_with_status.cc', + 'test/core/end2end/tests/channelz.cc', 'test/core/end2end/tests/compressed_payload.cc', 'test/core/end2end/tests/connectivity.cc', 'test/core/end2end/tests/default_host.cc', diff --git a/src/core/lib/channel/channelz.cc b/src/core/lib/channel/channelz.cc index 1d2be00f1c4..42b169dffd1 100644 --- a/src/core/lib/channel/channelz.cc +++ b/src/core/lib/channel/channelz.cc @@ -164,12 +164,12 @@ char* Channel::RenderJSON() { json_iterator = nullptr; // We use -1 as sentinel values since proto default value for integers is // zero, and the confuses the parser into thinking the value weren't present - json_iterator = add_num_str(json, json_iterator, "callsStarted", - calls_started_); - json_iterator = add_num_str(json, json_iterator, "callsSucceeded", - calls_succeeded_); - json_iterator = add_num_str(json, json_iterator, "callsFailed", - calls_failed_); + json_iterator = + add_num_str(json, json_iterator, "callsStarted", calls_started_); + json_iterator = + add_num_str(json, json_iterator, "callsSucceeded", calls_succeeded_); + json_iterator = + add_num_str(json, json_iterator, "callsFailed", calls_failed_); gpr_timespec ts = grpc_millis_to_timespec(last_call_started_millis_, GPR_CLOCK_REALTIME); json_iterator = diff --git a/test/core/channel/channelz_test.cc b/test/core/channel/channelz_test.cc index df97d34fd0d..262ca38ee05 100644 --- a/test/core/channel/channelz_test.cc +++ b/test/core/channel/channelz_test.cc @@ -116,7 +116,6 @@ void ValidateChannel(Channel* channel, validate_channel_data_args args) { grpc::testing::ValidateChannelProtoJsonTranslation(json_str); ValidateCounters(json_str, args); gpr_free(json_str); - } grpc_millis GetLastCallStartedMillis(Channel* channel) { diff --git a/test/core/end2end/end2end_nosec_tests.cc b/test/core/end2end/end2end_nosec_tests.cc index 59eb643a93b..5ee0bb83fda 100644 --- a/test/core/end2end/end2end_nosec_tests.cc +++ b/test/core/end2end/end2end_nosec_tests.cc @@ -54,6 +54,8 @@ extern void cancel_in_a_vacuum(grpc_end2end_test_config config); extern void cancel_in_a_vacuum_pre_init(void); extern void cancel_with_status(grpc_end2end_test_config config); extern void cancel_with_status_pre_init(void); +extern void channelz(grpc_end2end_test_config config); +extern void channelz_pre_init(void); extern void compressed_payload(grpc_end2end_test_config config); extern void compressed_payload_pre_init(void); extern void connectivity(grpc_end2end_test_config config); @@ -199,6 +201,7 @@ void grpc_end2end_tests_pre_init(void) { cancel_before_invoke_pre_init(); cancel_in_a_vacuum_pre_init(); cancel_with_status_pre_init(); + channelz_pre_init(); compressed_payload_pre_init(); connectivity_pre_init(); default_host_pre_init(); @@ -284,6 +287,7 @@ void grpc_end2end_tests(int argc, char **argv, cancel_before_invoke(config); cancel_in_a_vacuum(config); cancel_with_status(config); + channelz(config); compressed_payload(config); connectivity(config); default_host(config); @@ -400,6 +404,10 @@ void grpc_end2end_tests(int argc, char **argv, cancel_with_status(config); continue; } + if (0 == strcmp("channelz", argv[i])) { + channelz(config); + continue; + } if (0 == strcmp("compressed_payload", argv[i])) { compressed_payload(config); continue; diff --git a/test/core/end2end/end2end_tests.cc b/test/core/end2end/end2end_tests.cc index 9f164b4eadf..ca5c18bcc27 100644 --- a/test/core/end2end/end2end_tests.cc +++ b/test/core/end2end/end2end_tests.cc @@ -56,6 +56,8 @@ extern void cancel_in_a_vacuum(grpc_end2end_test_config config); extern void cancel_in_a_vacuum_pre_init(void); extern void cancel_with_status(grpc_end2end_test_config config); extern void cancel_with_status_pre_init(void); +extern void channelz(grpc_end2end_test_config config); +extern void channelz_pre_init(void); extern void compressed_payload(grpc_end2end_test_config config); extern void compressed_payload_pre_init(void); extern void connectivity(grpc_end2end_test_config config); @@ -202,6 +204,7 @@ void grpc_end2end_tests_pre_init(void) { cancel_before_invoke_pre_init(); cancel_in_a_vacuum_pre_init(); cancel_with_status_pre_init(); + channelz_pre_init(); compressed_payload_pre_init(); connectivity_pre_init(); default_host_pre_init(); @@ -288,6 +291,7 @@ void grpc_end2end_tests(int argc, char **argv, cancel_before_invoke(config); cancel_in_a_vacuum(config); cancel_with_status(config); + channelz(config); compressed_payload(config); connectivity(config); default_host(config); @@ -408,6 +412,10 @@ void grpc_end2end_tests(int argc, char **argv, cancel_with_status(config); continue; } + if (0 == strcmp("channelz", argv[i])) { + channelz(config); + continue; + } if (0 == strcmp("compressed_payload", argv[i])) { compressed_payload(config); continue; diff --git a/test/core/end2end/gen_build_yaml.py b/test/core/end2end/gen_build_yaml.py index c355fc24b54..53f4ab0d52b 100755 --- a/test/core/end2end/gen_build_yaml.py +++ b/test/core/end2end/gen_build_yaml.py @@ -106,6 +106,7 @@ END2END_TESTS = { needs_compression=True), 'connectivity': connectivity_test_options._replace(needs_names=True, proxyable=False, cpu_cost=LOWCPU, exclude_iomgrs=['uv']), + 'channelz': default_test_options, 'default_host': default_test_options._replace( needs_fullstack=True, needs_dns=True, needs_names=True), 'call_host_override': default_test_options._replace( diff --git a/test/core/end2end/generate_tests.bzl b/test/core/end2end/generate_tests.bzl index 11fc576165b..94bc092b59d 100755 --- a/test/core/end2end/generate_tests.bzl +++ b/test/core/end2end/generate_tests.bzl @@ -113,6 +113,7 @@ END2END_TESTS = { 'compressed_payload': test_options(proxyable=False, exclude_inproc=True), 'connectivity': test_options(needs_fullstack=True, needs_names=True, proxyable=False), + 'channelz': test_options(), 'default_host': test_options(needs_fullstack=True, needs_dns=True, needs_names=True), 'disappearing_server': test_options(needs_fullstack=True,needs_names=True), diff --git a/test/core/end2end/tests/channelz.cc b/test/core/end2end/tests/channelz.cc new file mode 100644 index 00000000000..95d6e3880d7 --- /dev/null +++ b/test/core/end2end/tests/channelz.cc @@ -0,0 +1,263 @@ +/* + * + * 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. + * + */ + +#include "test/core/end2end/end2end_tests.h" + +#include +#include + +#include "src/core/lib/surface/channel.h" + +#include +#include +#include +#include +#include +#include "src/core/lib/gpr/string.h" +#include "test/core/end2end/cq_verifier.h" + +static void* tag(intptr_t t) { return (void*)t; } + +static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, + const char* test_name, + grpc_channel_args* client_args, + grpc_channel_args* server_args) { + grpc_end2end_test_fixture f; + gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name); + f = config.create_fixture(client_args, server_args); + config.init_server(&f, server_args); + config.init_client(&f, client_args); + return f; +} + +static gpr_timespec n_seconds_from_now(int n) { + return grpc_timeout_seconds_to_deadline(n); +} + +static gpr_timespec five_seconds_from_now(void) { + return n_seconds_from_now(5); +} + +static void drain_cq(grpc_completion_queue* cq) { + grpc_event ev; + do { + ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr); + } while (ev.type != GRPC_QUEUE_SHUTDOWN); +} + +static void shutdown_server(grpc_end2end_test_fixture* f) { + if (!f->server) return; + grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000)); + GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000), + grpc_timeout_seconds_to_deadline(5), + nullptr) + .type == GRPC_OP_COMPLETE); + grpc_server_destroy(f->server); + f->server = nullptr; +} + +static void shutdown_client(grpc_end2end_test_fixture* f) { + if (!f->client) return; + grpc_channel_destroy(f->client); + f->client = nullptr; +} + +static void end_test(grpc_end2end_test_fixture* f) { + shutdown_server(f); + shutdown_client(f); + + grpc_completion_queue_shutdown(f->cq); + drain_cq(f->cq); + grpc_completion_queue_destroy(f->cq); + grpc_completion_queue_destroy(f->shutdown_cq); +} + +static void run_one_request(grpc_end2end_test_config config, + grpc_end2end_test_fixture f, + bool request_is_success) { + grpc_call* c; + grpc_call* s; + cq_verifier* cqv = cq_verifier_create(f.cq); + grpc_op ops[6]; + grpc_op* op; + grpc_metadata_array initial_metadata_recv; + grpc_metadata_array trailing_metadata_recv; + grpc_metadata_array request_metadata_recv; + grpc_call_details call_details; + grpc_status_code status; + grpc_call_error error; + grpc_slice details; + int was_cancelled = 2; + + gpr_timespec deadline = five_seconds_from_now(); + c = grpc_channel_create_call(f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq, + grpc_slice_from_static_string("/foo"), nullptr, + deadline, nullptr); + GPR_ASSERT(c); + + grpc_metadata_array_init(&initial_metadata_recv); + grpc_metadata_array_init(&trailing_metadata_recv); + grpc_metadata_array_init(&request_metadata_recv); + grpc_call_details_init(&call_details); + + memset(ops, 0, sizeof(ops)); + op = ops; + op->op = GRPC_OP_SEND_INITIAL_METADATA; + op->data.send_initial_metadata.count = 0; + op->flags = 0; + op->reserved = nullptr; + op++; + op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; + op->flags = 0; + op->reserved = nullptr; + op++; + op->op = GRPC_OP_RECV_INITIAL_METADATA; + op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv; + op->flags = 0; + op->reserved = nullptr; + op++; + op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; + op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv; + op->data.recv_status_on_client.status = &status; + op->data.recv_status_on_client.status_details = &details; + op->data.recv_status_on_client.error_string = nullptr; + op->flags = 0; + op->reserved = nullptr; + op++; + error = grpc_call_start_batch(c, ops, static_cast(op - ops), tag(1), + nullptr); + GPR_ASSERT(GRPC_CALL_OK == error); + + error = + grpc_server_request_call(f.server, &s, &call_details, + &request_metadata_recv, f.cq, f.cq, tag(101)); + GPR_ASSERT(GRPC_CALL_OK == error); + CQ_EXPECT_COMPLETION(cqv, tag(101), 1); + cq_verify(cqv); + + memset(ops, 0, sizeof(ops)); + op = ops; + op->op = GRPC_OP_SEND_INITIAL_METADATA; + op->data.send_initial_metadata.count = 0; + op->flags = 0; + op->reserved = nullptr; + op++; + op->op = GRPC_OP_SEND_STATUS_FROM_SERVER; + op->data.send_status_from_server.trailing_metadata_count = 0; + op->data.send_status_from_server.status = + request_is_success ? GRPC_STATUS_OK : GRPC_STATUS_UNIMPLEMENTED; + grpc_slice status_details = grpc_slice_from_static_string("xyz"); + op->data.send_status_from_server.status_details = &status_details; + op->flags = 0; + op->reserved = nullptr; + op++; + op->op = GRPC_OP_RECV_CLOSE_ON_SERVER; + op->data.recv_close_on_server.cancelled = &was_cancelled; + op->flags = 0; + op->reserved = nullptr; + op++; + error = grpc_call_start_batch(s, ops, static_cast(op - ops), tag(102), + nullptr); + GPR_ASSERT(GRPC_CALL_OK == error); + + CQ_EXPECT_COMPLETION(cqv, tag(102), 1); + CQ_EXPECT_COMPLETION(cqv, tag(1), 1); + cq_verify(cqv); + + GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz")); + GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo")); + GPR_ASSERT(0 == call_details.flags); + + grpc_slice_unref(details); + grpc_metadata_array_destroy(&initial_metadata_recv); + grpc_metadata_array_destroy(&trailing_metadata_recv); + grpc_metadata_array_destroy(&request_metadata_recv); + grpc_call_details_destroy(&call_details); + + grpc_call_unref(c); + grpc_call_unref(s); + + cq_verifier_destroy(cqv); +} + +static void test_channelz(grpc_end2end_test_config config) { + grpc_end2end_test_fixture f; + + f = begin_test(config, "test_channelz", nullptr, nullptr); + grpc_core::channelz::Channel* channelz_channel = + grpc_channel_get_channelz_node(f.client); + + char* json = channelz_channel->RenderJSON(); + GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"0\"")); + GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"0\"")); + GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"0\"")); + gpr_free(json); + + // one successful request + run_one_request(config, f, true); + + json = channelz_channel->RenderJSON(); + GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"1\"")); + GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"0\"")); + GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"1\"")); + gpr_free(json); + + // one failed request + run_one_request(config, f, false); + + json = channelz_channel->RenderJSON(); + gpr_log(GPR_INFO, "%s", json); + GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"2\"")); + GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"1\"")); + GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"1\"")); + gpr_free(json); + + end_test(&f); + config.tear_down_data(&f); +} + +static void test_channelz_with_channel_trace(grpc_end2end_test_config config) { + grpc_end2end_test_fixture f; + + grpc_arg client_a; + client_a.type = GRPC_ARG_INTEGER; + client_a.key = const_cast(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE); + client_a.value.integer = 5; + grpc_channel_args client_args = {1, &client_a}; + + f = begin_test(config, "test_channelz_with_channel_trace", &client_args, + nullptr); + grpc_core::channelz::Channel* channelz_channel = + grpc_channel_get_channelz_node(f.client); + + char* json = channelz_channel->RenderJSON(); + gpr_log(GPR_INFO, "%s", json); + GPR_ASSERT(nullptr != strstr(json, "\"trace\"")); + GPR_ASSERT(nullptr != strstr(json, "\"description\":\"Channel created\"")); + GPR_ASSERT(nullptr != strstr(json, "\"severity\":\"CT_INFO\"")); + gpr_free(json); + + end_test(&f); + config.tear_down_data(&f); +} +void channelz(grpc_end2end_test_config config) { + test_channelz(config); + test_channelz_with_channel_trace(config); +} + +void channelz_pre_init(void) {} diff --git a/test/core/end2end/tests/simple_request.cc b/test/core/end2end/tests/simple_request.cc index 8082bf93d54..941d9ae3198 100644 --- a/test/core/end2end/tests/simple_request.cc +++ b/test/core/end2end/tests/simple_request.cc @@ -21,8 +21,6 @@ #include #include -#include "src/core/lib/surface/channel.h" - #include #include #include @@ -254,18 +252,6 @@ static void test_invoke_simple_request(grpc_end2end_test_config config) { f = begin_test(config, "test_invoke_simple_request", nullptr, nullptr); simple_request_body(config, f); - - // The following is a quick sanity check on channelz functionality. It - // ensures that core properly tracked the one call that occurred in this - // simple end2end test. - grpc_core::channelz::Channel* channelz_channel = - grpc_channel_get_channelz_node(f.client); - char* json = channelz_channel->RenderJSON(); - GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"1\"")); - GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"1\"")); - GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"0\"")); - gpr_free(json); - end_test(&f); config.tear_down_data(&f); } @@ -278,16 +264,6 @@ static void test_invoke_10_simple_requests(grpc_end2end_test_config config) { simple_request_body(config, f); gpr_log(GPR_INFO, "Running test: Passed simple request %d", i); } - - // The following is a quick sanity check on channelz functionality. It - // ensures that core properly tracked the ten calls that occurred. - grpc_core::channelz::Channel* channelz_channel = - grpc_channel_get_channelz_node(f.client); - char* json = channelz_channel->RenderJSON(); - GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"10\"")); - GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"10\"")); - GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"0\"")); - gpr_free(json); end_test(&f); config.tear_down_data(&f); } diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index efe53d7da5c..564f39b6ca1 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -8744,6 +8744,7 @@ "test/core/end2end/tests/cancel_in_a_vacuum.cc", "test/core/end2end/tests/cancel_test_helpers.h", "test/core/end2end/tests/cancel_with_status.cc", + "test/core/end2end/tests/channelz.cc", "test/core/end2end/tests/compressed_payload.cc", "test/core/end2end/tests/connectivity.cc", "test/core/end2end/tests/default_host.cc", @@ -8843,6 +8844,7 @@ "test/core/end2end/tests/cancel_in_a_vacuum.cc", "test/core/end2end/tests/cancel_test_helpers.h", "test/core/end2end/tests/cancel_with_status.cc", + "test/core/end2end/tests/channelz.cc", "test/core/end2end/tests/compressed_payload.cc", "test/core/end2end/tests/connectivity.cc", "test/core/end2end/tests/default_host.cc", diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index 0a02b1df05f..83d4f32eb60 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -7287,6 +7287,29 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "h2_census_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "compressed_payload" @@ -9039,6 +9062,29 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "h2_compress_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "compressed_payload" @@ -10755,6 +10801,28 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "h2_fakesec_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "compressed_payload" @@ -12398,6 +12466,29 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_fd_test", + "platforms": [ + "linux", + "mac", + "posix" + ] + }, { "args": [ "compressed_payload" @@ -13640,6 +13731,29 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "h2_full_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "compressed_payload" @@ -15340,6 +15454,25 @@ "linux" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_test", + "platforms": [ + "linux" + ] + }, { "args": [ "compressed_payload" @@ -16836,6 +16969,29 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "compressed_payload" @@ -18542,6 +18698,29 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "h2_full+workarounds_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "compressed_payload" @@ -20307,6 +20486,30 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_http_proxy_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "compressed_payload" @@ -22142,6 +22345,29 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "h2_load_reporting_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "compressed_payload" @@ -23909,7 +24135,7 @@ }, { "args": [ - "compressed_payload" + "channelz" ], "ci_platforms": [ "windows", @@ -23933,14 +24159,14 @@ }, { "args": [ - "connectivity" + "compressed_payload" ], "ci_platforms": [ "windows", "linux", "posix" ], - "cpu_cost": 0.1, + "cpu_cost": 1.0, "exclude_configs": [], "exclude_iomgrs": [ "uv" @@ -23957,14 +24183,14 @@ }, { "args": [ - "default_host" + "connectivity" ], "ci_platforms": [ "windows", "linux", "posix" ], - "cpu_cost": 1.0, + "cpu_cost": 0.1, "exclude_configs": [], "exclude_iomgrs": [ "uv" @@ -23981,7 +24207,7 @@ }, { "args": [ - "disappearing_server" + "default_host" ], "ci_platforms": [ "windows", @@ -23993,30 +24219,6 @@ "exclude_iomgrs": [ "uv" ], - "flaky": true, - "language": "c", - "name": "h2_oauth2_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, - { - "args": [ - "empty_batch" - ], - "ci_platforms": [ - "windows", - "linux", - "posix" - ], - "cpu_cost": 0.1, - "exclude_configs": [], - "exclude_iomgrs": [ - "uv" - ], "flaky": false, "language": "c", "name": "h2_oauth2_test", @@ -24029,7 +24231,7 @@ }, { "args": [ - "filter_call_init_fails" + "disappearing_server" ], "ci_platforms": [ "windows", @@ -24041,7 +24243,7 @@ "exclude_iomgrs": [ "uv" ], - "flaky": false, + "flaky": true, "language": "c", "name": "h2_oauth2_test", "platforms": [ @@ -24053,7 +24255,55 @@ }, { "args": [ - "filter_causes_close" + "empty_batch" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 0.1, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_oauth2_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "filter_call_init_fails" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_oauth2_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "filter_causes_close" ], "ci_platforms": [ "windows", @@ -25707,6 +25957,30 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_proxy_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "default_host" @@ -26859,6 +27133,30 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_sockpair_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "compressed_payload" @@ -28107,6 +28405,30 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_sockpair+trace_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "compressed_payload" @@ -29305,6 +29627,32 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [ + "msan" + ], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_sockpair_1byte_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "compressed_payload" @@ -30644,6 +30992,29 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "h2_ssl_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "compressed_payload" @@ -32385,6 +32756,30 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_ssl_proxy_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "default_host" @@ -33549,6 +33944,29 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_uds_test", + "platforms": [ + "linux", + "mac", + "posix" + ] + }, { "args": [ "compressed_payload" @@ -35207,30 +35625,7 @@ }, { "args": [ - "empty_batch" - ], - "ci_platforms": [ - "windows", - "linux", - "mac", - "posix" - ], - "cpu_cost": 0.1, - "exclude_configs": [], - "exclude_iomgrs": [], - "flaky": false, - "language": "c", - "name": "inproc_test", - "platforms": [ - "windows", - "linux", - "mac", - "posix" - ] - }, - { - "args": [ - "filter_call_init_fails" + "channelz" ], "ci_platforms": [ "windows", @@ -35253,7 +35648,7 @@ }, { "args": [ - "filter_causes_close" + "empty_batch" ], "ci_platforms": [ "windows", @@ -35276,7 +35671,7 @@ }, { "args": [ - "filter_latency" + "filter_call_init_fails" ], "ci_platforms": [ "windows", @@ -35284,7 +35679,7 @@ "mac", "posix" ], - "cpu_cost": 0.1, + "cpu_cost": 1.0, "exclude_configs": [], "exclude_iomgrs": [], "flaky": false, @@ -35299,7 +35694,7 @@ }, { "args": [ - "filter_status_code" + "filter_causes_close" ], "ci_platforms": [ "windows", @@ -35322,7 +35717,7 @@ }, { "args": [ - "high_initial_seqno" + "filter_latency" ], "ci_platforms": [ "windows", @@ -35345,7 +35740,7 @@ }, { "args": [ - "hpack_size" + "filter_status_code" ], "ci_platforms": [ "windows", @@ -35368,7 +35763,7 @@ }, { "args": [ - "idempotent_request" + "high_initial_seqno" ], "ci_platforms": [ "windows", @@ -35376,7 +35771,7 @@ "mac", "posix" ], - "cpu_cost": 1.0, + "cpu_cost": 0.1, "exclude_configs": [], "exclude_iomgrs": [], "flaky": false, @@ -35391,7 +35786,7 @@ }, { "args": [ - "invoke_large_request" + "hpack_size" ], "ci_platforms": [ "windows", @@ -35399,7 +35794,7 @@ "mac", "posix" ], - "cpu_cost": 1.0, + "cpu_cost": 0.1, "exclude_configs": [], "exclude_iomgrs": [], "flaky": false, @@ -35414,7 +35809,7 @@ }, { "args": [ - "large_metadata" + "idempotent_request" ], "ci_platforms": [ "windows", @@ -35437,7 +35832,53 @@ }, { "args": [ - "load_reporting_hook" + "invoke_large_request" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "inproc_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "large_metadata" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "inproc_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, + { + "args": [ + "load_reporting_hook" ], "ci_platforms": [ "windows", @@ -36194,6 +36635,29 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "h2_census_nosec_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "compressed_payload" @@ -37923,6 +38387,29 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "h2_compress_nosec_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "compressed_payload" @@ -39583,6 +40070,29 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_fd_nosec_test", + "platforms": [ + "linux", + "mac", + "posix" + ] + }, { "args": [ "compressed_payload" @@ -40802,6 +41312,29 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "h2_full_nosec_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "compressed_payload" @@ -42483,6 +43016,25 @@ "linux" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_full+pipe_nosec_test", + "platforms": [ + "linux" + ] + }, { "args": [ "compressed_payload" @@ -43956,6 +44508,29 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "h2_full+trace_nosec_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "compressed_payload" @@ -45639,6 +46214,29 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "h2_full+workarounds_nosec_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "compressed_payload" @@ -47380,6 +47978,30 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_http_proxy_nosec_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "compressed_payload" @@ -49192,6 +49814,29 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "h2_load_reporting_nosec_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "compressed_payload" @@ -50909,6 +51554,30 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_proxy_nosec_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "default_host" @@ -52037,6 +52706,30 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_sockpair_nosec_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "compressed_payload" @@ -53261,6 +53954,30 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_sockpair+trace_nosec_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "compressed_payload" @@ -54433,6 +55150,32 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "windows", + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [ + "msan" + ], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_sockpair_1byte_nosec_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "compressed_payload" @@ -55726,6 +56469,29 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "h2_uds_nosec_test", + "platforms": [ + "linux", + "mac", + "posix" + ] + }, { "args": [ "compressed_payload" @@ -57359,6 +58125,29 @@ "posix" ] }, + { + "args": [ + "channelz" + ], + "ci_platforms": [ + "windows", + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "language": "c", + "name": "inproc_nosec_test", + "platforms": [ + "windows", + "linux", + "mac", + "posix" + ] + }, { "args": [ "empty_batch" From 6c987cbf0911b6d97eeec2e14bff2e8fc5bc40e5 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Fri, 8 Jun 2018 09:30:12 -0700 Subject: [PATCH 15/57] Rename channelz Channel to ChannelNode --- src/core/lib/channel/channel_trace.cc | 10 +++++----- src/core/lib/channel/channel_trace.h | 11 ++++++----- src/core/lib/channel/channelz.cc | 10 +++++----- src/core/lib/channel/channelz.h | 10 +++++----- src/core/lib/surface/call.cc | 4 ++-- src/core/lib/surface/channel.cc | 6 +++--- src/core/lib/surface/channel.h | 2 +- test/core/channel/channelz_test.cc | 18 +++++++++--------- 8 files changed, 36 insertions(+), 35 deletions(-) diff --git a/src/core/lib/channel/channel_trace.cc b/src/core/lib/channel/channel_trace.cc index 4c29df42f42..0f655d87160 100644 --- a/src/core/lib/channel/channel_trace.cc +++ b/src/core/lib/channel/channel_trace.cc @@ -41,9 +41,9 @@ namespace grpc_core { namespace channelz { -ChannelTrace::TraceEvent::TraceEvent(Severity severity, grpc_slice data, - RefCountedPtr referenced_channel, - ReferencedType type) +ChannelTrace::TraceEvent::TraceEvent( + Severity severity, grpc_slice data, + RefCountedPtr referenced_channel, ReferencedType type) : severity_(severity), data_(data), timestamp_(grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(), @@ -112,7 +112,7 @@ void ChannelTrace::AddTraceEvent(Severity severity, grpc_slice data) { void ChannelTrace::AddTraceEventReferencingChannel( Severity severity, grpc_slice data, - RefCountedPtr referenced_channel) { + RefCountedPtr referenced_channel) { if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0 // create and fill up the new event AddTraceEventHelper(New( @@ -121,7 +121,7 @@ void ChannelTrace::AddTraceEventReferencingChannel( void ChannelTrace::AddTraceEventReferencingSubchannel( Severity severity, grpc_slice data, - RefCountedPtr referenced_subchannel) { + RefCountedPtr referenced_subchannel) { if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0 // create and fill up the new event AddTraceEventHelper(New(severity, data, diff --git a/src/core/lib/channel/channel_trace.h b/src/core/lib/channel/channel_trace.h index f6021c32243..0dd162a7778 100644 --- a/src/core/lib/channel/channel_trace.h +++ b/src/core/lib/channel/channel_trace.h @@ -30,7 +30,7 @@ namespace grpc_core { namespace channelz { -class Channel; +class ChannelNode; // Object used to hold live data for a channel. This data is exposed via the // channelz service: @@ -64,10 +64,10 @@ class ChannelTrace { // slice. void AddTraceEventReferencingChannel( Severity severity, grpc_slice data, - RefCountedPtr referenced_channel); + RefCountedPtr referenced_channel); void AddTraceEventReferencingSubchannel( Severity severity, grpc_slice data, - RefCountedPtr referenced_subchannel); + RefCountedPtr referenced_subchannel); // Creates and returns the raw grpc_json object, so a parent channelz // object may incorporate the json before rendering. @@ -82,7 +82,8 @@ class ChannelTrace { public: // Constructor for a TraceEvent that references a different channel. TraceEvent(Severity severity, grpc_slice data, - RefCountedPtr referenced_channel, ReferencedType type); + RefCountedPtr referenced_channel, + ReferencedType type); // Constructor for a TraceEvent that does not reverence a different // channel. @@ -104,7 +105,7 @@ class ChannelTrace { gpr_timespec timestamp_; TraceEvent* next_; // the tracer object for the (sub)channel that this trace event refers to. - RefCountedPtr referenced_channel_; + RefCountedPtr referenced_channel_; // the type that the referenced tracer points to. Unused if this trace // does not point to any channel or subchannel ReferencedType referenced_type_; diff --git a/src/core/lib/channel/channelz.cc b/src/core/lib/channel/channelz.cc index 42b169dffd1..799eb8bed1a 100644 --- a/src/core/lib/channel/channelz.cc +++ b/src/core/lib/channel/channelz.cc @@ -89,7 +89,7 @@ grpc_json* add_num_str(grpc_json* parent, grpc_json* it, const char* name, } // namespace -Channel::Channel(grpc_channel* channel, size_t channel_tracer_max_nodes) +ChannelNode::ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes) : channel_(channel), target_(UniquePtr(grpc_channel_get_target(channel_))), channel_uuid_(ChannelzRegistry::Register(this)) { @@ -98,18 +98,18 @@ Channel::Channel(grpc_channel* channel, size_t channel_tracer_max_nodes) (gpr_atm)ExecCtx::Get()->Now()); } -Channel::~Channel() { +ChannelNode::~ChannelNode() { trace_.Destroy(); ChannelzRegistry::Unregister(channel_uuid_); } -void Channel::RecordCallStarted() { +void ChannelNode::RecordCallStarted() { gpr_atm_no_barrier_fetch_add(&calls_started_, (gpr_atm)1); gpr_atm_no_barrier_store(&last_call_started_millis_, (gpr_atm)ExecCtx::Get()->Now()); } -grpc_connectivity_state Channel::GetConnectivityState() { +grpc_connectivity_state ChannelNode::GetConnectivityState() { if (channel_ == nullptr) { return GRPC_CHANNEL_SHUTDOWN; } else { @@ -117,7 +117,7 @@ grpc_connectivity_state Channel::GetConnectivityState() { } } -char* Channel::RenderJSON() { +char* ChannelNode::RenderJSON() { // We need to track these three json objects to build our object grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT); grpc_json* json = top_level_json; diff --git a/src/core/lib/channel/channelz.h b/src/core/lib/channel/channelz.h index 68b7c8d26b9..62dc817b6ad 100644 --- a/src/core/lib/channel/channelz.h +++ b/src/core/lib/channel/channelz.h @@ -35,13 +35,13 @@ namespace grpc_core { namespace channelz { namespace testing { -class ChannelPeer; +class ChannelNodePeer; } -class Channel : public RefCounted { +class ChannelNode : public RefCounted { public: - Channel(grpc_channel* channel, size_t channel_tracer_max_nodes); - ~Channel(); + ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes); + ~ChannelNode(); void RecordCallStarted(); void RecordCallFailed() { @@ -64,7 +64,7 @@ class Channel : public RefCounted { private: // testing peer friend. - friend class testing::ChannelPeer; + friend class testing::ChannelNodePeer; // helper for getting connectivity state. grpc_connectivity_state GetConnectivityState(); diff --git a/src/core/lib/surface/call.cc b/src/core/lib/surface/call.cc index 65071672f27..33b9908a574 100644 --- a/src/core/lib/surface/call.cc +++ b/src/core/lib/surface/call.cc @@ -478,7 +478,7 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args, &call->pollent); } - grpc_core::channelz::Channel* channelz_channel = + grpc_core::channelz::ChannelNode* channelz_channel = grpc_channel_get_channelz_node(call->channel); channelz_channel->RecordCallStarted(); @@ -1260,7 +1260,7 @@ static void post_batch_completion(batch_control* bctl) { call->final_op.server.cancelled, nullptr, nullptr); } - grpc_core::channelz::Channel* channelz_channel = + grpc_core::channelz::ChannelNode* channelz_channel = grpc_channel_get_channelz_node(call->channel); if (*call->final_op.client.status != GRPC_STATUS_OK) { channelz_channel->RecordCallFailed(); diff --git a/src/core/lib/surface/channel.cc b/src/core/lib/surface/channel.cc index d2b52dad2fd..7dcfbc97cc1 100644 --- a/src/core/lib/surface/channel.cc +++ b/src/core/lib/surface/channel.cc @@ -67,7 +67,7 @@ struct grpc_channel { gpr_mu registered_call_mu; registered_call* registered_calls; - grpc_core::RefCountedPtr channelz_channel; + grpc_core::RefCountedPtr channelz_channel; char* target; }; @@ -147,7 +147,7 @@ grpc_channel* grpc_channel_create_with_builder( grpc_channel_args_destroy(args); channel->channelz_channel = - grpc_core::MakeRefCounted( + grpc_core::MakeRefCounted( channel, channel_tracer_max_nodes); channel->channelz_channel->trace()->AddTraceEvent( grpc_core::channelz::ChannelTrace::Severity::Info, @@ -190,7 +190,7 @@ char* grpc_channel_render_channelz(grpc_channel* channel) { return channel->channelz_channel->RenderJSON(); } -grpc_core::channelz::Channel* grpc_channel_get_channelz_node( +grpc_core::channelz::ChannelNode* grpc_channel_get_channelz_node( grpc_channel* channel) { return channel->channelz_channel.get(); } diff --git a/src/core/lib/surface/channel.h b/src/core/lib/surface/channel.h index 6d2e1931e68..e5ff2c35969 100644 --- a/src/core/lib/surface/channel.h +++ b/src/core/lib/surface/channel.h @@ -51,7 +51,7 @@ grpc_call* grpc_channel_create_pollset_set_call( /** Get a (borrowed) pointer to this channels underlying channel stack */ grpc_channel_stack* grpc_channel_get_channel_stack(grpc_channel* channel); -grpc_core::channelz::Channel* grpc_channel_get_channelz_node( +grpc_core::channelz::ChannelNode* grpc_channel_get_channelz_node( grpc_channel* channel); /** Get a grpc_mdelem of grpc-status: X where X is the numeric value of diff --git a/test/core/channel/channelz_test.cc b/test/core/channel/channelz_test.cc index 262ca38ee05..8ef91c3b09f 100644 --- a/test/core/channel/channelz_test.cc +++ b/test/core/channel/channelz_test.cc @@ -44,16 +44,16 @@ namespace channelz { namespace testing { // testing peer to access channel internals -class ChannelPeer { +class ChannelNodePeer { public: - ChannelPeer(Channel* channel) : channel_(channel) {} + ChannelNodePeer(ChannelNode* channel) : channel_(channel) {} grpc_millis last_call_started_millis() { return (grpc_millis)gpr_atm_no_barrier_load( &channel_->last_call_started_millis_); } private: - Channel* channel_; + ChannelNode* channel_; }; namespace { @@ -111,15 +111,15 @@ void ValidateCounters(char* json_str, validate_channel_data_args args) { grpc_json_destroy(json); } -void ValidateChannel(Channel* channel, validate_channel_data_args args) { +void ValidateChannel(ChannelNode* channel, validate_channel_data_args args) { char* json_str = channel->RenderJSON(); grpc::testing::ValidateChannelProtoJsonTranslation(json_str); ValidateCounters(json_str, args); gpr_free(json_str); } -grpc_millis GetLastCallStartedMillis(Channel* channel) { - ChannelPeer peer(channel); +grpc_millis GetLastCallStartedMillis(ChannelNode* channel) { + ChannelNodePeer peer(channel); return peer.last_call_started_millis(); } @@ -137,7 +137,7 @@ TEST_P(ChannelzChannelTest, BasicChannel) { grpc_core::ExecCtx exec_ctx; ChannelFixture channel(GetParam()); intptr_t uuid = grpc_channel_get_uuid(channel.channel()); - Channel* channelz_channel = ChannelzRegistry::Get(uuid); + ChannelNode* channelz_channel = ChannelzRegistry::Get(uuid); char* json_str = channelz_channel->RenderJSON(); ValidateCounters(json_str, {0, 0, 0}); gpr_free(json_str); @@ -147,7 +147,7 @@ TEST_P(ChannelzChannelTest, BasicChannelAPIFunctionality) { grpc_core::ExecCtx exec_ctx; ChannelFixture channel(GetParam()); intptr_t uuid = grpc_channel_get_uuid(channel.channel()); - Channel* channelz_channel = ChannelzRegistry::Get(uuid); + ChannelNode* channelz_channel = ChannelzRegistry::Get(uuid); channelz_channel->RecordCallStarted(); channelz_channel->RecordCallFailed(); channelz_channel->RecordCallSucceeded(); @@ -165,7 +165,7 @@ TEST_P(ChannelzChannelTest, LastCallStartedMillis) { grpc_core::ExecCtx exec_ctx; ChannelFixture channel(GetParam()); intptr_t uuid = grpc_channel_get_uuid(channel.channel()); - Channel* channelz_channel = ChannelzRegistry::Get(uuid); + ChannelNode* channelz_channel = ChannelzRegistry::Get(uuid); // start a call to set the last call started timestamp channelz_channel->RecordCallStarted(); grpc_millis millis1 = GetLastCallStartedMillis(channelz_channel); From 16280c7398809f374a90f1e6150d788cf7f2f6f2 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Fri, 8 Jun 2018 09:44:25 -0700 Subject: [PATCH 16/57] Remove unused API --- grpc.def | 1 - include/grpc/grpc.h | 4 ---- src/core/lib/surface/channel.cc | 4 ---- src/ruby/ext/grpc/rb_grpc_imports.generated.c | 2 -- src/ruby/ext/grpc/rb_grpc_imports.generated.h | 3 --- test/core/channel/channelz_test.cc | 12 ++++++------ test/core/surface/public_headers_must_be_c89.c | 1 - 7 files changed, 6 insertions(+), 21 deletions(-) diff --git a/grpc.def b/grpc.def index fc1d02a0352..e7f93396b2d 100644 --- a/grpc.def +++ b/grpc.def @@ -45,7 +45,6 @@ EXPORTS grpc_insecure_channel_create grpc_lame_client_channel_create grpc_channel_destroy - grpc_channel_get_uuid grpc_call_cancel grpc_call_cancel_with_status grpc_call_ref diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h index bb4a70f7b9f..c129a66949f 100644 --- a/include/grpc/grpc.h +++ b/include/grpc/grpc.h @@ -286,10 +286,6 @@ GRPCAPI grpc_channel* grpc_lame_client_channel_create( /** Close and destroy a grpc channel */ GRPCAPI void grpc_channel_destroy(grpc_channel* channel); -/** Returns the channel uuid, which can be used to look up its trace at a - later time. */ -GRPCAPI intptr_t grpc_channel_get_uuid(grpc_channel* channel); - /** Error handling for grpc_call Most grpc_call functions return a grpc_error. If the error is not GRPC_OK then the operation failed due to some unsatisfied precondition. diff --git a/src/core/lib/surface/channel.cc b/src/core/lib/surface/channel.cc index 7dcfbc97cc1..69c1329cdaa 100644 --- a/src/core/lib/surface/channel.cc +++ b/src/core/lib/surface/channel.cc @@ -195,10 +195,6 @@ grpc_core::channelz::ChannelNode* grpc_channel_get_channelz_node( return channel->channelz_channel.get(); } -intptr_t grpc_channel_get_uuid(grpc_channel* channel) { - return channel->channelz_channel->channel_uuid(); -} - grpc_channel* grpc_channel_create(const char* target, const grpc_channel_args* input_args, grpc_channel_stack_type channel_stack_type, diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c index 8b67a7ce2d2..031699ce8e2 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c @@ -68,7 +68,6 @@ grpc_channel_get_info_type grpc_channel_get_info_import; grpc_insecure_channel_create_type grpc_insecure_channel_create_import; grpc_lame_client_channel_create_type grpc_lame_client_channel_create_import; grpc_channel_destroy_type grpc_channel_destroy_import; -grpc_channel_get_uuid_type grpc_channel_get_uuid_import; grpc_call_cancel_type grpc_call_cancel_import; grpc_call_cancel_with_status_type grpc_call_cancel_with_status_import; grpc_call_ref_type grpc_call_ref_import; @@ -315,7 +314,6 @@ void grpc_rb_load_imports(HMODULE library) { grpc_insecure_channel_create_import = (grpc_insecure_channel_create_type) GetProcAddress(library, "grpc_insecure_channel_create"); grpc_lame_client_channel_create_import = (grpc_lame_client_channel_create_type) GetProcAddress(library, "grpc_lame_client_channel_create"); grpc_channel_destroy_import = (grpc_channel_destroy_type) GetProcAddress(library, "grpc_channel_destroy"); - grpc_channel_get_uuid_import = (grpc_channel_get_uuid_type) GetProcAddress(library, "grpc_channel_get_uuid"); grpc_call_cancel_import = (grpc_call_cancel_type) GetProcAddress(library, "grpc_call_cancel"); grpc_call_cancel_with_status_import = (grpc_call_cancel_with_status_type) GetProcAddress(library, "grpc_call_cancel_with_status"); grpc_call_ref_import = (grpc_call_ref_type) GetProcAddress(library, "grpc_call_ref"); diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h index c7919871c86..3cc6492d04f 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h @@ -179,9 +179,6 @@ extern grpc_lame_client_channel_create_type grpc_lame_client_channel_create_impo typedef void(*grpc_channel_destroy_type)(grpc_channel* channel); extern grpc_channel_destroy_type grpc_channel_destroy_import; #define grpc_channel_destroy grpc_channel_destroy_import -typedef intptr_t(*grpc_channel_get_uuid_type)(grpc_channel* channel); -extern grpc_channel_get_uuid_type grpc_channel_get_uuid_import; -#define grpc_channel_get_uuid grpc_channel_get_uuid_import typedef grpc_call_error(*grpc_call_cancel_type)(grpc_call* call, void* reserved); extern grpc_call_cancel_type grpc_call_cancel_import; #define grpc_call_cancel grpc_call_cancel_import diff --git a/test/core/channel/channelz_test.cc b/test/core/channel/channelz_test.cc index 8ef91c3b09f..facf1c03f76 100644 --- a/test/core/channel/channelz_test.cc +++ b/test/core/channel/channelz_test.cc @@ -136,8 +136,8 @@ class ChannelzChannelTest : public ::testing::TestWithParam {}; TEST_P(ChannelzChannelTest, BasicChannel) { grpc_core::ExecCtx exec_ctx; ChannelFixture channel(GetParam()); - intptr_t uuid = grpc_channel_get_uuid(channel.channel()); - ChannelNode* channelz_channel = ChannelzRegistry::Get(uuid); + ChannelNode* channelz_channel = + grpc_channel_get_channelz_node(channel.channel()); char* json_str = channelz_channel->RenderJSON(); ValidateCounters(json_str, {0, 0, 0}); gpr_free(json_str); @@ -146,8 +146,8 @@ TEST_P(ChannelzChannelTest, BasicChannel) { TEST_P(ChannelzChannelTest, BasicChannelAPIFunctionality) { grpc_core::ExecCtx exec_ctx; ChannelFixture channel(GetParam()); - intptr_t uuid = grpc_channel_get_uuid(channel.channel()); - ChannelNode* channelz_channel = ChannelzRegistry::Get(uuid); + ChannelNode* channelz_channel = + grpc_channel_get_channelz_node(channel.channel()); channelz_channel->RecordCallStarted(); channelz_channel->RecordCallFailed(); channelz_channel->RecordCallSucceeded(); @@ -164,8 +164,8 @@ TEST_P(ChannelzChannelTest, BasicChannelAPIFunctionality) { TEST_P(ChannelzChannelTest, LastCallStartedMillis) { grpc_core::ExecCtx exec_ctx; ChannelFixture channel(GetParam()); - intptr_t uuid = grpc_channel_get_uuid(channel.channel()); - ChannelNode* channelz_channel = ChannelzRegistry::Get(uuid); + ChannelNode* channelz_channel = + grpc_channel_get_channelz_node(channel.channel()); // start a call to set the last call started timestamp channelz_channel->RecordCallStarted(); grpc_millis millis1 = GetLastCallStartedMillis(channelz_channel); diff --git a/test/core/surface/public_headers_must_be_c89.c b/test/core/surface/public_headers_must_be_c89.c index 96b25ebdaff..29083061bbb 100644 --- a/test/core/surface/public_headers_must_be_c89.c +++ b/test/core/surface/public_headers_must_be_c89.c @@ -106,7 +106,6 @@ int main(int argc, char **argv) { printf("%lx", (unsigned long) grpc_insecure_channel_create); printf("%lx", (unsigned long) grpc_lame_client_channel_create); printf("%lx", (unsigned long) grpc_channel_destroy); - printf("%lx", (unsigned long) grpc_channel_get_uuid); printf("%lx", (unsigned long) grpc_call_cancel); printf("%lx", (unsigned long) grpc_call_cancel_with_status); printf("%lx", (unsigned long) grpc_call_ref); From db6593eb4045f2bcf0aabf61945dbddc8c7f791e Mon Sep 17 00:00:00 2001 From: ncteisen Date: Fri, 8 Jun 2018 09:46:55 -0700 Subject: [PATCH 17/57] fixup! Rename channelz Channel to ChannelNode --- test/core/end2end/tests/channelz.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/core/end2end/tests/channelz.cc b/test/core/end2end/tests/channelz.cc index 95d6e3880d7..9766646c138 100644 --- a/test/core/end2end/tests/channelz.cc +++ b/test/core/end2end/tests/channelz.cc @@ -199,7 +199,7 @@ static void test_channelz(grpc_end2end_test_config config) { grpc_end2end_test_fixture f; f = begin_test(config, "test_channelz", nullptr, nullptr); - grpc_core::channelz::Channel* channelz_channel = + grpc_core::channelz::ChannelNode* channelz_channel = grpc_channel_get_channelz_node(f.client); char* json = channelz_channel->RenderJSON(); @@ -242,7 +242,7 @@ static void test_channelz_with_channel_trace(grpc_end2end_test_config config) { f = begin_test(config, "test_channelz_with_channel_trace", &client_args, nullptr); - grpc_core::channelz::Channel* channelz_channel = + grpc_core::channelz::ChannelNode* channelz_channel = grpc_channel_get_channelz_node(f.client); char* json = channelz_channel->RenderJSON(); From 5644c5928d748e44478bbddc97fcc75488878d8c Mon Sep 17 00:00:00 2001 From: ncteisen Date: Fri, 8 Jun 2018 11:09:44 -0700 Subject: [PATCH 18/57] fixup! fixup! Rename channelz Channel to ChannelNode --- test/core/channel/channel_trace_test.cc | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/test/core/channel/channel_trace_test.cc b/test/core/channel/channel_trace_test.cc index ef69e631410..bbddee3f14e 100644 --- a/test/core/channel/channel_trace_test.cc +++ b/test/core/channel/channel_trace_test.cc @@ -156,8 +156,8 @@ TEST_P(ChannelTracerTest, ComplexTest) { AddSimpleTrace(&tracer); AddSimpleTrace(&tracer); ChannelFixture channel1(GetParam()); - RefCountedPtr sc1 = - MakeRefCounted(channel1.channel(), GetParam()); + RefCountedPtr sc1 = + MakeRefCounted(channel1.channel(), GetParam()); tracer.AddTraceEventReferencingSubchannel( ChannelTrace::Severity::Info, grpc_slice_from_static_string("subchannel one created"), sc1); @@ -174,8 +174,8 @@ TEST_P(ChannelTracerTest, ComplexTest) { AddSimpleTrace(&tracer); ValidateChannelTrace(&tracer, 5, GetParam()); ChannelFixture channel2(GetParam()); - RefCountedPtr sc2 = - MakeRefCounted(channel2.channel(), GetParam()); + RefCountedPtr sc2 = + MakeRefCounted(channel2.channel(), GetParam()); tracer.AddTraceEventReferencingChannel( ChannelTrace::Severity::Info, grpc_slice_from_static_string("LB channel two created"), sc2); @@ -203,16 +203,16 @@ TEST_P(ChannelTracerTest, TestNesting) { AddSimpleTrace(&tracer); ValidateChannelTrace(&tracer, 2, GetParam()); ChannelFixture channel1(GetParam()); - RefCountedPtr sc1 = - MakeRefCounted(channel1.channel(), GetParam()); + RefCountedPtr sc1 = + MakeRefCounted(channel1.channel(), GetParam()); tracer.AddTraceEventReferencingChannel( ChannelTrace::Severity::Info, grpc_slice_from_static_string("subchannel one created"), sc1); ValidateChannelTrace(&tracer, 3, GetParam()); AddSimpleTrace(sc1->trace()); ChannelFixture channel2(GetParam()); - RefCountedPtr conn1 = - MakeRefCounted(channel2.channel(), GetParam()); + RefCountedPtr conn1 = + MakeRefCounted(channel2.channel(), GetParam()); // nesting one level deeper. sc1->trace()->AddTraceEventReferencingSubchannel( ChannelTrace::Severity::Info, @@ -224,8 +224,8 @@ TEST_P(ChannelTracerTest, TestNesting) { ValidateChannelTrace(&tracer, 5, GetParam()); ValidateChannelTrace(conn1->trace(), 1, GetParam()); ChannelFixture channel3(GetParam()); - RefCountedPtr sc2 = - MakeRefCounted(channel3.channel(), GetParam()); + RefCountedPtr sc2 = + MakeRefCounted(channel3.channel(), GetParam()); tracer.AddTraceEventReferencingSubchannel( ChannelTrace::Severity::Info, grpc_slice_from_static_string("subchannel two created"), sc2); From e5047b5244486b4e80b702442137060aa18fd54b Mon Sep 17 00:00:00 2001 From: ncteisen Date: Fri, 8 Jun 2018 11:49:39 -0700 Subject: [PATCH 19/57] Fix ASAN --- src/core/lib/surface/channel.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/lib/surface/channel.cc b/src/core/lib/surface/channel.cc index 69c1329cdaa..087b7778bfd 100644 --- a/src/core/lib/surface/channel.cc +++ b/src/core/lib/surface/channel.cc @@ -398,6 +398,8 @@ void grpc_channel_internal_unref(grpc_channel* c REF_ARG) { static void destroy_channel(void* arg, grpc_error* error) { grpc_channel* channel = static_cast(arg); + channel->channelz_channel->set_channel_destroyed(); + channel->channelz_channel.reset(); grpc_channel_stack_destroy(CHANNEL_STACK_FROM_CHANNEL(channel)); while (channel->registered_calls) { registered_call* rc = channel->registered_calls; @@ -420,8 +422,6 @@ void grpc_channel_destroy(grpc_channel* channel) { GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel Destroyed"); elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CHANNEL(channel), 0); elem->filter->start_transport_op(elem, op); - channel->channelz_channel->set_channel_destroyed(); - channel->channelz_channel.reset(); GRPC_CHANNEL_INTERNAL_UNREF(channel, "channel"); } From 9868c025f0bb6e92f6c8b262eacc9a31cd99a2a8 Mon Sep 17 00:00:00 2001 From: Srini Polavarapu Date: Fri, 8 Jun 2018 17:14:08 -0700 Subject: [PATCH 20/57] Bump version to v1.13.0-pre1 --- BUILD | 4 ++-- build.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/BUILD b/BUILD index ea8cf505877..0dacfd9e3cf 100644 --- a/BUILD +++ b/BUILD @@ -66,9 +66,9 @@ config_setting( # This should be updated along with build.yaml g_stands_for = "gloriosa" -core_version = "6.0.0-dev" +core_version = "6.0.0-pre1" -version = "1.13.0-dev" +version = "1.13.0-pre1" GPR_PUBLIC_HDRS = [ "include/grpc/support/alloc.h", diff --git a/build.yaml b/build.yaml index ff87d5965a3..2a34681d96e 100644 --- a/build.yaml +++ b/build.yaml @@ -12,9 +12,9 @@ settings: '#08': Use "-preN" suffixes to identify pre-release versions '#09': Per-language overrides are possible with (eg) ruby_version tag here '#10': See the expand_version.py for all the quirks here - core_version: 6.0.0-dev + core_version: 6.0.0-pre1 g_stands_for: gloriosa - version: 1.13.0-dev + version: 1.13.0-pre1 filegroups: - name: alts_proto headers: From 586c6397959355bc2ecdfd6dc9bb82c80c79232d Mon Sep 17 00:00:00 2001 From: Srini Polavarapu Date: Fri, 8 Jun 2018 17:16:17 -0700 Subject: [PATCH 21/57] Regenerate projects --- CMakeLists.txt | 2 +- Makefile | 6 +++--- gRPC-C++.podspec | 4 ++-- gRPC-Core.podspec | 2 +- gRPC-ProtoRPC.podspec | 2 +- gRPC-RxLibrary.podspec | 2 +- gRPC.podspec | 2 +- package.xml | 4 ++-- src/core/lib/surface/version.cc | 2 +- src/cpp/common/version_cc.cc | 2 +- src/csharp/Grpc.Core/Version.csproj.include | 2 +- src/csharp/Grpc.Core/VersionInfo.cs | 2 +- src/csharp/build_packages_dotnetcli.bat | 2 +- src/csharp/build_packages_dotnetcli.sh | 6 +++--- src/objective-c/!ProtoCompiler-gRPCPlugin.podspec | 2 +- src/objective-c/GRPCClient/private/version.h | 2 +- src/objective-c/tests/version.h | 4 ++-- src/php/ext/grpc/version.h | 2 +- src/python/grpcio/grpc/_grpcio_metadata.py | 2 +- src/python/grpcio/grpc_version.py | 2 +- src/python/grpcio_health_checking/grpc_version.py | 2 +- src/python/grpcio_reflection/grpc_version.py | 2 +- src/python/grpcio_testing/grpc_version.py | 2 +- src/python/grpcio_tests/grpc_version.py | 2 +- src/ruby/lib/grpc/version.rb | 2 +- src/ruby/tools/version.rb | 2 +- tools/distrib/python/grpcio_tools/grpc_version.py | 2 +- tools/doxygen/Doxyfile.c++ | 2 +- tools/doxygen/Doxyfile.c++.internal | 2 +- tools/doxygen/Doxyfile.core | 2 +- tools/doxygen/Doxyfile.core.internal | 2 +- 31 files changed, 38 insertions(+), 38 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 71bebde5d8a..b38d48ac03b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ cmake_minimum_required(VERSION 2.8) set(PACKAGE_NAME "grpc") -set(PACKAGE_VERSION "1.13.0-dev") +set(PACKAGE_VERSION "1.13.0-pre1") set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_TARNAME "${PACKAGE_NAME}-${PACKAGE_VERSION}") set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/") diff --git a/Makefile b/Makefile index 1247566ffec..6c9ca5211e5 100644 --- a/Makefile +++ b/Makefile @@ -420,9 +420,9 @@ E = @echo Q = @ endif -CORE_VERSION = 6.0.0-dev -CPP_VERSION = 1.13.0-dev -CSHARP_VERSION = 1.13.0-dev +CORE_VERSION = 6.0.0-pre1 +CPP_VERSION = 1.13.0-pre1 +CSHARP_VERSION = 1.13.0-pre1 CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES)) CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS) diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index 262de72971b..e6fadf5d387 100644 --- a/gRPC-C++.podspec +++ b/gRPC-C++.podspec @@ -23,7 +23,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-C++' # TODO (mxyan): use version that match gRPC version when pod is stabilized - # version = '1.13.0-dev' + # version = '1.13.0-pre1' version = '0.0.2' s.version = version s.summary = 'gRPC C++ library' @@ -31,7 +31,7 @@ Pod::Spec.new do |s| s.license = 'Apache License, Version 2.0' s.authors = { 'The gRPC contributors' => 'grpc-packages@google.com' } - grpc_version = '1.13.0-dev' + grpc_version = '1.13.0-pre1' s.source = { :git => 'https://github.com/grpc/grpc.git', diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 5a111c2d3f0..45766ceec73 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -22,7 +22,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-Core' - version = '1.13.0-dev' + version = '1.13.0-pre1' s.version = version s.summary = 'Core cross-platform gRPC library, written in C' s.homepage = 'https://grpc.io' diff --git a/gRPC-ProtoRPC.podspec b/gRPC-ProtoRPC.podspec index 039f3d412b5..59c6a09d428 100644 --- a/gRPC-ProtoRPC.podspec +++ b/gRPC-ProtoRPC.podspec @@ -21,7 +21,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-ProtoRPC' - version = '1.13.0-dev' + version = '1.13.0-pre1' s.version = version s.summary = 'RPC library for Protocol Buffers, based on gRPC' s.homepage = 'https://grpc.io' diff --git a/gRPC-RxLibrary.podspec b/gRPC-RxLibrary.podspec index b9288afd806..81d9a2bda29 100644 --- a/gRPC-RxLibrary.podspec +++ b/gRPC-RxLibrary.podspec @@ -21,7 +21,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-RxLibrary' - version = '1.13.0-dev' + version = '1.13.0-pre1' s.version = version s.summary = 'Reactive Extensions library for iOS/OSX.' s.homepage = 'https://grpc.io' diff --git a/gRPC.podspec b/gRPC.podspec index a1d77206281..bec5f21ab95 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -20,7 +20,7 @@ Pod::Spec.new do |s| s.name = 'gRPC' - version = '1.13.0-dev' + version = '1.13.0-pre1' s.version = version s.summary = 'gRPC client library for iOS/OSX' s.homepage = 'https://grpc.io' diff --git a/package.xml b/package.xml index b8cda9d79f0..58c754765fd 100644 --- a/package.xml +++ b/package.xml @@ -13,8 +13,8 @@ 2018-01-19 - 1.13.0dev - 1.13.0dev + 1.13.0RC1 + 1.13.0RC1 beta diff --git a/src/core/lib/surface/version.cc b/src/core/lib/surface/version.cc index 306b7c395ea..2de5e5266ed 100644 --- a/src/core/lib/surface/version.cc +++ b/src/core/lib/surface/version.cc @@ -23,6 +23,6 @@ #include -const char* grpc_version_string(void) { return "6.0.0-dev"; } +const char* grpc_version_string(void) { return "6.0.0-pre1"; } const char* grpc_g_stands_for(void) { return "gloriosa"; } diff --git a/src/cpp/common/version_cc.cc b/src/cpp/common/version_cc.cc index 54cd2076ec0..6877d8f67f5 100644 --- a/src/cpp/common/version_cc.cc +++ b/src/cpp/common/version_cc.cc @@ -22,5 +22,5 @@ #include namespace grpc { -grpc::string Version() { return "1.13.0-dev"; } +grpc::string Version() { return "1.13.0-pre1"; } } // namespace grpc diff --git a/src/csharp/Grpc.Core/Version.csproj.include b/src/csharp/Grpc.Core/Version.csproj.include index f5d63b77f05..e27bd731212 100755 --- a/src/csharp/Grpc.Core/Version.csproj.include +++ b/src/csharp/Grpc.Core/Version.csproj.include @@ -1,7 +1,7 @@ - 1.13.0-dev + 1.13.0-pre1 3.5.1 diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs index 87edddae3fc..2e1c0c972e7 100644 --- a/src/csharp/Grpc.Core/VersionInfo.cs +++ b/src/csharp/Grpc.Core/VersionInfo.cs @@ -38,6 +38,6 @@ namespace Grpc.Core /// /// Current version of gRPC C# /// - public const string CurrentVersion = "1.13.0-dev"; + public const string CurrentVersion = "1.13.0-pre1"; } } diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat index f1111781e2b..8390efcff01 100755 --- a/src/csharp/build_packages_dotnetcli.bat +++ b/src/csharp/build_packages_dotnetcli.bat @@ -13,7 +13,7 @@ @rem limitations under the License. @rem Current package versions -set VERSION=1.13.0-dev +set VERSION=1.13.0-pre1 @rem Adjust the location of nuget.exe set NUGET=C:\nuget\nuget.exe diff --git a/src/csharp/build_packages_dotnetcli.sh b/src/csharp/build_packages_dotnetcli.sh index fb4138a4b2b..cfdbaa2518b 100755 --- a/src/csharp/build_packages_dotnetcli.sh +++ b/src/csharp/build_packages_dotnetcli.sh @@ -45,8 +45,8 @@ dotnet pack --configuration Release Grpc.Auth --output ../../../artifacts dotnet pack --configuration Release Grpc.HealthCheck --output ../../../artifacts dotnet pack --configuration Release Grpc.Reflection --output ../../../artifacts -nuget pack Grpc.nuspec -Version "1.13.0-dev" -OutputDirectory ../../artifacts -nuget pack Grpc.Core.NativeDebug.nuspec -Version "1.13.0-dev" -OutputDirectory ../../artifacts -nuget pack Grpc.Tools.nuspec -Version "1.13.0-dev" -OutputDirectory ../../artifacts +nuget pack Grpc.nuspec -Version "1.13.0-pre1" -OutputDirectory ../../artifacts +nuget pack Grpc.Core.NativeDebug.nuspec -Version "1.13.0-pre1" -OutputDirectory ../../artifacts +nuget pack Grpc.Tools.nuspec -Version "1.13.0-pre1" -OutputDirectory ../../artifacts (cd ../../artifacts && zip csharp_nugets_dotnetcli.zip *.nupkg) diff --git a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec index 515dc917d1a..f6be759b0c6 100644 --- a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec +++ b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec @@ -42,7 +42,7 @@ Pod::Spec.new do |s| # exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed # before them. s.name = '!ProtoCompiler-gRPCPlugin' - v = '1.13.0-dev' + v = '1.13.0-pre1' s.version = v s.summary = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.' s.description = <<-DESC diff --git a/src/objective-c/GRPCClient/private/version.h b/src/objective-c/GRPCClient/private/version.h index 6fe4a7d051e..ef828518262 100644 --- a/src/objective-c/GRPCClient/private/version.h +++ b/src/objective-c/GRPCClient/private/version.h @@ -22,4 +22,4 @@ // instead. This file can be regenerated from the template by running // `tools/buildgen/generate_projects.sh`. -#define GRPC_OBJC_VERSION_STRING @"1.13.0-dev" +#define GRPC_OBJC_VERSION_STRING @"1.13.0-pre1" diff --git a/src/objective-c/tests/version.h b/src/objective-c/tests/version.h index e9637099d9f..4c8278dca16 100644 --- a/src/objective-c/tests/version.h +++ b/src/objective-c/tests/version.h @@ -22,5 +22,5 @@ // instead. This file can be regenerated from the template by running // `tools/buildgen/generate_projects.sh`. -#define GRPC_OBJC_VERSION_STRING @"1.13.0-dev" -#define GRPC_C_VERSION_STRING @"6.0.0-dev" +#define GRPC_OBJC_VERSION_STRING @"1.13.0-pre1" +#define GRPC_C_VERSION_STRING @"6.0.0-pre1" diff --git a/src/php/ext/grpc/version.h b/src/php/ext/grpc/version.h index 407d6347e6b..1672a9706b5 100644 --- a/src/php/ext/grpc/version.h +++ b/src/php/ext/grpc/version.h @@ -20,6 +20,6 @@ #ifndef VERSION_H #define VERSION_H -#define PHP_GRPC_VERSION "1.13.0dev" +#define PHP_GRPC_VERSION "1.13.0RC1" #endif /* VERSION_H */ diff --git a/src/python/grpcio/grpc/_grpcio_metadata.py b/src/python/grpcio/grpc/_grpcio_metadata.py index ad53f60ad36..3150f3e4bc0 100644 --- a/src/python/grpcio/grpc/_grpcio_metadata.py +++ b/src/python/grpcio/grpc/_grpcio_metadata.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc/_grpcio_metadata.py.template`!!! -__version__ = """1.13.0.dev0""" +__version__ = """1.13.0rc1""" diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py index 57dc26dbeb7..43a620f6e15 100644 --- a/src/python/grpcio/grpc_version.py +++ b/src/python/grpcio/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!! -VERSION = '1.13.0.dev0' +VERSION = '1.13.0rc1' diff --git a/src/python/grpcio_health_checking/grpc_version.py b/src/python/grpcio_health_checking/grpc_version.py index ba0d4a3b6de..c52d72a9778 100644 --- a/src/python/grpcio_health_checking/grpc_version.py +++ b/src/python/grpcio_health_checking/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!! -VERSION = '1.13.0.dev0' +VERSION = '1.13.0rc1' diff --git a/src/python/grpcio_reflection/grpc_version.py b/src/python/grpcio_reflection/grpc_version.py index ea2878d9ee4..657df1e6be3 100644 --- a/src/python/grpcio_reflection/grpc_version.py +++ b/src/python/grpcio_reflection/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!! -VERSION = '1.13.0.dev0' +VERSION = '1.13.0rc1' diff --git a/src/python/grpcio_testing/grpc_version.py b/src/python/grpcio_testing/grpc_version.py index 02f19f22830..345c3e6c8a9 100644 --- a/src/python/grpcio_testing/grpc_version.py +++ b/src/python/grpcio_testing/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_testing/grpc_version.py.template`!!! -VERSION = '1.13.0.dev0' +VERSION = '1.13.0rc1' diff --git a/src/python/grpcio_tests/grpc_version.py b/src/python/grpcio_tests/grpc_version.py index 9d2e41644e1..17e4b9d1da0 100644 --- a/src/python/grpcio_tests/grpc_version.py +++ b/src/python/grpcio_tests/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!! -VERSION = '1.13.0.dev0' +VERSION = '1.13.0rc1' diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb index 15f375100a2..b5f7960b0f2 100644 --- a/src/ruby/lib/grpc/version.rb +++ b/src/ruby/lib/grpc/version.rb @@ -14,5 +14,5 @@ # GRPC contains the General RPC module. module GRPC - VERSION = '1.13.0.dev' + VERSION = '1.13.0.pre1' end diff --git a/src/ruby/tools/version.rb b/src/ruby/tools/version.rb index 09d5c826747..20fdc0e36fc 100644 --- a/src/ruby/tools/version.rb +++ b/src/ruby/tools/version.rb @@ -14,6 +14,6 @@ module GRPC module Tools - VERSION = '1.13.0.dev' + VERSION = '1.13.0.pre1' end end diff --git a/tools/distrib/python/grpcio_tools/grpc_version.py b/tools/distrib/python/grpcio_tools/grpc_version.py index f0367e2af42..df98a4319a4 100644 --- a/tools/distrib/python/grpcio_tools/grpc_version.py +++ b/tools/distrib/python/grpcio_tools/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!! -VERSION = '1.13.0.dev0' +VERSION = '1.13.0rc1' diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++ index 09c62462afc..e96b8def2fa 100644 --- a/tools/doxygen/Doxyfile.c++ +++ b/tools/doxygen/Doxyfile.c++ @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.13.0-dev +PROJECT_NUMBER = 1.13.0-pre1 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index ea2f377c917..8a513f51fcd 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.13.0-dev +PROJECT_NUMBER = 1.13.0-pre1 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/tools/doxygen/Doxyfile.core b/tools/doxygen/Doxyfile.core index 592c94e51bf..e2d4e06ec7d 100644 --- a/tools/doxygen/Doxyfile.core +++ b/tools/doxygen/Doxyfile.core @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC Core" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 6.0.0-dev +PROJECT_NUMBER = 6.0.0-pre1 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 589e862b9a8..26ddd87c00f 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC Core" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 6.0.0-dev +PROJECT_NUMBER = 6.0.0-pre1 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a From c6664b04679d16350d0e2f4fc6ac4106f39936c7 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Fri, 8 Jun 2018 14:22:12 -0700 Subject: [PATCH 22/57] Revert "move recv_trailing_metadata into its own callback, don't use on_complete for recv_ops" --- .../filters/client_channel/client_channel.cc | 874 ++++++++++-------- .../ext/filters/deadline/deadline_filter.cc | 28 +- .../ext/filters/deadline/deadline_filter.h | 10 +- .../filters/http/client/http_client_filter.cc | 19 +- .../chttp2/transport/chttp2_transport.cc | 35 +- .../cronet/transport/cronet_transport.cc | 19 +- .../ext/transport/inproc/inproc_transport.cc | 52 +- src/core/lib/channel/connected_channel.cc | 9 +- src/core/lib/iomgr/call_combiner.h | 80 -- src/core/lib/iomgr/closure.h | 5 +- src/core/lib/surface/call.cc | 63 +- src/core/lib/transport/transport.cc | 29 +- src/core/lib/transport/transport.h | 22 +- src/core/lib/transport/transport_op_string.cc | 7 + test/cpp/microbenchmarks/bm_call_create.cc | 24 +- 15 files changed, 607 insertions(+), 669 deletions(-) diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc index 98391a13ef8..ea6775a8d85 100644 --- a/src/core/ext/filters/client_channel/client_channel.cc +++ b/src/core/ext/filters/client_channel/client_channel.cc @@ -817,7 +817,6 @@ typedef struct { // For intercepting recv_trailing_metadata. grpc_metadata_batch recv_trailing_metadata; grpc_transport_stream_stats collect_stats; - grpc_closure recv_trailing_metadata_ready; // For intercepting on_complete. grpc_closure on_complete; } subchannel_batch_data; @@ -1193,24 +1192,35 @@ static void pending_batches_fail(grpc_call_element* elem, grpc_error* error, "chand=%p calld=%p: failing %" PRIuPTR " pending batches: %s", elem->channel_data, calld, num_batches, grpc_error_string(error)); } - grpc_core::CallCombinerClosureList closures; + grpc_transport_stream_op_batch* + batches[GPR_ARRAY_SIZE(calld->pending_batches)]; + size_t num_batches = 0; for (size_t i = 0; i < GPR_ARRAY_SIZE(calld->pending_batches); ++i) { pending_batch* pending = &calld->pending_batches[i]; grpc_transport_stream_op_batch* batch = pending->batch; if (batch != nullptr) { - batch->handler_private.extra_arg = calld; - GRPC_CLOSURE_INIT(&batch->handler_private.closure, - fail_pending_batch_in_call_combiner, batch, - grpc_schedule_on_exec_ctx); - closures.Add(&batch->handler_private.closure, GRPC_ERROR_REF(error), - "pending_batches_fail"); + batches[num_batches++] = batch; pending_batch_clear(calld, pending); } } + for (size_t i = yield_call_combiner ? 1 : 0; i < num_batches; ++i) { + grpc_transport_stream_op_batch* batch = batches[i]; + batch->handler_private.extra_arg = calld; + GRPC_CLOSURE_INIT(&batch->handler_private.closure, + fail_pending_batch_in_call_combiner, batch, + grpc_schedule_on_exec_ctx); + GRPC_CALL_COMBINER_START(calld->call_combiner, + &batch->handler_private.closure, + GRPC_ERROR_REF(error), "pending_batches_fail"); + } if (yield_call_combiner) { - closures.RunClosures(calld->call_combiner); - } else { - closures.RunClosuresWithoutYielding(calld->call_combiner); + if (num_batches > 0) { + // Note: This will release the call combiner. + grpc_transport_stream_op_batch_finish_with_failure( + batches[0], GRPC_ERROR_REF(error), calld->call_combiner); + } else { + GRPC_CALL_COMBINER_STOP(calld->call_combiner, "pending_batches_fail"); + } } GRPC_ERROR_UNREF(error); } @@ -1245,22 +1255,30 @@ static void pending_batches_resume(grpc_call_element* elem) { " pending batches on subchannel_call=%p", chand, calld, num_batches, calld->subchannel_call); } - grpc_core::CallCombinerClosureList closures; + grpc_transport_stream_op_batch* + batches[GPR_ARRAY_SIZE(calld->pending_batches)]; + size_t num_batches = 0; for (size_t i = 0; i < GPR_ARRAY_SIZE(calld->pending_batches); ++i) { pending_batch* pending = &calld->pending_batches[i]; grpc_transport_stream_op_batch* batch = pending->batch; if (batch != nullptr) { - batch->handler_private.extra_arg = calld->subchannel_call; - GRPC_CLOSURE_INIT(&batch->handler_private.closure, - resume_pending_batch_in_call_combiner, batch, - grpc_schedule_on_exec_ctx); - closures.Add(&batch->handler_private.closure, GRPC_ERROR_NONE, - "pending_batches_resume"); + batches[num_batches++] = batch; pending_batch_clear(calld, pending); } } + for (size_t i = 1; i < num_batches; ++i) { + grpc_transport_stream_op_batch* batch = batches[i]; + batch->handler_private.extra_arg = calld->subchannel_call; + GRPC_CLOSURE_INIT(&batch->handler_private.closure, + resume_pending_batch_in_call_combiner, batch, + grpc_schedule_on_exec_ctx); + GRPC_CALL_COMBINER_START(calld->call_combiner, + &batch->handler_private.closure, GRPC_ERROR_NONE, + "pending_batches_resume"); + } + GPR_ASSERT(num_batches > 0); // Note: This will release the call combiner. - closures.RunClosures(calld->call_combiner); + grpc_subchannel_call_process_op(calld->subchannel_call, batches[0]); } static void maybe_clear_pending_batch(grpc_call_element* elem, @@ -1275,10 +1293,7 @@ static void maybe_clear_pending_batch(grpc_call_element* elem, batch->payload->recv_initial_metadata.recv_initial_metadata_ready == nullptr) && (!batch->recv_message || - batch->payload->recv_message.recv_message_ready == nullptr) && - (!batch->recv_trailing_metadata || - batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready == - nullptr)) { + batch->payload->recv_message.recv_message_ready == nullptr)) { if (grpc_client_channel_trace.enabled()) { gpr_log(GPR_INFO, "chand=%p calld=%p: clearing pending batch", chand, calld); @@ -1287,27 +1302,75 @@ static void maybe_clear_pending_batch(grpc_call_element* elem, } } -// Returns a pointer to the first pending batch for which predicate(batch) -// returns true, or null if not found. -template -static pending_batch* pending_batch_find(grpc_call_element* elem, - const char* log_message, - Predicate predicate) { - channel_data* chand = static_cast(elem->channel_data); - call_data* calld = static_cast(elem->call_data); - for (size_t i = 0; i < GPR_ARRAY_SIZE(calld->pending_batches); ++i) { - pending_batch* pending = &calld->pending_batches[i]; - grpc_transport_stream_op_batch* batch = pending->batch; - if (batch != nullptr && predicate(batch)) { - if (grpc_client_channel_trace.enabled()) { - gpr_log(GPR_INFO, - "chand=%p calld=%p: %s pending batch at index %" PRIuPTR, chand, - calld, log_message, i); - } - return pending; - } +// Returns true if all ops in the pending batch have been completed. +static bool pending_batch_is_completed( + pending_batch* pending, call_data* calld, + subchannel_call_retry_state* retry_state) { + if (pending->batch == nullptr || pending->batch->on_complete == nullptr) { + return false; + } + if (pending->batch->send_initial_metadata && + !retry_state->completed_send_initial_metadata) { + return false; + } + if (pending->batch->send_message && + retry_state->completed_send_message_count < + calld->send_messages->size()) { + return false; + } + if (pending->batch->send_trailing_metadata && + !retry_state->completed_send_trailing_metadata) { + return false; + } + if (pending->batch->recv_initial_metadata && + !retry_state->completed_recv_initial_metadata) { + return false; + } + if (pending->batch->recv_message && + retry_state->completed_recv_message_count < + retry_state->started_recv_message_count) { + return false; + } + if (pending->batch->recv_trailing_metadata && + !retry_state->completed_recv_trailing_metadata) { + return false; } - return nullptr; + return true; +} + +// Returns true if any op in the batch was not yet started. +static bool pending_batch_is_unstarted( + pending_batch* pending, call_data* calld, + subchannel_call_retry_state* retry_state) { + if (pending->batch == nullptr || pending->batch->on_complete == nullptr) { + return false; + } + if (pending->batch->send_initial_metadata && + !retry_state->started_send_initial_metadata) { + return true; + } + if (pending->batch->send_message && + retry_state->started_send_message_count < calld->send_messages->size()) { + return true; + } + if (pending->batch->send_trailing_metadata && + !retry_state->started_send_trailing_metadata) { + return true; + } + if (pending->batch->recv_initial_metadata && + !retry_state->started_recv_initial_metadata) { + return true; + } + if (pending->batch->recv_message && + retry_state->completed_recv_message_count == + retry_state->started_recv_message_count) { + return true; + } + if (pending->batch->recv_trailing_metadata && + !retry_state->started_recv_trailing_metadata) { + return true; + } + return false; } // @@ -1494,13 +1557,8 @@ static bool maybe_retry(grpc_call_element* elem, // subchannel_batch_data // -// Creates a subchannel_batch_data object on the call's arena with the -// specified refcount. If set_on_complete is true, the batch's -// on_complete callback will be set to point to on_complete(); -// otherwise, the batch's on_complete callback will be null. static subchannel_batch_data* batch_data_create(grpc_call_element* elem, - int refcount, - bool set_on_complete) { + int refcount) { call_data* calld = static_cast(elem->call_data); subchannel_call_retry_state* retry_state = static_cast( @@ -1513,11 +1571,9 @@ static subchannel_batch_data* batch_data_create(grpc_call_element* elem, GRPC_SUBCHANNEL_CALL_REF(calld->subchannel_call, "batch_data_create"); batch_data->batch.payload = &retry_state->batch_payload; gpr_ref_init(&batch_data->refs, refcount); - if (set_on_complete) { - GRPC_CLOSURE_INIT(&batch_data->on_complete, on_complete, batch_data, - grpc_schedule_on_exec_ctx); - batch_data->batch.on_complete = &batch_data->on_complete; - } + GRPC_CLOSURE_INIT(&batch_data->on_complete, on_complete, batch_data, + grpc_schedule_on_exec_ctx); + batch_data->batch.on_complete = &batch_data->on_complete; GRPC_CALL_STACK_REF(calld->owning_call, "batch_data"); return batch_data; } @@ -1550,14 +1606,26 @@ static void batch_data_unref(subchannel_batch_data* batch_data) { static void invoke_recv_initial_metadata_callback(void* arg, grpc_error* error) { subchannel_batch_data* batch_data = static_cast(arg); + channel_data* chand = + static_cast(batch_data->elem->channel_data); + call_data* calld = static_cast(batch_data->elem->call_data); // Find pending batch. - pending_batch* pending = pending_batch_find( - batch_data->elem, "invoking recv_initial_metadata_ready for", - [](grpc_transport_stream_op_batch* batch) { - return batch->recv_initial_metadata && - batch->payload->recv_initial_metadata - .recv_initial_metadata_ready != nullptr; - }); + pending_batch* pending = nullptr; + for (size_t i = 0; i < GPR_ARRAY_SIZE(calld->pending_batches); ++i) { + grpc_transport_stream_op_batch* batch = calld->pending_batches[i].batch; + if (batch != nullptr && batch->recv_initial_metadata && + batch->payload->recv_initial_metadata.recv_initial_metadata_ready != + nullptr) { + if (grpc_client_channel_trace.enabled()) { + gpr_log(GPR_INFO, + "chand=%p calld=%p: invoking recv_initial_metadata_ready for " + "pending batch at index %" PRIuPTR, + chand, calld, i); + } + pending = &calld->pending_batches[i]; + break; + } + } GPR_ASSERT(pending != nullptr); // Return metadata. grpc_metadata_batch_move( @@ -1593,19 +1661,10 @@ static void recv_initial_metadata_ready(void* arg, grpc_error* error) { static_cast( grpc_connected_subchannel_call_get_parent_data( batch_data->subchannel_call)); - retry_state->completed_recv_initial_metadata = true; - // If a retry was already dispatched, then we're not going to use the - // result of this recv_initial_metadata op, so do nothing. - if (retry_state->retry_dispatched) { - GRPC_CALL_COMBINER_STOP( - calld->call_combiner, - "recv_initial_metadata_ready after retry dispatched"); - return; - } // If we got an error or a Trailers-Only response and have not yet gotten - // the recv_trailing_metadata_ready callback, then defer propagating this - // callback back to the surface. We can evaluate whether to retry when - // recv_trailing_metadata comes back. + // the recv_trailing_metadata on_complete callback, then defer + // propagating this callback back to the surface. We can evaluate whether + // to retry when recv_trailing_metadata comes back. if (GPR_UNLIKELY((batch_data->trailing_metadata_available || error != GRPC_ERROR_NONE) && !retry_state->completed_recv_trailing_metadata)) { @@ -1630,9 +1689,9 @@ static void recv_initial_metadata_ready(void* arg, grpc_error* error) { } // Received valid initial metadata, so commit the call. retry_commit(elem, retry_state); - // Invoke the callback to return the result to the surface. // Manually invoking a callback function; it does not take ownership of error. invoke_recv_initial_metadata_callback(batch_data, error); + GRPC_ERROR_UNREF(error); } // @@ -1642,13 +1701,25 @@ static void recv_initial_metadata_ready(void* arg, grpc_error* error) { // Invokes recv_message_ready for a subchannel batch. static void invoke_recv_message_callback(void* arg, grpc_error* error) { subchannel_batch_data* batch_data = static_cast(arg); + channel_data* chand = + static_cast(batch_data->elem->channel_data); + call_data* calld = static_cast(batch_data->elem->call_data); // Find pending op. - pending_batch* pending = pending_batch_find( - batch_data->elem, "invoking recv_message_ready for", - [](grpc_transport_stream_op_batch* batch) { - return batch->recv_message && - batch->payload->recv_message.recv_message_ready != nullptr; - }); + pending_batch* pending = nullptr; + for (size_t i = 0; i < GPR_ARRAY_SIZE(calld->pending_batches); ++i) { + grpc_transport_stream_op_batch* batch = calld->pending_batches[i].batch; + if (batch != nullptr && batch->recv_message && + batch->payload->recv_message.recv_message_ready != nullptr) { + if (grpc_client_channel_trace.enabled()) { + gpr_log(GPR_INFO, + "chand=%p calld=%p: invoking recv_message_ready for " + "pending batch at index %" PRIuPTR, + chand, calld, i); + } + pending = &calld->pending_batches[i]; + break; + } + } GPR_ASSERT(pending != nullptr); // Return payload. *pending->batch->payload->recv_message.recv_message = @@ -1680,18 +1751,10 @@ static void recv_message_ready(void* arg, grpc_error* error) { static_cast( grpc_connected_subchannel_call_get_parent_data( batch_data->subchannel_call)); - ++retry_state->completed_recv_message_count; - // If a retry was already dispatched, then we're not going to use the - // result of this recv_message op, so do nothing. - if (retry_state->retry_dispatched) { - GRPC_CALL_COMBINER_STOP(calld->call_combiner, - "recv_message_ready after retry dispatched"); - return; - } // If we got an error or the payload was nullptr and we have not yet gotten - // the recv_trailing_metadata_ready callback, then defer propagating this - // callback back to the surface. We can evaluate whether to retry when - // recv_trailing_metadata comes back. + // the recv_trailing_metadata on_complete callback, then defer + // propagating this callback back to the surface. We can evaluate whether + // to retry when recv_trailing_metadata comes back. if (GPR_UNLIKELY( (batch_data->recv_message == nullptr || error != GRPC_ERROR_NONE) && !retry_state->completed_recv_trailing_metadata)) { @@ -1714,241 +1777,133 @@ static void recv_message_ready(void* arg, grpc_error* error) { } // Received a valid message, so commit the call. retry_commit(elem, retry_state); - // Invoke the callback to return the result to the surface. // Manually invoking a callback function; it does not take ownership of error. invoke_recv_message_callback(batch_data, error); + GRPC_ERROR_UNREF(error); } // -// recv_trailing_metadata handling +// list of closures to execute in call combiner // -// Adds recv_trailing_metadata_ready closure to closures. -static void add_closure_for_recv_trailing_metadata_ready( - grpc_call_element* elem, subchannel_batch_data* batch_data, - grpc_error* error, grpc_core::CallCombinerClosureList* closures) { - // Find pending batch. - pending_batch* pending = pending_batch_find( - elem, "invoking recv_trailing_metadata for", - [](grpc_transport_stream_op_batch* batch) { - return batch->recv_trailing_metadata && - batch->payload->recv_trailing_metadata - .recv_trailing_metadata_ready != nullptr; - }); - // If we generated the recv_trailing_metadata op internally via - // start_internal_recv_trailing_metadata(), then there will be no - // pending batch. - if (pending == nullptr) { - GRPC_ERROR_UNREF(error); - return; +// Represents a closure that needs to run in the call combiner as part of +// starting or completing a batch. +typedef struct { + grpc_closure* closure; + grpc_error* error; + const char* reason; + bool free_reason = false; +} closure_to_execute; + +static void execute_closures_in_call_combiner(grpc_call_element* elem, + const char* caller, + closure_to_execute* closures, + size_t num_closures) { + channel_data* chand = static_cast(elem->channel_data); + call_data* calld = static_cast(elem->call_data); + // Note that the call combiner will be yielded for each closure that + // we schedule. We're already running in the call combiner, so one of + // the closures can be scheduled directly, but the others will + // have to re-enter the call combiner. + if (num_closures > 0) { + if (grpc_client_channel_trace.enabled()) { + gpr_log(GPR_INFO, "chand=%p calld=%p: %s starting closure: %s", chand, + calld, caller, closures[0].reason); + } + GRPC_CLOSURE_SCHED(closures[0].closure, closures[0].error); + if (closures[0].free_reason) { + gpr_free(const_cast(closures[0].reason)); + } + for (size_t i = 1; i < num_closures; ++i) { + if (grpc_client_channel_trace.enabled()) { + gpr_log(GPR_INFO, + "chand=%p calld=%p: %s starting closure in call combiner: %s", + chand, calld, caller, closures[i].reason); + } + GRPC_CALL_COMBINER_START(calld->call_combiner, closures[i].closure, + closures[i].error, closures[i].reason); + if (closures[i].free_reason) { + gpr_free(const_cast(closures[i].reason)); + } + } + } else { + if (grpc_client_channel_trace.enabled()) { + gpr_log(GPR_INFO, "chand=%p calld=%p: no closures to run for %s", chand, + calld, caller); + } + GRPC_CALL_COMBINER_STOP(calld->call_combiner, "no closures to run"); + } +} + +// +// on_complete callback handling +// + +// Updates retry_state to reflect the ops completed in batch_data. +static void update_retry_state_for_completed_batch( + subchannel_batch_data* batch_data, + subchannel_call_retry_state* retry_state) { + if (batch_data->batch.send_initial_metadata) { + retry_state->completed_send_initial_metadata = true; + } + if (batch_data->batch.send_message) { + ++retry_state->completed_send_message_count; + } + if (batch_data->batch.send_trailing_metadata) { + retry_state->completed_send_trailing_metadata = true; + } + if (batch_data->batch.recv_initial_metadata) { + retry_state->completed_recv_initial_metadata = true; + } + if (batch_data->batch.recv_message) { + ++retry_state->completed_recv_message_count; + } + if (batch_data->batch.recv_trailing_metadata) { + retry_state->completed_recv_trailing_metadata = true; } - // Return metadata. - grpc_metadata_batch_move( - &batch_data->recv_trailing_metadata, - pending->batch->payload->recv_trailing_metadata.recv_trailing_metadata); - // Add closure. - closures->Add(pending->batch->payload->recv_trailing_metadata - .recv_trailing_metadata_ready, - error, "recv_trailing_metadata_ready for pending batch"); - // Update bookkeeping. - pending->batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready = - nullptr; - maybe_clear_pending_batch(elem, pending); } // Adds any necessary closures for deferred recv_initial_metadata and -// recv_message callbacks to closures. +// recv_message callbacks to closures, updating *num_closures as needed. static void add_closures_for_deferred_recv_callbacks( subchannel_batch_data* batch_data, subchannel_call_retry_state* retry_state, - grpc_core::CallCombinerClosureList* closures) { + closure_to_execute* closures, size_t* num_closures) { if (batch_data->batch.recv_trailing_metadata) { // Add closure for deferred recv_initial_metadata_ready. if (GPR_UNLIKELY(retry_state->recv_initial_metadata_ready_deferred_batch != nullptr)) { - GRPC_CLOSURE_INIT(&batch_data->recv_initial_metadata_ready, - invoke_recv_initial_metadata_callback, - retry_state->recv_initial_metadata_ready_deferred_batch, - grpc_schedule_on_exec_ctx); - closures->Add(&batch_data->recv_initial_metadata_ready, - retry_state->recv_initial_metadata_error, - "resuming recv_initial_metadata_ready"); + closure_to_execute* closure = &closures[(*num_closures)++]; + closure->closure = GRPC_CLOSURE_INIT( + &batch_data->recv_initial_metadata_ready, + invoke_recv_initial_metadata_callback, + retry_state->recv_initial_metadata_ready_deferred_batch, + grpc_schedule_on_exec_ctx); + closure->error = retry_state->recv_initial_metadata_error; + closure->reason = "resuming recv_initial_metadata_ready"; retry_state->recv_initial_metadata_ready_deferred_batch = nullptr; } // Add closure for deferred recv_message_ready. if (GPR_UNLIKELY(retry_state->recv_message_ready_deferred_batch != nullptr)) { - GRPC_CLOSURE_INIT(&batch_data->recv_message_ready, - invoke_recv_message_callback, - retry_state->recv_message_ready_deferred_batch, - grpc_schedule_on_exec_ctx); - closures->Add(&batch_data->recv_message_ready, - retry_state->recv_message_error, - "resuming recv_message_ready"); + closure_to_execute* closure = &closures[(*num_closures)++]; + closure->closure = GRPC_CLOSURE_INIT( + &batch_data->recv_message_ready, invoke_recv_message_callback, + retry_state->recv_message_ready_deferred_batch, + grpc_schedule_on_exec_ctx); + closure->error = retry_state->recv_message_error; + closure->reason = "resuming recv_message_ready"; retry_state->recv_message_ready_deferred_batch = nullptr; } } } -// Returns true if any op in the batch was not yet started. -// Only looks at send ops, since recv ops are always started immediately. -static bool pending_batch_is_unstarted( - pending_batch* pending, call_data* calld, - subchannel_call_retry_state* retry_state) { - if (pending->batch == nullptr || pending->batch->on_complete == nullptr) { - return false; - } - if (pending->batch->send_initial_metadata && - !retry_state->started_send_initial_metadata) { - return true; - } - if (pending->batch->send_message && - retry_state->started_send_message_count < calld->send_messages->size()) { - return true; - } - if (pending->batch->send_trailing_metadata && - !retry_state->started_send_trailing_metadata) { - return true; - } - return false; -} - -// For any pending batch containing an op that has not yet been started, -// adds the pending batch's completion closures to closures. -static void add_closures_to_fail_unstarted_pending_batches( - grpc_call_element* elem, subchannel_call_retry_state* retry_state, - grpc_error* error, grpc_core::CallCombinerClosureList* closures) { - channel_data* chand = static_cast(elem->channel_data); - call_data* calld = static_cast(elem->call_data); - for (size_t i = 0; i < GPR_ARRAY_SIZE(calld->pending_batches); ++i) { - pending_batch* pending = &calld->pending_batches[i]; - if (pending_batch_is_unstarted(pending, calld, retry_state)) { - if (grpc_client_channel_trace.enabled()) { - gpr_log(GPR_INFO, - "chand=%p calld=%p: failing unstarted pending batch at index " - "%" PRIuPTR, - chand, calld, i); - } - closures->Add(pending->batch->on_complete, GRPC_ERROR_REF(error), - "failing on_complete for pending batch"); - pending->batch->on_complete = nullptr; - maybe_clear_pending_batch(elem, pending); - } - } - GRPC_ERROR_UNREF(error); -} - -// Intercepts recv_trailing_metadata_ready callback for retries. -// Commits the call and returns the trailing metadata up the stack. -static void recv_trailing_metadata_ready(void* arg, grpc_error* error) { - subchannel_batch_data* batch_data = static_cast(arg); - grpc_call_element* elem = batch_data->elem; - channel_data* chand = static_cast(elem->channel_data); - call_data* calld = static_cast(elem->call_data); - if (grpc_client_channel_trace.enabled()) { - gpr_log(GPR_INFO, - "chand=%p calld=%p: got recv_trailing_metadata_ready, error=%s", - chand, calld, grpc_error_string(error)); - } - subchannel_call_retry_state* retry_state = - static_cast( - grpc_connected_subchannel_call_get_parent_data( - batch_data->subchannel_call)); - retry_state->completed_recv_trailing_metadata = true; - // Get the call's status and check for server pushback metadata. - grpc_status_code status = GRPC_STATUS_OK; - grpc_mdelem* server_pushback_md = nullptr; - if (error != GRPC_ERROR_NONE) { - grpc_error_get_status(error, calld->deadline, &status, nullptr, nullptr, - nullptr); - } else { - grpc_metadata_batch* md_batch = - batch_data->batch.payload->recv_trailing_metadata - .recv_trailing_metadata; - GPR_ASSERT(md_batch->idx.named.grpc_status != nullptr); - status = - grpc_get_status_code_from_metadata(md_batch->idx.named.grpc_status->md); - if (md_batch->idx.named.grpc_retry_pushback_ms != nullptr) { - server_pushback_md = &md_batch->idx.named.grpc_retry_pushback_ms->md; - } - } - if (grpc_client_channel_trace.enabled()) { - gpr_log(GPR_INFO, "chand=%p calld=%p: call finished, status=%s", chand, - calld, grpc_status_code_to_string(status)); - } - // Check if we should retry. - if (maybe_retry(elem, batch_data, status, server_pushback_md)) { - // Unref batch_data for deferred recv_initial_metadata_ready or - // recv_message_ready callbacks, if any. - if (retry_state->recv_initial_metadata_ready_deferred_batch != nullptr) { - batch_data_unref(batch_data); - GRPC_ERROR_UNREF(retry_state->recv_initial_metadata_error); - } - if (retry_state->recv_message_ready_deferred_batch != nullptr) { - batch_data_unref(batch_data); - GRPC_ERROR_UNREF(retry_state->recv_message_error); - } - batch_data_unref(batch_data); - return; - } - // Not retrying, so commit the call. - retry_commit(elem, retry_state); - // Construct list of closures to execute. - grpc_core::CallCombinerClosureList closures; - // First, add closure for recv_trailing_metadata_ready. - add_closure_for_recv_trailing_metadata_ready( - elem, batch_data, GRPC_ERROR_REF(error), &closures); - // If there are deferred recv_initial_metadata_ready or recv_message_ready - // callbacks, add them to closures. - add_closures_for_deferred_recv_callbacks(batch_data, retry_state, &closures); - // Add closures to fail any pending batches that have not yet been started. - add_closures_to_fail_unstarted_pending_batches( - elem, retry_state, GRPC_ERROR_REF(error), &closures); - // Don't need batch_data anymore. - batch_data_unref(batch_data); - // Schedule all of the closures identified above. - // Note: This will release the call combiner. - closures.RunClosures(calld->call_combiner); -} - -// -// on_complete callback handling -// - -// For any pending batch completed in batch_data, adds the necessary -// completion closures to closures. -static void add_closure_for_completed_pending_batch( - grpc_call_element* elem, subchannel_batch_data* batch_data, - subchannel_call_retry_state* retry_state, grpc_error* error, - grpc_core::CallCombinerClosureList* closures) { - pending_batch* pending = pending_batch_find( - elem, "completed", [batch_data](grpc_transport_stream_op_batch* batch) { - return batch->on_complete != nullptr && - batch_data->batch.send_initial_metadata == - batch->send_initial_metadata && - batch_data->batch.send_message == batch->send_message && - batch_data->batch.send_trailing_metadata == - batch->send_trailing_metadata; - }); - // If batch_data is a replay batch, then there will be no pending - // batch to complete. - if (pending == nullptr) { - GRPC_ERROR_UNREF(error); - return; - } - // Add closure. - closures->Add(pending->batch->on_complete, error, - "on_complete for pending batch"); - pending->batch->on_complete = nullptr; - maybe_clear_pending_batch(elem, pending); -} - // If there are any cached ops to replay or pending ops to start on the // subchannel call, adds a closure to closures to invoke -// start_retriable_subchannel_batches(). +// start_retriable_subchannel_batches(), updating *num_closures as needed. static void add_closures_for_replay_or_pending_send_ops( grpc_call_element* elem, subchannel_batch_data* batch_data, - subchannel_call_retry_state* retry_state, - grpc_core::CallCombinerClosureList* closures) { + subchannel_call_retry_state* retry_state, closure_to_execute* closures, + size_t* num_closures) { channel_data* chand = static_cast(elem->channel_data); call_data* calld = static_cast(elem->call_data); bool have_pending_send_message_ops = @@ -1974,12 +1929,93 @@ static void add_closures_for_replay_or_pending_send_ops( "chand=%p calld=%p: starting next batch for pending send op(s)", chand, calld); } - GRPC_CLOSURE_INIT(&batch_data->batch.handler_private.closure, - start_retriable_subchannel_batches, elem, - grpc_schedule_on_exec_ctx); - closures->Add(&batch_data->batch.handler_private.closure, GRPC_ERROR_NONE, - "starting next batch for send_* op(s)"); + closure_to_execute* closure = &closures[(*num_closures)++]; + closure->closure = GRPC_CLOSURE_INIT( + &batch_data->batch.handler_private.closure, + start_retriable_subchannel_batches, elem, grpc_schedule_on_exec_ctx); + closure->error = GRPC_ERROR_NONE; + closure->reason = "starting next batch for send_* op(s)"; + } +} + +// For any pending batch completed in batch_data, adds the necessary +// completion closures to closures, updating *num_closures as needed. +static void add_closures_for_completed_pending_batches( + grpc_call_element* elem, subchannel_batch_data* batch_data, + subchannel_call_retry_state* retry_state, grpc_error* error, + closure_to_execute* closures, size_t* num_closures) { + channel_data* chand = static_cast(elem->channel_data); + call_data* calld = static_cast(elem->call_data); + for (size_t i = 0; i < GPR_ARRAY_SIZE(calld->pending_batches); ++i) { + pending_batch* pending = &calld->pending_batches[i]; + if (pending_batch_is_completed(pending, calld, retry_state)) { + if (grpc_client_channel_trace.enabled()) { + gpr_log(GPR_INFO, + "chand=%p calld=%p: pending batch completed at index %" PRIuPTR, + chand, calld, i); + } + // Copy the trailing metadata to return it to the surface. + if (batch_data->batch.recv_trailing_metadata) { + grpc_metadata_batch_move(&batch_data->recv_trailing_metadata, + pending->batch->payload->recv_trailing_metadata + .recv_trailing_metadata); + } + closure_to_execute* closure = &closures[(*num_closures)++]; + closure->closure = pending->batch->on_complete; + closure->error = GRPC_ERROR_REF(error); + closure->reason = "on_complete for pending batch"; + pending->batch->on_complete = nullptr; + maybe_clear_pending_batch(elem, pending); + } } + GRPC_ERROR_UNREF(error); +} + +// For any pending batch containing an op that has not yet been started, +// adds the pending batch's completion closures to closures, updating +// *num_closures as needed. +static void add_closures_to_fail_unstarted_pending_batches( + grpc_call_element* elem, subchannel_call_retry_state* retry_state, + grpc_error* error, closure_to_execute* closures, size_t* num_closures) { + channel_data* chand = static_cast(elem->channel_data); + call_data* calld = static_cast(elem->call_data); + for (size_t i = 0; i < GPR_ARRAY_SIZE(calld->pending_batches); ++i) { + pending_batch* pending = &calld->pending_batches[i]; + if (pending_batch_is_unstarted(pending, calld, retry_state)) { + if (grpc_client_channel_trace.enabled()) { + gpr_log(GPR_INFO, + "chand=%p calld=%p: failing unstarted pending batch at index " + "%" PRIuPTR, + chand, calld, i); + } + if (pending->batch->recv_initial_metadata) { + closure_to_execute* closure = &closures[(*num_closures)++]; + closure->closure = pending->batch->payload->recv_initial_metadata + .recv_initial_metadata_ready; + closure->error = GRPC_ERROR_REF(error); + closure->reason = + "failing recv_initial_metadata_ready for pending batch"; + pending->batch->payload->recv_initial_metadata + .recv_initial_metadata_ready = nullptr; + } + if (pending->batch->recv_message) { + *pending->batch->payload->recv_message.recv_message = nullptr; + closure_to_execute* closure = &closures[(*num_closures)++]; + closure->closure = + pending->batch->payload->recv_message.recv_message_ready; + closure->error = GRPC_ERROR_REF(error); + closure->reason = "failing recv_message_ready for pending batch"; + pending->batch->payload->recv_message.recv_message_ready = nullptr; + } + closure_to_execute* closure = &closures[(*num_closures)++]; + closure->closure = pending->batch->on_complete; + closure->error = GRPC_ERROR_REF(error); + closure->reason = "failing on_complete for pending batch"; + pending->batch->on_complete = nullptr; + maybe_clear_pending_batch(elem, pending); + } + } + GRPC_ERROR_UNREF(error); } // Callback used to intercept on_complete from subchannel calls. @@ -1999,48 +2035,135 @@ static void on_complete(void* arg, grpc_error* error) { static_cast( grpc_connected_subchannel_call_get_parent_data( batch_data->subchannel_call)); + // If we have previously completed recv_trailing_metadata, then the + // call is finished. + bool call_finished = retry_state->completed_recv_trailing_metadata; + // Record whether we were already committed before receiving this callback. + const bool previously_committed = calld->retry_committed; // Update bookkeeping in retry_state. - if (batch_data->batch.send_initial_metadata) { - retry_state->completed_send_initial_metadata = true; - } - if (batch_data->batch.send_message) { - ++retry_state->completed_send_message_count; - } - if (batch_data->batch.send_trailing_metadata) { - retry_state->completed_send_trailing_metadata = true; + update_retry_state_for_completed_batch(batch_data, retry_state); + if (call_finished) { + if (grpc_client_channel_trace.enabled()) { + gpr_log(GPR_INFO, "chand=%p calld=%p: call already finished", chand, + calld); + } + } else { + // Check if this batch finished the call, and if so, get its status. + // The call is finished if either (a) this callback was invoked with + // an error or (b) we receive status. + grpc_status_code status = GRPC_STATUS_OK; + grpc_mdelem* server_pushback_md = nullptr; + if (GPR_UNLIKELY(error != GRPC_ERROR_NONE)) { // Case (a). + call_finished = true; + grpc_error_get_status(error, calld->deadline, &status, nullptr, nullptr, + nullptr); + } else if (batch_data->batch.recv_trailing_metadata) { // Case (b). + call_finished = true; + grpc_metadata_batch* md_batch = + batch_data->batch.payload->recv_trailing_metadata + .recv_trailing_metadata; + GPR_ASSERT(md_batch->idx.named.grpc_status != nullptr); + status = grpc_get_status_code_from_metadata( + md_batch->idx.named.grpc_status->md); + if (md_batch->idx.named.grpc_retry_pushback_ms != nullptr) { + server_pushback_md = &md_batch->idx.named.grpc_retry_pushback_ms->md; + } + } + // If the call just finished, check if we should retry. + if (call_finished) { + if (grpc_client_channel_trace.enabled()) { + gpr_log(GPR_INFO, "chand=%p calld=%p: call finished, status=%s", chand, + calld, grpc_status_code_to_string(status)); + } + if (maybe_retry(elem, batch_data, status, server_pushback_md)) { + // Unref batch_data for deferred recv_initial_metadata_ready or + // recv_message_ready callbacks, if any. + if (batch_data->batch.recv_trailing_metadata && + retry_state->recv_initial_metadata_ready_deferred_batch != + nullptr) { + batch_data_unref(batch_data); + GRPC_ERROR_UNREF(retry_state->recv_initial_metadata_error); + } + if (batch_data->batch.recv_trailing_metadata && + retry_state->recv_message_ready_deferred_batch != nullptr) { + batch_data_unref(batch_data); + GRPC_ERROR_UNREF(retry_state->recv_message_error); + } + // Track number of pending subchannel send batches and determine if + // this was the last one. + bool last_callback_complete = false; + if (batch_data->batch.send_initial_metadata || + batch_data->batch.send_message || + batch_data->batch.send_trailing_metadata) { + --calld->num_pending_retriable_subchannel_send_batches; + last_callback_complete = + calld->num_pending_retriable_subchannel_send_batches == 0; + } + batch_data_unref(batch_data); + // If we just completed the last subchannel send batch, unref the + // call stack. + if (last_callback_complete) { + GRPC_CALL_STACK_UNREF(calld->owning_call, "subchannel_send_batches"); + } + return; + } + // Not retrying, so commit the call. + retry_commit(elem, retry_state); + } } - // If the call is committed, free cached data for send ops that we've just - // completed. - if (calld->retry_committed) { + // If we were already committed before receiving this callback, free + // cached data for send ops that we've just completed. (If the call has + // just now finished, the call to retry_commit() above will have freed all + // cached send ops, so we don't need to do it here.) + if (previously_committed) { free_cached_send_op_data_for_completed_batch(elem, batch_data, retry_state); } + // Call not being retried. // Construct list of closures to execute. - grpc_core::CallCombinerClosureList closures; - // If a retry was already dispatched, that means we saw - // recv_trailing_metadata before this, so we do nothing here. - // Otherwise, invoke the callback to return the result to the surface. - if (!retry_state->retry_dispatched) { - // Add closure for the completed pending batch, if any. - add_closure_for_completed_pending_batch(elem, batch_data, retry_state, - GRPC_ERROR_REF(error), &closures); - // If needed, add a callback to start_retriable_subchannel_batches() to - // start any replay or pending send ops on the subchannel call. - if (!retry_state->completed_recv_trailing_metadata) { - add_closures_for_replay_or_pending_send_ops(elem, batch_data, retry_state, - &closures); - } + // Max number of closures is number of pending batches plus one for + // each of: + // - recv_initial_metadata_ready (either deferred or unstarted) + // - recv_message_ready (either deferred or unstarted) + // - starting a new batch for pending send ops + closure_to_execute closures[GPR_ARRAY_SIZE(calld->pending_batches) + 3]; + size_t num_closures = 0; + // If there are deferred recv_initial_metadata_ready or recv_message_ready + // callbacks, add them to closures. + add_closures_for_deferred_recv_callbacks(batch_data, retry_state, closures, + &num_closures); + // Find pending batches whose ops are now complete and add their + // on_complete callbacks to closures. + add_closures_for_completed_pending_batches(elem, batch_data, retry_state, + GRPC_ERROR_REF(error), closures, + &num_closures); + // Add closures to handle any pending batches that have not yet been started. + // If the call is finished, we fail these batches; otherwise, we add a + // callback to start_retriable_subchannel_batches() to start them on + // the subchannel call. + if (call_finished) { + add_closures_to_fail_unstarted_pending_batches( + elem, retry_state, GRPC_ERROR_REF(error), closures, &num_closures); + } else { + add_closures_for_replay_or_pending_send_ops(elem, batch_data, retry_state, + closures, &num_closures); } // Track number of pending subchannel send batches and determine if this // was the last one. - --calld->num_pending_retriable_subchannel_send_batches; - const bool last_callback_complete = - calld->num_pending_retriable_subchannel_send_batches == 0; + bool last_callback_complete = false; + if (batch_data->batch.send_initial_metadata || + batch_data->batch.send_message || + batch_data->batch.send_trailing_metadata) { + --calld->num_pending_retriable_subchannel_send_batches; + last_callback_complete = + calld->num_pending_retriable_subchannel_send_batches == 0; + } // Don't need batch_data anymore. batch_data_unref(batch_data); // Schedule all of the closures identified above. // Note: This yeilds the call combiner. - closures.RunClosures(calld->call_combiner); - // If this was the last subchannel send batch, unref the call stack. + execute_closures_in_call_combiner(elem, "on_complete", closures, + num_closures); + // If we just completed the last subchannel send batch, unref the call stack. if (last_callback_complete) { GRPC_CALL_STACK_UNREF(calld->owning_call, "subchannel_send_batches"); } @@ -2062,22 +2185,27 @@ static void start_batch_in_call_combiner(void* arg, grpc_error* ignored) { // Adds a closure to closures that will execute batch in the call combiner. static void add_closure_for_subchannel_batch( - grpc_call_element* elem, grpc_transport_stream_op_batch* batch, - grpc_core::CallCombinerClosureList* closures) { - channel_data* chand = static_cast(elem->channel_data); - call_data* calld = static_cast(elem->call_data); + call_data* calld, grpc_transport_stream_op_batch* batch, + closure_to_execute* closures, size_t* num_closures) { batch->handler_private.extra_arg = calld->subchannel_call; GRPC_CLOSURE_INIT(&batch->handler_private.closure, start_batch_in_call_combiner, batch, grpc_schedule_on_exec_ctx); + closure_to_execute* closure = &closures[(*num_closures)++]; + closure->closure = &batch->handler_private.closure; + closure->error = GRPC_ERROR_NONE; + // If the tracer is enabled, we log a more detailed message, which + // requires dynamic allocation. This will be freed in + // start_retriable_subchannel_batches(). if (grpc_client_channel_trace.enabled()) { char* batch_str = grpc_transport_stream_op_batch_string(batch); - gpr_log(GPR_INFO, "chand=%p calld=%p: starting subchannel batch: %s", chand, - calld, batch_str); + gpr_asprintf(const_cast(&closure->reason), + "starting batch in call combiner: %s", batch_str); gpr_free(batch_str); + closure->free_reason = true; + } else { + closure->reason = "start_subchannel_batch"; } - closures->Add(&batch->handler_private.closure, GRPC_ERROR_NONE, - "start_subchannel_batch"); } // Adds retriable send_initial_metadata op to batch_data. @@ -2213,13 +2341,9 @@ static void add_retriable_recv_trailing_metadata_op( grpc_metadata_batch_init(&batch_data->recv_trailing_metadata); batch_data->batch.payload->recv_trailing_metadata.recv_trailing_metadata = &batch_data->recv_trailing_metadata; - batch_data->batch.payload->recv_trailing_metadata.collect_stats = + batch_data->batch.collect_stats = true; + batch_data->batch.payload->collect_stats.collect_stats = &batch_data->collect_stats; - GRPC_CLOSURE_INIT(&batch_data->recv_trailing_metadata_ready, - recv_trailing_metadata_ready, batch_data, - grpc_schedule_on_exec_ctx); - batch_data->batch.payload->recv_trailing_metadata - .recv_trailing_metadata_ready = &batch_data->recv_trailing_metadata_ready; } // Helper function used to start a recv_trailing_metadata batch. This @@ -2240,11 +2364,9 @@ static void start_internal_recv_trailing_metadata(grpc_call_element* elem) { grpc_connected_subchannel_call_get_parent_data( calld->subchannel_call)); // Create batch_data with 2 refs, since this batch will be unreffed twice: - // once for the recv_trailing_metadata_ready callback when the subchannel - // batch returns, and again when we actually get a recv_trailing_metadata - // op from the surface. - subchannel_batch_data* batch_data = - batch_data_create(elem, 2, false /* set_on_complete */); + // once when the subchannel batch returns, and again when we actually get + // a recv_trailing_metadata op from the surface. + subchannel_batch_data* batch_data = batch_data_create(elem, 2); add_retriable_recv_trailing_metadata_op(calld, retry_state, batch_data); retry_state->recv_trailing_metadata_internal_batch = batch_data; // Note: This will release the call combiner. @@ -2269,7 +2391,7 @@ static subchannel_batch_data* maybe_create_subchannel_batch_for_replay( "send_initial_metadata op", chand, calld); } - replay_batch_data = batch_data_create(elem, 1, true /* set_on_complete */); + replay_batch_data = batch_data_create(elem, 1); add_retriable_send_initial_metadata_op(calld, retry_state, replay_batch_data); } @@ -2286,8 +2408,7 @@ static subchannel_batch_data* maybe_create_subchannel_batch_for_replay( chand, calld); } if (replay_batch_data == nullptr) { - replay_batch_data = - batch_data_create(elem, 1, true /* set_on_complete */); + replay_batch_data = batch_data_create(elem, 1); } add_retriable_send_message_op(elem, retry_state, replay_batch_data); } @@ -2306,8 +2427,7 @@ static subchannel_batch_data* maybe_create_subchannel_batch_for_replay( chand, calld); } if (replay_batch_data == nullptr) { - replay_batch_data = - batch_data_create(elem, 1, true /* set_on_complete */); + replay_batch_data = batch_data_create(elem, 1); } add_retriable_send_trailing_metadata_op(calld, retry_state, replay_batch_data); @@ -2319,7 +2439,7 @@ static subchannel_batch_data* maybe_create_subchannel_batch_for_replay( // *num_batches as needed. static void add_subchannel_batches_for_pending_batches( grpc_call_element* elem, subchannel_call_retry_state* retry_state, - grpc_core::CallCombinerClosureList* closures) { + closure_to_execute* closures, size_t* num_closures) { call_data* calld = static_cast(elem->call_data); for (size_t i = 0; i < GPR_ARRAY_SIZE(calld->pending_batches); ++i) { pending_batch* pending = &calld->pending_batches[i]; @@ -2375,11 +2495,13 @@ static void add_subchannel_batches_for_pending_batches( if (retry_state->completed_recv_trailing_metadata) { subchannel_batch_data* batch_data = retry_state->recv_trailing_metadata_internal_batch; + closure_to_execute* closure = &closures[(*num_closures)++]; + closure->closure = &batch_data->on_complete; // Batches containing recv_trailing_metadata always succeed. - closures->Add( - &batch_data->recv_trailing_metadata_ready, GRPC_ERROR_NONE, - "re-executing recv_trailing_metadata_ready to propagate " - "internally triggered result"); + closure->error = GRPC_ERROR_NONE; + closure->reason = + "re-executing on_complete for recv_trailing_metadata " + "to propagate internally triggered result"; } else { batch_data_unref(retry_state->recv_trailing_metadata_internal_batch); } @@ -2391,19 +2513,14 @@ static void add_subchannel_batches_for_pending_batches( if (calld->method_params == nullptr || calld->method_params->retry_policy() == nullptr || calld->retry_committed) { - add_closure_for_subchannel_batch(elem, batch, closures); + add_closure_for_subchannel_batch(calld, batch, closures, num_closures); pending_batch_clear(calld, pending); continue; } // Create batch with the right number of callbacks. - const bool has_send_ops = batch->send_initial_metadata || - batch->send_message || - batch->send_trailing_metadata; - const int num_callbacks = has_send_ops + batch->recv_initial_metadata + - batch->recv_message + - batch->recv_trailing_metadata; - subchannel_batch_data* batch_data = batch_data_create( - elem, num_callbacks, has_send_ops /* set_on_complete */); + const int num_callbacks = + 1 + batch->recv_initial_metadata + batch->recv_message; + subchannel_batch_data* batch_data = batch_data_create(elem, num_callbacks); // Cache send ops if needed. maybe_cache_send_ops_for_batch(calld, pending); // send_initial_metadata. @@ -2430,9 +2547,11 @@ static void add_subchannel_batches_for_pending_batches( } // recv_trailing_metadata. if (batch->recv_trailing_metadata) { + GPR_ASSERT(batch->collect_stats); add_retriable_recv_trailing_metadata_op(calld, retry_state, batch_data); } - add_closure_for_subchannel_batch(elem, &batch_data->batch, closures); + add_closure_for_subchannel_batch(calld, &batch_data->batch, closures, + num_closures); // Track number of pending subchannel send batches. // If this is the first one, take a ref to the call stack. if (batch->send_initial_metadata || batch->send_message || @@ -2460,13 +2579,15 @@ static void start_retriable_subchannel_batches(void* arg, grpc_error* ignored) { grpc_connected_subchannel_call_get_parent_data( calld->subchannel_call)); // Construct list of closures to execute, one for each pending batch. - grpc_core::CallCombinerClosureList closures; + // We can start up to 6 batches. + closure_to_execute closures[GPR_ARRAY_SIZE(calld->pending_batches)]; + size_t num_closures = 0; // Replay previously-returned send_* ops if needed. subchannel_batch_data* replay_batch_data = maybe_create_subchannel_batch_for_replay(elem, retry_state); if (replay_batch_data != nullptr) { - add_closure_for_subchannel_batch(elem, &replay_batch_data->batch, - &closures); + add_closure_for_subchannel_batch(calld, &replay_batch_data->batch, closures, + &num_closures); // Track number of pending subchannel send batches. // If this is the first one, take a ref to the call stack. if (calld->num_pending_retriable_subchannel_send_batches == 0) { @@ -2475,16 +2596,17 @@ static void start_retriable_subchannel_batches(void* arg, grpc_error* ignored) { ++calld->num_pending_retriable_subchannel_send_batches; } // Now add pending batches. - add_subchannel_batches_for_pending_batches(elem, retry_state, &closures); + add_subchannel_batches_for_pending_batches(elem, retry_state, closures, + &num_closures); // Start batches on subchannel call. if (grpc_client_channel_trace.enabled()) { gpr_log(GPR_INFO, "chand=%p calld=%p: starting %" PRIuPTR " retriable batches on subchannel_call=%p", - chand, calld, closures.size(), calld->subchannel_call); + chand, calld, num_closures, calld->subchannel_call); } - // Note: This will yield the call combiner. - closures.RunClosures(calld->call_combiner); + execute_closures_in_call_combiner(elem, "start_retriable_subchannel_batches", + closures, num_closures); } // diff --git a/src/core/ext/filters/deadline/deadline_filter.cc b/src/core/ext/filters/deadline/deadline_filter.cc index d575d2d983c..27d3eac8d61 100644 --- a/src/core/ext/filters/deadline/deadline_filter.cc +++ b/src/core/ext/filters/deadline/deadline_filter.cc @@ -128,25 +128,21 @@ static void cancel_timer_if_needed(grpc_deadline_state* deadline_state) { } } -// Callback run when we receive trailing metadata. -static void recv_trailing_metadata_ready(void* arg, grpc_error* error) { +// Callback run when the call is complete. +static void on_complete(void* arg, grpc_error* error) { grpc_deadline_state* deadline_state = static_cast(arg); cancel_timer_if_needed(deadline_state); - // Invoke the original callback. - GRPC_CLOSURE_RUN(deadline_state->original_recv_trailing_metadata_ready, - GRPC_ERROR_REF(error)); + // Invoke the next callback. + GRPC_CLOSURE_RUN(deadline_state->next_on_complete, GRPC_ERROR_REF(error)); } -// Inject our own recv_trailing_metadata_ready callback into op. -static void inject_recv_trailing_metadata_ready( - grpc_deadline_state* deadline_state, grpc_transport_stream_op_batch* op) { - deadline_state->original_recv_trailing_metadata_ready = - op->payload->recv_trailing_metadata.recv_trailing_metadata_ready; - GRPC_CLOSURE_INIT(&deadline_state->recv_trailing_metadata_ready, - recv_trailing_metadata_ready, deadline_state, +// Inject our own on_complete callback into op. +static void inject_on_complete_cb(grpc_deadline_state* deadline_state, + grpc_transport_stream_op_batch* op) { + deadline_state->next_on_complete = op->on_complete; + GRPC_CLOSURE_INIT(&deadline_state->on_complete, on_complete, deadline_state, grpc_schedule_on_exec_ctx); - op->payload->recv_trailing_metadata.recv_trailing_metadata_ready = - &deadline_state->recv_trailing_metadata_ready; + op->on_complete = &deadline_state->on_complete; } // Callback and associated state for starting the timer after call stack @@ -230,7 +226,7 @@ void grpc_deadline_state_client_start_transport_stream_op_batch( // Make sure we know when the call is complete, so that we can cancel // the timer. if (op->recv_trailing_metadata) { - inject_recv_trailing_metadata_ready(deadline_state, op); + inject_on_complete_cb(deadline_state, op); } } } @@ -327,7 +323,7 @@ static void server_start_transport_stream_op_batch( // the client never sends trailing metadata, because this is the // hook that tells us when the call is complete on the server side. if (op->recv_trailing_metadata) { - inject_recv_trailing_metadata_ready(&calld->base.deadline_state, op); + inject_on_complete_cb(&calld->base.deadline_state, op); } } // Chain to next filter. diff --git a/src/core/ext/filters/deadline/deadline_filter.h b/src/core/ext/filters/deadline/deadline_filter.h index 1d797f445a7..13207cbd6fb 100644 --- a/src/core/ext/filters/deadline/deadline_filter.h +++ b/src/core/ext/filters/deadline/deadline_filter.h @@ -37,12 +37,12 @@ typedef struct grpc_deadline_state { grpc_deadline_timer_state timer_state; grpc_timer timer; grpc_closure timer_callback; - // Closure to invoke when we receive trailing metadata. + // Closure to invoke when the call is complete. // We use this to cancel the timer. - grpc_closure recv_trailing_metadata_ready; - // The original recv_trailing_metadata_ready closure, which we chain to - // after our own closure is invoked. - grpc_closure* original_recv_trailing_metadata_ready; + grpc_closure on_complete; + // The original on_complete closure, which we chain to after our own + // closure is invoked. + grpc_closure* next_on_complete; } grpc_deadline_state; // diff --git a/src/core/ext/filters/http/client/http_client_filter.cc b/src/core/ext/filters/http/client/http_client_filter.cc index 1678051beb1..ae94ce47b9e 100644 --- a/src/core/ext/filters/http/client/http_client_filter.cc +++ b/src/core/ext/filters/http/client/http_client_filter.cc @@ -55,8 +55,8 @@ struct call_data { grpc_closure recv_initial_metadata_ready; // State for handling recv_trailing_metadata ops. grpc_metadata_batch* recv_trailing_metadata; - grpc_closure* original_recv_trailing_metadata_ready; - grpc_closure recv_trailing_metadata_ready; + grpc_closure* original_recv_trailing_metadata_on_complete; + grpc_closure recv_trailing_metadata_on_complete; // State for handling send_message ops. grpc_transport_stream_op_batch* send_message_batch; size_t send_message_bytes_read; @@ -153,7 +153,8 @@ static void recv_initial_metadata_ready(void* user_data, grpc_error* error) { GRPC_CLOSURE_RUN(calld->original_recv_initial_metadata_ready, error); } -static void recv_trailing_metadata_ready(void* user_data, grpc_error* error) { +static void recv_trailing_metadata_on_complete(void* user_data, + grpc_error* error) { grpc_call_element* elem = static_cast(user_data); call_data* calld = static_cast(elem->call_data); if (error == GRPC_ERROR_NONE) { @@ -162,7 +163,7 @@ static void recv_trailing_metadata_ready(void* user_data, grpc_error* error) { } else { GRPC_ERROR_REF(error); } - GRPC_CLOSURE_RUN(calld->original_recv_trailing_metadata_ready, error); + GRPC_CLOSURE_RUN(calld->original_recv_trailing_metadata_on_complete, error); } static void send_message_on_complete(void* arg, grpc_error* error) { @@ -311,10 +312,8 @@ static void hc_start_transport_stream_op_batch( /* substitute our callback for the higher callback */ calld->recv_trailing_metadata = batch->payload->recv_trailing_metadata.recv_trailing_metadata; - calld->original_recv_trailing_metadata_ready = - batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready; - batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready = - &calld->recv_trailing_metadata_ready; + calld->original_recv_trailing_metadata_on_complete = batch->on_complete; + batch->on_complete = &calld->recv_trailing_metadata_on_complete; } grpc_error* error = GRPC_ERROR_NONE; @@ -421,8 +420,8 @@ static grpc_error* init_call_elem(grpc_call_element* elem, GRPC_CLOSURE_INIT(&calld->recv_initial_metadata_ready, recv_initial_metadata_ready, elem, grpc_schedule_on_exec_ctx); - GRPC_CLOSURE_INIT(&calld->recv_trailing_metadata_ready, - recv_trailing_metadata_ready, elem, + GRPC_CLOSURE_INIT(&calld->recv_trailing_metadata_on_complete, + recv_trailing_metadata_on_complete, elem, grpc_schedule_on_exec_ctx); GRPC_CLOSURE_INIT(&calld->send_message_on_complete, send_message_on_complete, elem, grpc_schedule_on_exec_ctx); diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc index 0d6b72c66e4..a8090d18a65 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc @@ -1149,10 +1149,12 @@ static void maybe_start_some_streams(grpc_chttp2_transport* t) { } } +/* Flag that this closure barrier wants stats to be updated before finishing */ +#define CLOSURE_BARRIER_STATS_BIT (1 << 0) /* Flag that this closure barrier may be covering a write in a pollset, and so we should not complete this closure until we can prove that the write got scheduled */ -#define CLOSURE_BARRIER_MAY_COVER_WRITE (1 << 0) +#define CLOSURE_BARRIER_MAY_COVER_WRITE (1 << 1) /* First bit of the reference count, stored in the high order bits (with the low bits being used for flags defined above) */ #define CLOSURE_BARRIER_FIRST_REF_BIT (1 << 16) @@ -1204,6 +1206,10 @@ void grpc_chttp2_complete_closure_step(grpc_chttp2_transport* t, grpc_error_add_child(closure->error_data.error, error); } if (closure->next_data.scratch < CLOSURE_BARRIER_FIRST_REF_BIT) { + if (closure->next_data.scratch & CLOSURE_BARRIER_STATS_BIT) { + grpc_transport_move_stats(&s->stats, s->collecting_stats); + s->collecting_stats = nullptr; + } if ((t->write_state == GRPC_CHTTP2_WRITE_STATE_IDLE) || !(closure->next_data.scratch & CLOSURE_BARRIER_MAY_COVER_WRITE)) { GRPC_CLOSURE_RUN(closure, closure->error_data.error); @@ -1345,14 +1351,9 @@ static void perform_stream_op_locked(void* stream_op, } grpc_closure* on_complete = op->on_complete; - // TODO(roth): This is a hack needed because we use data inside of the - // closure itself to do the barrier calculation (i.e., to ensure that - // we don't schedule the closure until all ops in the batch have been - // completed). This can go away once we move to a new C++ closure API - // that provides the ability to create a barrier closure. if (on_complete == nullptr) { - on_complete = GRPC_CLOSURE_INIT(&op->handler_private.closure, do_nothing, - nullptr, grpc_schedule_on_exec_ctx); + on_complete = + GRPC_CLOSURE_CREATE(do_nothing, nullptr, grpc_schedule_on_exec_ctx); } /* use final_data as a barrier until enqueue time; the inital counter is @@ -1360,6 +1361,12 @@ static void perform_stream_op_locked(void* stream_op, on_complete->next_data.scratch = CLOSURE_BARRIER_FIRST_REF_BIT; on_complete->error_data.error = GRPC_ERROR_NONE; + if (op->collect_stats) { + GPR_ASSERT(s->collecting_stats == nullptr); + s->collecting_stats = op_payload->collect_stats.collect_stats; + on_complete->next_data.scratch |= CLOSURE_BARRIER_STATS_BIT; + } + if (op->cancel_stream) { GRPC_STATS_INC_HTTP2_OP_CANCEL(); grpc_chttp2_cancel_stream(t, s, op_payload->cancel_stream.cancel_error); @@ -1593,11 +1600,8 @@ static void perform_stream_op_locked(void* stream_op, if (op->recv_trailing_metadata) { GRPC_STATS_INC_HTTP2_OP_RECV_TRAILING_METADATA(); - GPR_ASSERT(s->collecting_stats == nullptr); - s->collecting_stats = op_payload->recv_trailing_metadata.collect_stats; GPR_ASSERT(s->recv_trailing_metadata_finished == nullptr); - s->recv_trailing_metadata_finished = - op_payload->recv_trailing_metadata.recv_trailing_metadata_ready; + s->recv_trailing_metadata_finished = add_closure_barrier(on_complete); s->recv_trailing_metadata = op_payload->recv_trailing_metadata.recv_trailing_metadata; s->final_metadata_requested = true; @@ -1956,12 +1960,11 @@ void grpc_chttp2_maybe_complete_recv_trailing_metadata(grpc_chttp2_transport* t, } if (s->read_closed && s->frame_storage.length == 0 && !pending_data && s->recv_trailing_metadata_finished != nullptr) { - grpc_transport_move_stats(&s->stats, s->collecting_stats); - s->collecting_stats = nullptr; grpc_chttp2_incoming_metadata_buffer_publish(&s->metadata_buffer[1], s->recv_trailing_metadata); - null_then_run_closure(&s->recv_trailing_metadata_finished, - GRPC_ERROR_NONE); + grpc_chttp2_complete_closure_step( + t, s, &s->recv_trailing_metadata_finished, GRPC_ERROR_NONE, + "recv_trailing_metadata_finished"); } } } diff --git a/src/core/ext/transport/cronet/transport/cronet_transport.cc b/src/core/ext/transport/cronet/transport/cronet_transport.cc index 4a252d972d5..420c2d13e1d 100644 --- a/src/core/ext/transport/cronet/transport/cronet_transport.cc +++ b/src/core/ext/transport/cronet/transport/cronet_transport.cc @@ -925,10 +925,6 @@ static bool op_can_be_run(grpc_transport_stream_op_batch* curr_op, result = false; } /* Check if every op that was asked for is done. */ - /* TODO(muxi): We should not consider the recv ops here, since they - * have their own callbacks. We should invoke a batch's on_complete - * as soon as all of the batch's send ops are complete, even if - * there are still recv ops pending. */ else if (curr_op->send_initial_metadata && !stream_state->state_callback_received[OP_SEND_INITIAL_METADATA]) { CRONET_LOG(GPR_DEBUG, "Because"); @@ -1284,20 +1280,12 @@ static enum e_op_result execute_stream_op(struct op_and_state* oas) { op_can_be_run(stream_op, s, &oas->state, OP_RECV_TRAILING_METADATA)) { CRONET_LOG(GPR_DEBUG, "running: %p OP_RECV_TRAILING_METADATA", oas); - grpc_error* error = GRPC_ERROR_NONE; - if (stream_state->state_op_done[OP_CANCEL_ERROR]) { - error = GRPC_ERROR_REF(stream_state->cancel_error); - } else if (stream_state->state_op_done[OP_FAILED]) { - error = make_error_with_desc(GRPC_STATUS_UNAVAILABLE, "Unavailable."); - } else if (oas->s->state.rs.trailing_metadata_valid) { + if (oas->s->state.rs.trailing_metadata_valid) { grpc_chttp2_incoming_metadata_buffer_publish( &oas->s->state.rs.trailing_metadata, stream_op->payload->recv_trailing_metadata.recv_trailing_metadata); stream_state->rs.trailing_metadata_valid = false; } - GRPC_CLOSURE_SCHED( - stream_op->payload->recv_trailing_metadata.recv_trailing_metadata_ready, - error); stream_state->state_op_done[OP_RECV_TRAILING_METADATA] = true; result = ACTION_TAKEN_NO_CALLBACK; } else if (stream_op->cancel_stream && @@ -1410,11 +1398,6 @@ static void perform_stream_op(grpc_transport* gt, grpc_stream* gs, GRPC_CLOSURE_SCHED(op->payload->recv_message.recv_message_ready, GRPC_ERROR_CANCELLED); } - if (op->recv_trailing_metadata) { - GRPC_CLOSURE_SCHED( - op->payload->recv_trailing_metadata.recv_trailing_metadata_ready, - GRPC_ERROR_CANCELLED); - } GRPC_CLOSURE_SCHED(op->on_complete, GRPC_ERROR_CANCELLED); return; } diff --git a/src/core/ext/transport/inproc/inproc_transport.cc b/src/core/ext/transport/inproc/inproc_transport.cc index b0ca7f8207e..2c3bff5c1e5 100644 --- a/src/core/ext/transport/inproc/inproc_transport.cc +++ b/src/core/ext/transport/inproc/inproc_transport.cc @@ -120,6 +120,7 @@ typedef struct inproc_stream { struct inproc_stream* stream_list_next; } inproc_stream; +static grpc_closure do_nothing_closure; static bool cancel_stream_locked(inproc_stream* s, grpc_error* error); static void op_state_machine(void* arg, grpc_error* error); @@ -372,10 +373,6 @@ static void complete_if_batch_end_locked(inproc_stream* s, grpc_error* error, const char* msg) { int is_sm = static_cast(op == s->send_message_op); int is_stm = static_cast(op == s->send_trailing_md_op); - // TODO(vjpai): We should not consider the recv ops here, since they - // have their own callbacks. We should invoke a batch's on_complete - // as soon as all of the batch's send ops are complete, even if there - // are still recv ops pending. int is_rim = static_cast(op == s->recv_initial_md_op); int is_rm = static_cast(op == s->recv_message_op); int is_rtm = static_cast(op == s->recv_trailing_md_op); @@ -499,11 +496,6 @@ static void fail_helper_locked(inproc_stream* s, grpc_error* error) { s->send_trailing_md_op = nullptr; } if (s->recv_trailing_md_op) { - INPROC_LOG(GPR_INFO, "fail_helper %p scheduling trailing-metadata-ready %p", - s, error); - GRPC_CLOSURE_SCHED(s->recv_trailing_md_op->payload->recv_trailing_metadata - .recv_trailing_metadata_ready, - GRPC_ERROR_REF(error)); INPROC_LOG(GPR_INFO, "fail_helper %p scheduling trailing-md-on-complete %p", s, error); complete_if_batch_end_locked( @@ -646,12 +638,6 @@ static void op_state_machine(void* arg, grpc_error* error) { } s->trailing_md_sent = true; if (!s->t->is_client && s->trailing_md_recvd && s->recv_trailing_md_op) { - INPROC_LOG(GPR_INFO, - "op_state_machine %p scheduling trailing-metadata-ready", s); - GRPC_CLOSURE_SCHED( - s->recv_trailing_md_op->payload->recv_trailing_metadata - .recv_trailing_metadata_ready, - GRPC_ERROR_NONE); INPROC_LOG(GPR_INFO, "op_state_machine %p scheduling trailing-md-on-complete", s); GRPC_CLOSURE_SCHED(s->recv_trailing_md_op->on_complete, @@ -725,12 +711,6 @@ static void op_state_machine(void* arg, grpc_error* error) { } if (s->recv_trailing_md_op && s->t->is_client && other && other->send_message_op) { - INPROC_LOG(GPR_INFO, - "op_state_machine %p scheduling trailing-metadata-ready %p", s, - GRPC_ERROR_NONE); - GRPC_CLOSURE_SCHED(s->recv_trailing_md_op->payload->recv_trailing_metadata - .recv_trailing_metadata_ready, - GRPC_ERROR_NONE); maybe_schedule_op_closure_locked(other, GRPC_ERROR_NONE); } if (s->to_read_trailing_md_filled) { @@ -786,10 +766,6 @@ static void op_state_machine(void* arg, grpc_error* error) { INPROC_LOG(GPR_INFO, "op_state_machine %p scheduling trailing-md-on-complete %p", s, new_err); - GRPC_CLOSURE_SCHED( - s->recv_trailing_md_op->payload->recv_trailing_metadata - .recv_trailing_metadata_ready, - GRPC_ERROR_REF(new_err)); GRPC_CLOSURE_SCHED(s->recv_trailing_md_op->on_complete, GRPC_ERROR_REF(new_err)); s->recv_trailing_md_op = nullptr; @@ -883,9 +859,6 @@ static bool cancel_stream_locked(inproc_stream* s, grpc_error* error) { // couldn't complete that because we hadn't yet sent out trailing // md, now's the chance if (!s->t->is_client && s->trailing_md_recvd && s->recv_trailing_md_op) { - GRPC_CLOSURE_SCHED(s->recv_trailing_md_op->payload->recv_trailing_metadata - .recv_trailing_metadata_ready, - GRPC_ERROR_REF(s->cancel_self_error)); complete_if_batch_end_locked( s, s->cancel_self_error, s->recv_trailing_md_op, "cancel_stream scheduling trailing-md-on-complete"); @@ -900,8 +873,6 @@ static bool cancel_stream_locked(inproc_stream* s, grpc_error* error) { return ret; } -static void do_nothing(void* arg, grpc_error* error) {} - static void perform_stream_op(grpc_transport* gt, grpc_stream* gs, grpc_transport_stream_op_batch* op) { INPROC_LOG(GPR_INFO, "perform_stream_op %p %p %p", gt, gs, op); @@ -921,14 +892,8 @@ static void perform_stream_op(grpc_transport* gt, grpc_stream* gs, } grpc_error* error = GRPC_ERROR_NONE; grpc_closure* on_complete = op->on_complete; - // TODO(roth): This is a hack needed because we use data inside of the - // closure itself to do the barrier calculation (i.e., to ensure that - // we don't schedule the closure until all ops in the batch have been - // completed). This can go away once we move to a new C++ closure API - // that provides the ability to create a barrier closure. if (on_complete == nullptr) { - on_complete = GRPC_CLOSURE_INIT(&op->handler_private.closure, do_nothing, - nullptr, grpc_schedule_on_exec_ctx); + on_complete = &do_nothing_closure; } if (op->cancel_stream) { @@ -1061,15 +1026,6 @@ static void perform_stream_op(grpc_transport* gt, grpc_stream* gs, GRPC_CLOSURE_SCHED(op->payload->recv_message.recv_message_ready, GRPC_ERROR_REF(error)); } - if (op->recv_trailing_metadata) { - INPROC_LOG( - GPR_INFO, - "perform_stream_op error %p scheduling trailing-metadata-ready %p", - s, error); - GRPC_CLOSURE_SCHED( - op->payload->recv_trailing_metadata.recv_trailing_metadata_ready, - GRPC_ERROR_REF(error)); - } } INPROC_LOG(GPR_INFO, "perform_stream_op %p scheduling on_complete %p", s, error); @@ -1173,8 +1129,12 @@ static grpc_endpoint* get_endpoint(grpc_transport* t) { return nullptr; } /******************************************************************************* * GLOBAL INIT AND DESTROY */ +static void do_nothing(void* arg, grpc_error* error) {} + void grpc_inproc_transport_init(void) { grpc_core::ExecCtx exec_ctx; + GRPC_CLOSURE_INIT(&do_nothing_closure, do_nothing, nullptr, + grpc_schedule_on_exec_ctx); g_empty_slice = grpc_slice_from_static_buffer(nullptr, 0); grpc_slice key_tmp = grpc_slice_from_static_string(":path"); diff --git a/src/core/lib/channel/connected_channel.cc b/src/core/lib/channel/connected_channel.cc index e2ea334dedf..ddd30294020 100644 --- a/src/core/lib/channel/connected_channel.cc +++ b/src/core/lib/channel/connected_channel.cc @@ -51,7 +51,6 @@ typedef struct connected_channel_call_data { callback_state on_complete[6]; // Max number of pending batches. callback_state recv_initial_metadata_ready; callback_state recv_message_ready; - callback_state recv_trailing_metadata_ready; } call_data; static void run_in_call_combiner(void* arg, grpc_error* error) { @@ -112,12 +111,6 @@ static void con_start_transport_stream_op_batch( intercept_callback(calld, state, false, "recv_message_ready", &batch->payload->recv_message.recv_message_ready); } - if (batch->recv_trailing_metadata) { - callback_state* state = &calld->recv_trailing_metadata_ready; - intercept_callback( - calld, state, false, "recv_trailing_metadata_ready", - &batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready); - } if (batch->cancel_stream) { // There can be more than one cancellation batch in flight at any // given time, so we can't just pick out a fixed index into @@ -128,7 +121,7 @@ static void con_start_transport_stream_op_batch( static_cast(gpr_malloc(sizeof(*state))); intercept_callback(calld, state, true, "on_complete (cancel_stream)", &batch->on_complete); - } else if (batch->on_complete != nullptr) { + } else { callback_state* state = get_state_for_batch(calld, batch); intercept_callback(calld, state, false, "on_complete", &batch->on_complete); } diff --git a/src/core/lib/iomgr/call_combiner.h b/src/core/lib/iomgr/call_combiner.h index f9ce29f231e..0ccd08ea577 100644 --- a/src/core/lib/iomgr/call_combiner.h +++ b/src/core/lib/iomgr/call_combiner.h @@ -26,7 +26,6 @@ #include #include "src/core/lib/gpr/mpscq.h" -#include "src/core/lib/gprpp/inlined_vector.h" #include "src/core/lib/iomgr/closure.h" // A simple, lock-free mechanism for serializing activity related to a @@ -110,83 +109,4 @@ void grpc_call_combiner_set_notify_on_cancel(grpc_call_combiner* call_combiner, void grpc_call_combiner_cancel(grpc_call_combiner* call_combiner, grpc_error* error); -namespace grpc_core { - -// Helper for running a list of closures in a call combiner. -// -// Each callback running in the call combiner will eventually be -// returned to the surface, at which point the surface will yield the -// call combiner. So when we are running in the call combiner and have -// more than one callback to return to the surface, we need to re-enter -// the call combiner for all but one of those callbacks. -class CallCombinerClosureList { - public: - CallCombinerClosureList() {} - - // Adds a closure to the list. The closure must eventually result in - // the call combiner being yielded. - void Add(grpc_closure* closure, grpc_error* error, const char* reason) { - closures_.emplace_back(closure, error, reason); - } - - // Runs all closures in the call combiner and yields the call combiner. - // - // All but one of the closures in the list will be scheduled via - // GRPC_CALL_COMBINER_START(), and the remaining closure will be - // scheduled via GRPC_CLOSURE_SCHED(), which will eventually result in - // yielding the call combiner. If the list is empty, then the call - // combiner will be yielded immediately. - void RunClosures(grpc_call_combiner* call_combiner) { - for (size_t i = 1; i < closures_.size(); ++i) { - auto& closure = closures_[i]; - GRPC_CALL_COMBINER_START(call_combiner, closure.closure, closure.error, - closure.reason); - } - if (closures_.size() > 0) { - if (grpc_call_combiner_trace.enabled()) { - gpr_log(GPR_INFO, - "CallCombinerClosureList executing closure while already " - "holding call_combiner %p: closure=%p error=%s reason=%s", - call_combiner, closures_[0].closure, - grpc_error_string(closures_[0].error), closures_[0].reason); - } - // This will release the call combiner. - GRPC_CLOSURE_SCHED(closures_[0].closure, closures_[0].error); - } else { - GRPC_CALL_COMBINER_STOP(call_combiner, "no closures to schedule"); - } - closures_.clear(); - } - - // Runs all closures in the call combiner, but does NOT yield the call - // combiner. All closures will be scheduled via GRPC_CALL_COMBINER_START(). - void RunClosuresWithoutYielding(grpc_call_combiner* call_combiner) { - for (size_t i = 0; i < closures_.size(); ++i) { - auto& closure = closures_[i]; - GRPC_CALL_COMBINER_START(call_combiner, closure.closure, closure.error, - closure.reason); - } - closures_.clear(); - } - - size_t size() const { return closures_.size(); } - - private: - struct CallCombinerClosure { - grpc_closure* closure; - grpc_error* error; - const char* reason; - - CallCombinerClosure(grpc_closure* closure, grpc_error* error, - const char* reason) - : closure(closure), error(error), reason(reason) {} - }; - - // There are generally a maximum of 6 closures to run in the call - // combiner, one for each pending op. - InlinedVector closures_; -}; - -} // namespace grpc_core - #endif /* GRPC_CORE_LIB_IOMGR_CALL_COMBINER_H */ diff --git a/src/core/lib/iomgr/closure.h b/src/core/lib/iomgr/closure.h index f14c723844e..34a494485d9 100644 --- a/src/core/lib/iomgr/closure.h +++ b/src/core/lib/iomgr/closure.h @@ -283,10 +283,9 @@ inline void grpc_closure_sched(grpc_closure* c, grpc_error* error) { if (c->scheduled) { gpr_log(GPR_ERROR, "Closure already scheduled. (closure: %p, created: [%s:%d], " - "previously scheduled at: [%s: %d], newly scheduled at [%s: %d], " - "run?: %s", + "previously scheduled at: [%s: %d] run?: %s", c, c->file_created, c->line_created, c->file_initiated, - c->line_initiated, file, line, c->run ? "true" : "false"); + c->line_initiated, c->run ? "true" : "false"); abort(); } c->scheduled = true; diff --git a/src/core/lib/surface/call.cc b/src/core/lib/surface/call.cc index d44846cd12d..1cf8ea94e75 100644 --- a/src/core/lib/surface/call.cc +++ b/src/core/lib/surface/call.cc @@ -233,7 +233,6 @@ struct grpc_call { grpc_closure receiving_slice_ready; grpc_closure receiving_stream_ready; grpc_closure receiving_initial_metadata_ready; - grpc_closure receiving_trailing_metadata_ready; uint32_t test_only_last_message_flags; grpc_closure release_call; @@ -1210,6 +1209,7 @@ static void post_batch_completion(batch_control* bctl) { if (bctl->op.send_initial_metadata) { grpc_metadata_batch_destroy( + &call->metadata_batch[0 /* is_receiving */][0 /* is_trailing */]); } if (bctl->op.send_message) { @@ -1217,9 +1217,14 @@ static void post_batch_completion(batch_control* bctl) { } if (bctl->op.send_trailing_metadata) { grpc_metadata_batch_destroy( + &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */]); } if (bctl->op.recv_trailing_metadata) { + grpc_metadata_batch* md = + &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */]; + recv_trailing_filter(call, md); + /* propagate cancellation to any interested children */ gpr_atm_rel_store(&call->received_final_op_atm, 1); parent_call* pc = get_parent_call(call); @@ -1241,6 +1246,7 @@ static void post_batch_completion(batch_control* bctl) { } gpr_mu_unlock(&pc->child_list_mu); } + if (call->is_client) { get_final_status(call, set_status_value_directly, call->final_op.client.status, @@ -1250,6 +1256,7 @@ static void post_batch_completion(batch_control* bctl) { get_final_status(call, set_cancelled_value, call->final_op.server.cancelled, nullptr, nullptr); } + GRPC_ERROR_UNREF(error); error = GRPC_ERROR_NONE; } @@ -1531,19 +1538,6 @@ static void receiving_initial_metadata_ready(void* bctlp, grpc_error* error) { finish_batch_step(bctl); } -static void receiving_trailing_metadata_ready(void* bctlp, grpc_error* error) { - batch_control* bctl = static_cast(bctlp); - grpc_call* call = bctl->call; - GRPC_CALL_COMBINER_STOP(&call->call_combiner, "recv_trailing_metadata_ready"); - add_batch_error(bctl, GRPC_ERROR_REF(error), false); - if (error == GRPC_ERROR_NONE) { - grpc_metadata_batch* md = - &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */]; - recv_trailing_filter(call, md); - } - finish_batch_step(bctl); -} - static void finish_batch(void* bctlp, grpc_error* error) { batch_control* bctl = static_cast(bctlp); grpc_call* call = bctl->call; @@ -1564,8 +1558,7 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops, size_t i; const grpc_op* op; batch_control* bctl; - bool has_send_ops = false; - int num_recv_ops = 0; + int num_completion_callbacks_needed = 1; grpc_call_error error = GRPC_CALL_OK; grpc_transport_stream_op_batch* stream_op; grpc_transport_stream_op_batch_payload* stream_op_payload; @@ -1671,7 +1664,6 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops, stream_op_payload->send_initial_metadata.peer_string = &call->peer_string; } - has_send_ops = true; break; } case GRPC_OP_SEND_MESSAGE: { @@ -1701,7 +1693,6 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops, &op->data.send_message.send_message->data.raw.slice_buffer, flags); stream_op_payload->send_message.send_message.reset( call->sending_stream.get()); - has_send_ops = true; break; } case GRPC_OP_SEND_CLOSE_FROM_CLIENT: { @@ -1722,7 +1713,6 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops, call->sent_final_op = true; stream_op_payload->send_trailing_metadata.send_trailing_metadata = &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */]; - has_send_ops = true; break; } case GRPC_OP_SEND_STATUS_FROM_SERVER: { @@ -1787,7 +1777,6 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops, } stream_op_payload->send_trailing_metadata.send_trailing_metadata = &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */]; - has_send_ops = true; break; } case GRPC_OP_RECV_INITIAL_METADATA: { @@ -1815,7 +1804,7 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops, stream_op_payload->recv_initial_metadata.peer_string = &call->peer_string; } - ++num_recv_ops; + num_completion_callbacks_needed++; break; } case GRPC_OP_RECV_MESSAGE: { @@ -1837,7 +1826,7 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops, grpc_schedule_on_exec_ctx); stream_op_payload->recv_message.recv_message_ready = &call->receiving_stream_ready; - ++num_recv_ops; + num_completion_callbacks_needed++; break; } case GRPC_OP_RECV_STATUS_ON_CLIENT: { @@ -1863,16 +1852,11 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops, call->final_op.client.error_string = op->data.recv_status_on_client.error_string; stream_op->recv_trailing_metadata = true; + stream_op->collect_stats = true; stream_op_payload->recv_trailing_metadata.recv_trailing_metadata = &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */]; - stream_op_payload->recv_trailing_metadata.collect_stats = + stream_op_payload->collect_stats.collect_stats = &call->final_info.stats.transport_stream_stats; - GRPC_CLOSURE_INIT(&call->receiving_trailing_metadata_ready, - receiving_trailing_metadata_ready, bctl, - grpc_schedule_on_exec_ctx); - stream_op_payload->recv_trailing_metadata.recv_trailing_metadata_ready = - &call->receiving_trailing_metadata_ready; - ++num_recv_ops; break; } case GRPC_OP_RECV_CLOSE_ON_SERVER: { @@ -1893,16 +1877,11 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops, call->final_op.server.cancelled = op->data.recv_close_on_server.cancelled; stream_op->recv_trailing_metadata = true; + stream_op->collect_stats = true; stream_op_payload->recv_trailing_metadata.recv_trailing_metadata = &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */]; - stream_op_payload->recv_trailing_metadata.collect_stats = + stream_op_payload->collect_stats.collect_stats = &call->final_info.stats.transport_stream_stats; - GRPC_CLOSURE_INIT(&call->receiving_trailing_metadata_ready, - receiving_trailing_metadata_ready, bctl, - grpc_schedule_on_exec_ctx); - stream_op_payload->recv_trailing_metadata.recv_trailing_metadata_ready = - &call->receiving_trailing_metadata_ready; - ++num_recv_ops; break; } } @@ -1912,15 +1891,13 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops, if (!is_notify_tag_closure) { GPR_ASSERT(grpc_cq_begin_op(call->cq, notify_tag)); } - gpr_ref_init(&bctl->steps_to_complete, (has_send_ops ? 1 : 0) + num_recv_ops); - - if (has_send_ops) { - GRPC_CLOSURE_INIT(&bctl->finish_batch, finish_batch, bctl, - grpc_schedule_on_exec_ctx); - stream_op->on_complete = &bctl->finish_batch; - } + gpr_ref_init(&bctl->steps_to_complete, num_completion_callbacks_needed); + GRPC_CLOSURE_INIT(&bctl->finish_batch, finish_batch, bctl, + grpc_schedule_on_exec_ctx); + stream_op->on_complete = &bctl->finish_batch; gpr_atm_rel_store(&call->any_ops_sent_atm, 1); + execute_batch(call, stream_op, &bctl->start_batch); done: diff --git a/src/core/lib/transport/transport.cc b/src/core/lib/transport/transport.cc index cbdb77c8441..039d603394f 100644 --- a/src/core/lib/transport/transport.cc +++ b/src/core/lib/transport/transport.cc @@ -212,32 +212,21 @@ void grpc_transport_stream_op_batch_finish_with_failure( if (batch->send_message) { batch->payload->send_message.send_message.reset(); } - if (batch->cancel_stream) { - GRPC_ERROR_UNREF(batch->payload->cancel_stream.cancel_error); + if (batch->recv_message) { + GRPC_CALL_COMBINER_START( + call_combiner, batch->payload->recv_message.recv_message_ready, + GRPC_ERROR_REF(error), "failing recv_message_ready"); } - // Construct a list of closures to execute. - grpc_core::CallCombinerClosureList closures; if (batch->recv_initial_metadata) { - closures.Add( + GRPC_CALL_COMBINER_START( + call_combiner, batch->payload->recv_initial_metadata.recv_initial_metadata_ready, GRPC_ERROR_REF(error), "failing recv_initial_metadata_ready"); } - if (batch->recv_message) { - closures.Add(batch->payload->recv_message.recv_message_ready, - GRPC_ERROR_REF(error), "failing recv_message_ready"); - } - if (batch->recv_trailing_metadata) { - closures.Add( - batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready, - GRPC_ERROR_REF(error), "failing recv_trailing_metadata_ready"); - } - if (batch->on_complete != nullptr) { - closures.Add(batch->on_complete, GRPC_ERROR_REF(error), - "failing on_complete"); + GRPC_CLOSURE_SCHED(batch->on_complete, error); + if (batch->cancel_stream) { + GRPC_ERROR_UNREF(batch->payload->cancel_stream.cancel_error); } - // Execute closures. - closures.RunClosures(call_combiner); - GRPC_ERROR_UNREF(error); } typedef struct { diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h index 585b9dfae91..b2e252d939e 100644 --- a/src/core/lib/transport/transport.h +++ b/src/core/lib/transport/transport.h @@ -122,15 +122,9 @@ typedef struct grpc_transport_stream_op_batch_payload /* Transport stream op: a set of operations to perform on a transport against a single stream */ typedef struct grpc_transport_stream_op_batch { - /** Should be scheduled when all of the non-recv operations in the batch - are complete. - - The recv ops (recv_initial_metadata, recv_message, and - recv_trailing_metadata) each have their own callbacks. If a batch - contains both recv ops and non-recv ops, on_complete should be - scheduled as soon as the non-recv ops are complete, regardless of - whether or not the recv ops are complete. If a batch contains - only recv ops, on_complete can be null. */ + /** Should be enqueued when all requested operations (excluding recv_message + and recv_initial_metadata which have their own closures) in a given batch + have been completed. */ grpc_closure* on_complete; /** Values for the stream op (fields set are determined by flags above) */ @@ -155,6 +149,9 @@ typedef struct grpc_transport_stream_op_batch { */ bool recv_trailing_metadata : 1; + /** Collect any stats into provided buffer, zero internal stat counters */ + bool collect_stats : 1; + /** Cancel this stream with the provided error */ bool cancel_stream : 1; @@ -222,11 +219,12 @@ struct grpc_transport_stream_op_batch_payload { struct { grpc_metadata_batch* recv_trailing_metadata; - grpc_transport_stream_stats* collect_stats; - /** Should be enqueued when initial metadata is ready to be processed. */ - grpc_closure* recv_trailing_metadata_ready; } recv_trailing_metadata; + struct { + grpc_transport_stream_stats* collect_stats; + } collect_stats; + /** Forcefully close this stream. The HTTP2 semantics should be: - server side: if cancel_error has GRPC_ERROR_INT_GRPC_STATUS, and diff --git a/src/core/lib/transport/transport_op_string.cc b/src/core/lib/transport/transport_op_string.cc index 8c7db642a54..25ab492f3a4 100644 --- a/src/core/lib/transport/transport_op_string.cc +++ b/src/core/lib/transport/transport_op_string.cc @@ -120,6 +120,13 @@ char* grpc_transport_stream_op_batch_string( gpr_strvec_add(&b, tmp); } + if (op->collect_stats) { + gpr_strvec_add(&b, gpr_strdup(" ")); + gpr_asprintf(&tmp, "COLLECT_STATS:%p", + op->payload->collect_stats.collect_stats); + gpr_strvec_add(&b, tmp); + } + out = gpr_strvec_flatten(&b, nullptr); gpr_strvec_destroy(&b); diff --git a/test/cpp/microbenchmarks/bm_call_create.cc b/test/cpp/microbenchmarks/bm_call_create.cc index dd1610dc3d3..831b29c506c 100644 --- a/test/cpp/microbenchmarks/bm_call_create.cc +++ b/test/cpp/microbenchmarks/bm_call_create.cc @@ -621,26 +621,18 @@ typedef struct { static void StartTransportStreamOp(grpc_call_element* elem, grpc_transport_stream_op_batch* op) { call_data* calld = static_cast(elem->call_data); - // Construct list of closures to return. - grpc_core::CallCombinerClosureList closures; if (op->recv_initial_metadata) { - closures.Add(op->payload->recv_initial_metadata.recv_initial_metadata_ready, - GRPC_ERROR_NONE, "recv_initial_metadata"); + GRPC_CALL_COMBINER_START( + calld->call_combiner, + op->payload->recv_initial_metadata.recv_initial_metadata_ready, + GRPC_ERROR_NONE, "recv_initial_metadata"); } if (op->recv_message) { - closures.Add(op->payload->recv_message.recv_message_ready, GRPC_ERROR_NONE, - "recv_message"); + GRPC_CALL_COMBINER_START(calld->call_combiner, + op->payload->recv_message.recv_message_ready, + GRPC_ERROR_NONE, "recv_message"); } - if (op->recv_trailing_metadata) { - closures.Add( - op->payload->recv_trailing_metadata.recv_trailing_metadata_ready, - GRPC_ERROR_NONE, "recv_trailing_metadata"); - } - if (op->on_complete != nullptr) { - closures.Add(op->on_complete, GRPC_ERROR_NONE, "on_complete"); - } - // Execute closures. - closures.RunClosures(calld->call_combiner); + GRPC_CLOSURE_SCHED(op->on_complete, GRPC_ERROR_NONE); } static void StartTransportOp(grpc_channel_element* elem, From 7174ed5ded78b61307785d4f3e4ecbdcea6a3f83 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Mon, 11 Jun 2018 14:24:25 -0700 Subject: [PATCH 23/57] Backport #15714 to v1.13.x --- src/core/lib/iomgr/cfstream_handle.cc | 4 +++- src/core/lib/iomgr/tcp_client_cfstream.cc | 14 +++++++------- src/objective-c/tests/GRPCClientTests.m | 3 ++- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/core/lib/iomgr/cfstream_handle.cc b/src/core/lib/iomgr/cfstream_handle.cc index 30f4e656324..827fd24831e 100644 --- a/src/core/lib/iomgr/cfstream_handle.cc +++ b/src/core/lib/iomgr/cfstream_handle.cc @@ -116,7 +116,9 @@ CFStreamHandle::CFStreamHandle(CFReadStreamRef read_stream, open_event_.InitEvent(); read_event_.InitEvent(); write_event_.InitEvent(); - CFStreamClientContext ctx = {0, static_cast(this), nil, nil, nil}; + CFStreamClientContext ctx = {0, static_cast(this), + CFStreamHandle::Retain, CFStreamHandle::Release, + nil}; CFReadStreamSetClient( read_stream, kCFStreamEventOpenCompleted | kCFStreamEventHasBytesAvailable | diff --git a/src/core/lib/iomgr/tcp_client_cfstream.cc b/src/core/lib/iomgr/tcp_client_cfstream.cc index ffed3bbef67..5acea91792f 100644 --- a/src/core/lib/iomgr/tcp_client_cfstream.cc +++ b/src/core/lib/iomgr/tcp_client_cfstream.cc @@ -52,7 +52,7 @@ typedef struct CFStreamConnect { CFReadStreamRef read_stream; CFWriteStreamRef write_stream; - CFStreamHandle* stream_sync; + CFStreamHandle* stream_handle; grpc_timer alarm; grpc_closure on_alarm; @@ -71,7 +71,7 @@ typedef struct CFStreamConnect { static void CFStreamConnectCleanup(CFStreamConnect* connect) { grpc_resource_quota_unref_internal(connect->resource_quota); - CFSTREAM_HANDLE_UNREF(connect->stream_sync, "async connect clean up"); + CFSTREAM_HANDLE_UNREF(connect->stream_handle, "async connect clean up"); CFRelease(connect->read_stream); CFRelease(connect->write_stream); gpr_mu_destroy(&connect->mu); @@ -131,7 +131,7 @@ static void OnOpen(void* arg, grpc_error* error) { if (error == GRPC_ERROR_NONE) { *endpoint = grpc_cfstream_endpoint_create( connect->read_stream, connect->write_stream, connect->addr_name, - connect->resource_quota, connect->stream_sync); + connect->resource_quota, connect->stream_handle); } } else { GRPC_ERROR_REF(error); @@ -170,8 +170,8 @@ static void CFStreamClientConnect(grpc_closure* closure, grpc_endpoint** ep, gpr_mu_init(&connect->mu); if (grpc_tcp_trace.enabled()) { - gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: asynchronously connecting", - connect->addr_name); + gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %p, %s: asynchronously connecting", + connect, connect->addr_name); } grpc_resource_quota* resource_quota = grpc_resource_quota_create(NULL); @@ -197,11 +197,11 @@ static void CFStreamClientConnect(grpc_closure* closure, grpc_endpoint** ep, CFRelease(host); connect->read_stream = read_stream; connect->write_stream = write_stream; - connect->stream_sync = + connect->stream_handle = CFStreamHandle::CreateStreamHandle(read_stream, write_stream); GRPC_CLOSURE_INIT(&connect->on_open, OnOpen, static_cast(connect), grpc_schedule_on_exec_ctx); - connect->stream_sync->NotifyOnOpen(&connect->on_open); + connect->stream_handle->NotifyOnOpen(&connect->on_open); GRPC_CLOSURE_INIT(&connect->on_alarm, OnAlarm, connect, grpc_schedule_on_exec_ctx); gpr_mu_lock(&connect->mu); diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m index 5cd0231db7f..d9186561c35 100644 --- a/src/objective-c/tests/GRPCClientTests.m +++ b/src/objective-c/tests/GRPCClientTests.m @@ -525,7 +525,8 @@ static GRPCProtoMethod *kFullDuplexCallMethod; - (void)testErrorCode { int port = [self findFreePort]; NSString *const kDummyAddress = [NSString stringWithFormat:@"localhost:%d", port]; - __weak XCTestExpectation *completion = [self expectationWithDescription:@"Empty RPC completed."]; + __weak XCTestExpectation *completion = + [self expectationWithDescription:@"Received correct error code."]; GRPCCall *call = [[GRPCCall alloc] initWithHost:kDummyAddress path:kEmptyCallMethod.HTTPPath From 7a28a34ca78b8fa1a02c2fe6882a355d0ff672c3 Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Mon, 11 Jun 2018 17:06:19 -0700 Subject: [PATCH 24/57] log granular ruby end2end test times --- .../helper_scripts/run_ruby_end2end_tests.sh | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh b/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh index 5784745bac0..1ae1d598dea 100755 --- a/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh +++ b/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh @@ -19,14 +19,14 @@ set -ex cd "$(dirname "$0")/../../.." EXIT_CODE=0 -ruby src/ruby/end2end/sig_handling_driver.rb || EXIT_CODE=1 -ruby src/ruby/end2end/channel_state_driver.rb || EXIT_CODE=1 -ruby src/ruby/end2end/channel_closing_driver.rb || EXIT_CODE=1 -ruby src/ruby/end2end/sig_int_during_channel_watch_driver.rb || EXIT_CODE=1 -ruby src/ruby/end2end/killed_client_thread_driver.rb || EXIT_CODE=1 -ruby src/ruby/end2end/forking_client_driver.rb || EXIT_CODE=1 -ruby src/ruby/end2end/grpc_class_init_driver.rb || EXIT_CODE=1 -ruby src/ruby/end2end/multiple_killed_watching_threads_driver.rb || EXIT_CODE=1 -ruby src/ruby/end2end/load_grpc_with_gc_stress_driver.rb || EXIT_CODE=1 -ruby src/ruby/end2end/client_memory_usage_driver.rb || EXIT_CODE=1 +time ruby src/ruby/end2end/sig_handling_driver.rb || EXIT_CODE=1 +time ruby src/ruby/end2end/channel_state_driver.rb || EXIT_CODE=1 +time ruby src/ruby/end2end/channel_closing_driver.rb || EXIT_CODE=1 +time ruby src/ruby/end2end/sig_int_during_channel_watch_driver.rb || EXIT_CODE=1 +time ruby src/ruby/end2end/killed_client_thread_driver.rb || EXIT_CODE=1 +time ruby src/ruby/end2end/forking_client_driver.rb || EXIT_CODE=1 +time ruby src/ruby/end2end/grpc_class_init_driver.rb || EXIT_CODE=1 +time ruby src/ruby/end2end/multiple_killed_watching_threads_driver.rb || EXIT_CODE=1 +time ruby src/ruby/end2end/load_grpc_with_gc_stress_driver.rb || EXIT_CODE=1 +time ruby src/ruby/end2end/client_memory_usage_driver.rb || EXIT_CODE=1 exit $EXIT_CODE From 2a881a3a05ade7211657e10bd6a324daebc56677 Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Mon, 11 Jun 2018 17:25:23 -0700 Subject: [PATCH 25/57] double timeout to check if finishes --- tools/run_tests/run_tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py index ea4c7c3c655..014fb7d33a3 100755 --- a/tools/run_tests/run_tests.py +++ b/tools/run_tests/run_tests.py @@ -883,7 +883,7 @@ class RubyLanguage(object): tests.append( self.config.job_spec( ['tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh'], - timeout_seconds=10 * 60, + timeout_seconds=20 * 60, environ=_FORCE_ENVIRON_FOR_WRAPPERS)) return tests From cb5471c2eead73a90dca739fbfbfb8819a3ec31b Mon Sep 17 00:00:00 2001 From: ncteisen Date: Mon, 11 Jun 2018 20:07:43 -0700 Subject: [PATCH 26/57] Sleep less for ruby test --- src/ruby/end2end/multiple_killed_watching_threads_driver.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ruby/end2end/multiple_killed_watching_threads_driver.rb b/src/ruby/end2end/multiple_killed_watching_threads_driver.rb index 8ec2073d988..dbfdf61599f 100755 --- a/src/ruby/end2end/multiple_killed_watching_threads_driver.rb +++ b/src/ruby/end2end/multiple_killed_watching_threads_driver.rb @@ -60,8 +60,8 @@ def main run_multiple_killed_watches(1000, 0.001) STDERR.puts '10000 iterations, sleep 0.00001 before killing thread' run_multiple_killed_watches(10_000, 0.00001) - STDERR.puts '20000 iterations, sleep 0.00001 before killing thread' - run_multiple_killed_watches(20_000, 0.00001) + STDERR.puts '20000 iterations, sleep 0.000001 before killing thread' + run_multiple_killed_watches(20_000, 0.000001) end main From 19ac7c0baf298be51c0dbfa7d5bcd1f45eec7c78 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Wed, 13 Jun 2018 15:06:07 -0700 Subject: [PATCH 27/57] Fix ruby test by backing off on the concurrency --- src/ruby/end2end/multiple_killed_watching_threads_driver.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/ruby/end2end/multiple_killed_watching_threads_driver.rb b/src/ruby/end2end/multiple_killed_watching_threads_driver.rb index dbfdf61599f..7b39f5a3476 100755 --- a/src/ruby/end2end/multiple_killed_watching_threads_driver.rb +++ b/src/ruby/end2end/multiple_killed_watching_threads_driver.rb @@ -58,10 +58,6 @@ def main run_multiple_killed_watches(10, 0.1) STDERR.puts '1000 iterations, sleep 0.001 before killing thread' run_multiple_killed_watches(1000, 0.001) - STDERR.puts '10000 iterations, sleep 0.00001 before killing thread' - run_multiple_killed_watches(10_000, 0.00001) - STDERR.puts '20000 iterations, sleep 0.000001 before killing thread' - run_multiple_killed_watches(20_000, 0.000001) end main From 87d08a3b16801ca6c5f4570f026511dfda9c48bf Mon Sep 17 00:00:00 2001 From: Mehrdad Afshari Date: Mon, 4 Jun 2018 14:15:39 -0700 Subject: [PATCH 28/57] Add Python 3.7 Linux wheels to artifact build --- tools/run_tests/artifacts/artifact_targets.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/run_tests/artifacts/artifact_targets.py b/tools/run_tests/artifacts/artifact_targets.py index e4d9e6bdfed..35cbd730c88 100644 --- a/tools/run_tests/artifacts/artifact_targets.py +++ b/tools/run_tests/artifacts/artifact_targets.py @@ -354,6 +354,7 @@ def targets(): PythonArtifact('linux', 'x86', 'cp34-cp34m'), PythonArtifact('linux', 'x86', 'cp35-cp35m'), PythonArtifact('linux', 'x86', 'cp36-cp36m'), + PythonArtifact('linux', 'x86', 'cp37-cp37m'), PythonArtifact('linux_extra', 'armv7', '2.7'), PythonArtifact('linux_extra', 'armv7', '3.4'), PythonArtifact('linux_extra', 'armv7', '3.5'), @@ -367,6 +368,7 @@ def targets(): PythonArtifact('linux', 'x64', 'cp34-cp34m'), PythonArtifact('linux', 'x64', 'cp35-cp35m'), PythonArtifact('linux', 'x64', 'cp36-cp36m'), + PythonArtifact('linux', 'x64', 'cp37-cp37m'), PythonArtifact('macos', 'x64', 'python2.7'), PythonArtifact('macos', 'x64', 'python3.4'), PythonArtifact('macos', 'x64', 'python3.5'), From 26cb182dade4d6cd7dd959e531ca1b101eba3d9d Mon Sep 17 00:00:00 2001 From: Mehrdad Afshari Date: Thu, 14 Jun 2018 13:08:57 -0400 Subject: [PATCH 29/57] Use a Docker image that includes Python3.7rc1 In order to build Python3.7 packages for manylinux1 platform, we need our Docker image to include Python3.7. Unfortunately, since Python 3.7 is still in RC1 stage, the official docker image does not include that Python release, so we temporarily rely on our own underlying docker image to build. --- .../dockerfile/grpc_artifact_python_manylinux_x64/Dockerfile | 5 ++++- .../dockerfile/grpc_artifact_python_manylinux_x86/Dockerfile | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/tools/dockerfile/grpc_artifact_python_manylinux_x64/Dockerfile b/tools/dockerfile/grpc_artifact_python_manylinux_x64/Dockerfile index 07604c7c424..aeb7b978450 100644 --- a/tools/dockerfile/grpc_artifact_python_manylinux_x64/Dockerfile +++ b/tools/dockerfile/grpc_artifact_python_manylinux_x64/Dockerfile @@ -14,7 +14,9 @@ # Docker file for building gRPC manylinux Python artifacts. -FROM quay.io/pypa/manylinux1_x86_64 +# TODO(mmx): revert to the official manylinux1 docker image +# after it ships with Python 3.7 +FROM grpctesting/manylinux1_temp_py37rc1_x86_64:79891dc2ec764b62a2dd2ffd083d381efde11a5f # Update the package manager RUN yum update -y @@ -27,6 +29,7 @@ RUN /opt/python/cp27-cp27mu/bin/pip install cython RUN /opt/python/cp34-cp34m/bin/pip install cython RUN /opt/python/cp35-cp35m/bin/pip install cython RUN /opt/python/cp36-cp36m/bin/pip install cython +RUN /opt/python/cp37-cp37m/bin/pip install cython #################################################### # Install auditwheel with fix for namespace packages diff --git a/tools/dockerfile/grpc_artifact_python_manylinux_x86/Dockerfile b/tools/dockerfile/grpc_artifact_python_manylinux_x86/Dockerfile index 96ab515efe0..dcd9c817da1 100644 --- a/tools/dockerfile/grpc_artifact_python_manylinux_x86/Dockerfile +++ b/tools/dockerfile/grpc_artifact_python_manylinux_x86/Dockerfile @@ -14,7 +14,9 @@ # Docker file for building gRPC manylinux Python artifacts. -FROM quay.io/pypa/manylinux1_i686 +# TODO(mmx): revert to the official manylinux1 docker image +# after it ships with Python 3.7 +FROM grpctesting/manylinux1_temp_py37rc1_i686:79891dc2ec764b62a2dd2ffd083d381efde11a5f # Update the package manager RUN yum update -y @@ -27,6 +29,7 @@ RUN /opt/python/cp27-cp27mu/bin/pip install cython RUN /opt/python/cp34-cp34m/bin/pip install cython RUN /opt/python/cp35-cp35m/bin/pip install cython RUN /opt/python/cp36-cp36m/bin/pip install cython +RUN /opt/python/cp37-cp37m/bin/pip install cython #################################################### # Install auditwheel with fix for namespace packages From c7166ae67dd554d41b4d26286da2888aebc0153b Mon Sep 17 00:00:00 2001 From: ncteisen Date: Fri, 15 Jun 2018 11:04:37 -0400 Subject: [PATCH 30/57] Make channelz an opt in feature --- include/grpc/impl/codegen/grpc_types.h | 3 + src/core/lib/channel/channelz.cc | 16 +++-- src/core/lib/channel/channelz.h | 13 ++-- src/core/lib/surface/channel.cc | 5 +- test/core/channel/channel_trace_test.cc | 10 +-- test/core/channel/channelz_test.cc | 26 ++++++-- test/core/end2end/tests/channelz.cc | 86 +++++++++++++++++++++++-- 7 files changed, 132 insertions(+), 27 deletions(-) diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h index a5961857c10..786c070c140 100644 --- a/include/grpc/impl/codegen/grpc_types.h +++ b/include/grpc/impl/codegen/grpc_types.h @@ -289,6 +289,9 @@ typedef struct { * subchannel. The default is 10. If set to 0, channel tracing is disabled. */ #define GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE \ "grpc.max_channel_trace_events_per_node" +/** If non-zero, gRPC library will track stats and information at at per channel + * level. Disabling channelz naturally disabled channel tracing. */ +#define GRPC_ARG_ENABLE_CHANNELZ "grpc.enable_channelz" /** If non-zero, Cronet transport will coalesce packets to fewer frames * when possible. */ #define GRPC_ARG_USE_CRONET_PACKET_COALESCING \ diff --git a/src/core/lib/channel/channelz.cc b/src/core/lib/channel/channelz.cc index 799eb8bed1a..40c0932f3f8 100644 --- a/src/core/lib/channel/channelz.cc +++ b/src/core/lib/channel/channelz.cc @@ -89,21 +89,28 @@ grpc_json* add_num_str(grpc_json* parent, grpc_json* it, const char* name, } // namespace -ChannelNode::ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes) - : channel_(channel), - target_(UniquePtr(grpc_channel_get_target(channel_))), - channel_uuid_(ChannelzRegistry::Register(this)) { +ChannelNode::ChannelNode(bool enabled, grpc_channel* channel, + size_t channel_tracer_max_nodes) + : enabled_(enabled), + channel_(channel), + target_(nullptr), + channel_uuid_(-1) { trace_.Init(channel_tracer_max_nodes); + if (!enabled_) return; + target_ = UniquePtr(grpc_channel_get_target(channel_)); + channel_uuid_ = ChannelzRegistry::Register(this); gpr_atm_no_barrier_store(&last_call_started_millis_, (gpr_atm)ExecCtx::Get()->Now()); } ChannelNode::~ChannelNode() { trace_.Destroy(); + if (!enabled_) return; ChannelzRegistry::Unregister(channel_uuid_); } void ChannelNode::RecordCallStarted() { + if (!enabled_) return; gpr_atm_no_barrier_fetch_add(&calls_started_, (gpr_atm)1); gpr_atm_no_barrier_store(&last_call_started_millis_, (gpr_atm)ExecCtx::Get()->Now()); @@ -118,6 +125,7 @@ grpc_connectivity_state ChannelNode::GetConnectivityState() { } char* ChannelNode::RenderJSON() { + if (!enabled_) return nullptr; // We need to track these three json objects to build our object grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT); grpc_json* json = top_level_json; diff --git a/src/core/lib/channel/channelz.h b/src/core/lib/channel/channelz.h index 62dc817b6ad..3352daccd09 100644 --- a/src/core/lib/channel/channelz.h +++ b/src/core/lib/channel/channelz.h @@ -40,14 +40,17 @@ class ChannelNodePeer; class ChannelNode : public RefCounted { public: - ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes); + ChannelNode(bool enabled, grpc_channel* channel, + size_t channel_tracer_max_nodes); ~ChannelNode(); void RecordCallStarted(); void RecordCallFailed() { + if (!enabled_) return; gpr_atm_no_barrier_fetch_add(&calls_failed_, (gpr_atm(1))); } void RecordCallSucceeded() { + if (!enabled_) return; gpr_atm_no_barrier_fetch_add(&calls_succeeded_, (gpr_atm(1))); } @@ -56,6 +59,7 @@ class ChannelNode : public RefCounted { ChannelTrace* trace() { return trace_.get(); } void set_channel_destroyed() { + if (!enabled_) return; GPR_ASSERT(channel_ != nullptr); channel_ = nullptr; } @@ -70,13 +74,14 @@ class ChannelNode : public RefCounted { grpc_connectivity_state GetConnectivityState(); // Not owned. Will be set to nullptr when the channel is destroyed. - grpc_channel* channel_; + const bool enabled_; + grpc_channel* channel_ = nullptr; UniquePtr target_; gpr_atm calls_started_ = 0; gpr_atm calls_succeeded_ = 0; gpr_atm calls_failed_ = 0; - gpr_atm last_call_started_millis_; - const intptr_t channel_uuid_; + gpr_atm last_call_started_millis_ = 0; + intptr_t channel_uuid_; ManualConstructor trace_; }; diff --git a/src/core/lib/surface/channel.cc b/src/core/lib/surface/channel.cc index 087b7778bfd..b8255706058 100644 --- a/src/core/lib/surface/channel.cc +++ b/src/core/lib/surface/channel.cc @@ -104,6 +104,7 @@ grpc_channel* grpc_channel_create_with_builder( channel->target = target; channel->is_client = grpc_channel_stack_type_is_client(channel_stack_type); size_t channel_tracer_max_nodes = 0; // default to off + bool channelz_enabled = false; gpr_mu_init(&channel->registered_call_mu); channel->registered_calls = nullptr; @@ -142,13 +143,15 @@ grpc_channel* grpc_channel_create_with_builder( const grpc_integer_options options = {0, 0, INT_MAX}; channel_tracer_max_nodes = (size_t)grpc_channel_arg_get_integer(&args->args[i], options); + } else if (0 == strcmp(args->args[i].key, GRPC_ARG_ENABLE_CHANNELZ)) { + channelz_enabled = grpc_channel_arg_get_bool(&args->args[i], false); } } grpc_channel_args_destroy(args); channel->channelz_channel = grpc_core::MakeRefCounted( - channel, channel_tracer_max_nodes); + channelz_enabled, channel, channel_tracer_max_nodes); channel->channelz_channel->trace()->AddTraceEvent( grpc_core::channelz::ChannelTrace::Severity::Info, grpc_slice_from_static_string("Channel created")); diff --git a/test/core/channel/channel_trace_test.cc b/test/core/channel/channel_trace_test.cc index bbddee3f14e..e1bde4e6d4b 100644 --- a/test/core/channel/channel_trace_test.cc +++ b/test/core/channel/channel_trace_test.cc @@ -157,7 +157,7 @@ TEST_P(ChannelTracerTest, ComplexTest) { AddSimpleTrace(&tracer); ChannelFixture channel1(GetParam()); RefCountedPtr sc1 = - MakeRefCounted(channel1.channel(), GetParam()); + MakeRefCounted(true, channel1.channel(), GetParam()); tracer.AddTraceEventReferencingSubchannel( ChannelTrace::Severity::Info, grpc_slice_from_static_string("subchannel one created"), sc1); @@ -175,7 +175,7 @@ TEST_P(ChannelTracerTest, ComplexTest) { ValidateChannelTrace(&tracer, 5, GetParam()); ChannelFixture channel2(GetParam()); RefCountedPtr sc2 = - MakeRefCounted(channel2.channel(), GetParam()); + MakeRefCounted(true, channel2.channel(), GetParam()); tracer.AddTraceEventReferencingChannel( ChannelTrace::Severity::Info, grpc_slice_from_static_string("LB channel two created"), sc2); @@ -204,7 +204,7 @@ TEST_P(ChannelTracerTest, TestNesting) { ValidateChannelTrace(&tracer, 2, GetParam()); ChannelFixture channel1(GetParam()); RefCountedPtr sc1 = - MakeRefCounted(channel1.channel(), GetParam()); + MakeRefCounted(true, channel1.channel(), GetParam()); tracer.AddTraceEventReferencingChannel( ChannelTrace::Severity::Info, grpc_slice_from_static_string("subchannel one created"), sc1); @@ -212,7 +212,7 @@ TEST_P(ChannelTracerTest, TestNesting) { AddSimpleTrace(sc1->trace()); ChannelFixture channel2(GetParam()); RefCountedPtr conn1 = - MakeRefCounted(channel2.channel(), GetParam()); + MakeRefCounted(true, channel2.channel(), GetParam()); // nesting one level deeper. sc1->trace()->AddTraceEventReferencingSubchannel( ChannelTrace::Severity::Info, @@ -225,7 +225,7 @@ TEST_P(ChannelTracerTest, TestNesting) { ValidateChannelTrace(conn1->trace(), 1, GetParam()); ChannelFixture channel3(GetParam()); RefCountedPtr sc2 = - MakeRefCounted(channel3.channel(), GetParam()); + MakeRefCounted(true, channel3.channel(), GetParam()); tracer.AddTraceEventReferencingSubchannel( ChannelTrace::Severity::Info, grpc_slice_from_static_string("subchannel two created"), sc2); diff --git a/test/core/channel/channelz_test.cc b/test/core/channel/channelz_test.cc index facf1c03f76..e1dc76e4aa5 100644 --- a/test/core/channel/channelz_test.cc +++ b/test/core/channel/channelz_test.cc @@ -70,12 +70,15 @@ grpc_json* GetJsonChild(grpc_json* parent, const char* key) { class ChannelFixture { public: ChannelFixture(int max_trace_nodes) { - grpc_arg client_a; - client_a.type = GRPC_ARG_INTEGER; - client_a.key = + grpc_arg client_a[2]; + client_a[0].type = GRPC_ARG_INTEGER; + client_a[0].key = const_cast(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE); - client_a.value.integer = max_trace_nodes; - grpc_channel_args client_args = {1, &client_a}; + client_a[0].value.integer = max_trace_nodes; + client_a[1].type = GRPC_ARG_INTEGER; + client_a[1].key = const_cast(GRPC_ARG_ENABLE_CHANNELZ); + client_a[1].value.integer = true; + grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a}; channel_ = grpc_insecure_channel_create("fake_target", &client_args, nullptr); } @@ -96,14 +99,14 @@ struct validate_channel_data_args { void ValidateChildInteger(grpc_json* json, int64_t expect, const char* key) { grpc_json* gotten_json = GetJsonChild(json, key); - EXPECT_NE(gotten_json, nullptr); + ASSERT_NE(gotten_json, nullptr); int64_t gotten_number = (int64_t)strtol(gotten_json->value, nullptr, 0); EXPECT_EQ(gotten_number, expect); } void ValidateCounters(char* json_str, validate_channel_data_args args) { grpc_json* json = grpc_json_parse_string(json_str); - EXPECT_NE(json, nullptr); + ASSERT_NE(json, nullptr); grpc_json* data = GetJsonChild(json, "data"); ValidateChildInteger(data, args.calls_started, "callsStarted"); ValidateChildInteger(data, args.calls_failed, "callsFailed"); @@ -143,6 +146,15 @@ TEST_P(ChannelzChannelTest, BasicChannel) { gpr_free(json_str); } +TEST(ChannelzChannelTest, ChannelzDisabled) { + grpc_core::ExecCtx exec_ctx; + grpc_channel* channel = + grpc_insecure_channel_create("fake_target", nullptr, nullptr); + ChannelNode* channelz_channel = grpc_channel_get_channelz_node(channel); + char* json_str = channelz_channel->RenderJSON(); + ASSERT_EQ(json_str, nullptr); +} + TEST_P(ChannelzChannelTest, BasicChannelAPIFunctionality) { grpc_core::ExecCtx exec_ctx; ChannelFixture channel(GetParam()); diff --git a/test/core/end2end/tests/channelz.cc b/test/core/end2end/tests/channelz.cc index 9766646c138..06343c46b4f 100644 --- a/test/core/end2end/tests/channelz.cc +++ b/test/core/end2end/tests/channelz.cc @@ -198,11 +198,18 @@ static void run_one_request(grpc_end2end_test_config config, static void test_channelz(grpc_end2end_test_config config) { grpc_end2end_test_fixture f; - f = begin_test(config, "test_channelz", nullptr, nullptr); + grpc_arg client_a; + client_a.type = GRPC_ARG_INTEGER; + client_a.key = const_cast(GRPC_ARG_ENABLE_CHANNELZ); + client_a.value.integer = true; + grpc_channel_args client_args = {1, &client_a}; + + f = begin_test(config, "test_channelz", &client_args, nullptr); grpc_core::channelz::ChannelNode* channelz_channel = grpc_channel_get_channelz_node(f.client); char* json = channelz_channel->RenderJSON(); + GPR_ASSERT(json != nullptr); GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"0\"")); GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"0\"")); GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"0\"")); @@ -212,6 +219,7 @@ static void test_channelz(grpc_end2end_test_config config) { run_one_request(config, f, true); json = channelz_channel->RenderJSON(); + GPR_ASSERT(json != nullptr); GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"1\"")); GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"0\"")); GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"1\"")); @@ -221,10 +229,15 @@ static void test_channelz(grpc_end2end_test_config config) { run_one_request(config, f, false); json = channelz_channel->RenderJSON(); + GPR_ASSERT(json != nullptr); gpr_log(GPR_INFO, "%s", json); GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"2\"")); GPR_ASSERT(nullptr != strstr(json, "\"callsFailed\":\"1\"")); GPR_ASSERT(nullptr != strstr(json, "\"callsSucceeded\":\"1\"")); + // channel tracing is not enables, so these should not be preset. + GPR_ASSERT(nullptr == strstr(json, "\"trace\"")); + GPR_ASSERT(nullptr == strstr(json, "\"description\":\"Channel created\"")); + GPR_ASSERT(nullptr == strstr(json, "\"severity\":\"CT_INFO\"")); gpr_free(json); end_test(&f); @@ -234,11 +247,15 @@ static void test_channelz(grpc_end2end_test_config config) { static void test_channelz_with_channel_trace(grpc_end2end_test_config config) { grpc_end2end_test_fixture f; - grpc_arg client_a; - client_a.type = GRPC_ARG_INTEGER; - client_a.key = const_cast(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE); - client_a.value.integer = 5; - grpc_channel_args client_args = {1, &client_a}; + grpc_arg client_a[2]; + client_a[0].type = GRPC_ARG_INTEGER; + client_a[0].key = + const_cast(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE); + client_a[0].value.integer = 5; + client_a[1].type = GRPC_ARG_INTEGER; + client_a[1].key = const_cast(GRPC_ARG_ENABLE_CHANNELZ); + client_a[1].value.integer = true; + grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a}; f = begin_test(config, "test_channelz_with_channel_trace", &client_args, nullptr); @@ -246,6 +263,7 @@ static void test_channelz_with_channel_trace(grpc_end2end_test_config config) { grpc_channel_get_channelz_node(f.client); char* json = channelz_channel->RenderJSON(); + GPR_ASSERT(json != nullptr); gpr_log(GPR_INFO, "%s", json); GPR_ASSERT(nullptr != strstr(json, "\"trace\"")); GPR_ASSERT(nullptr != strstr(json, "\"description\":\"Channel created\"")); @@ -255,9 +273,65 @@ static void test_channelz_with_channel_trace(grpc_end2end_test_config config) { end_test(&f); config.tear_down_data(&f); } + +static void test_channelz_disabled(grpc_end2end_test_config config) { + grpc_end2end_test_fixture f; + + f = begin_test(config, "test_channelz_disabled", nullptr, nullptr); + grpc_core::channelz::ChannelNode* channelz_channel = + grpc_channel_get_channelz_node(f.client); + char* json_str = channelz_channel->RenderJSON(); + GPR_ASSERT(json_str == nullptr); + grpc_json* json = channelz_channel->trace()->RenderJSON(); + GPR_ASSERT(json == nullptr); + // one successful request + run_one_request(config, f, true); + json_str = channelz_channel->RenderJSON(); + GPR_ASSERT(json_str == nullptr); + GPR_ASSERT(json == nullptr); + end_test(&f); + config.tear_down_data(&f); +} + +static void test_channelz_disabled_with_channel_trace( + grpc_end2end_test_config config) { + grpc_end2end_test_fixture f; + + grpc_arg client_a; + client_a.type = GRPC_ARG_INTEGER; + client_a.key = const_cast(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE); + client_a.value.integer = 5; + grpc_channel_args client_args = {1, &client_a}; + + f = begin_test(config, "test_channelz_disabled_with_channel_trace", + &client_args, nullptr); + grpc_core::channelz::ChannelNode* channelz_channel = + grpc_channel_get_channelz_node(f.client); + // channelz is disabled so rendering return null. + char* json_str = channelz_channel->RenderJSON(); + GPR_ASSERT(json_str == nullptr); + // channel trace is explicitly requested, so this works as it should + grpc_json* json = channelz_channel->trace()->RenderJSON(); + GPR_ASSERT(json != nullptr); + json_str = grpc_json_dump_to_string(json, 0); + GPR_ASSERT(json_str != nullptr); + gpr_log(GPR_INFO, "%s", json_str); + GPR_ASSERT(nullptr != + strstr(json_str, "\"description\":\"Channel created\"")); + GPR_ASSERT(nullptr != strstr(json_str, "\"severity\":\"CT_INFO\"")); + GPR_ASSERT(nullptr != strstr(json_str, "\"numEventsLogged\":")); + grpc_json_destroy(json); + gpr_free(json_str); + + end_test(&f); + config.tear_down_data(&f); +} + void channelz(grpc_end2end_test_config config) { test_channelz(config); test_channelz_with_channel_trace(config); + test_channelz_disabled(config); + test_channelz_disabled_with_channel_trace(config); } void channelz_pre_init(void) {} From 8cbd880b1ff7442f02122e97290686939cb1b337 Mon Sep 17 00:00:00 2001 From: kpayson64 Date: Tue, 12 Jun 2018 13:18:22 -0700 Subject: [PATCH 31/57] Add a null check for the endpoint on shutdown --- src/core/lib/channel/handshaker.cc | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/core/lib/channel/handshaker.cc b/src/core/lib/channel/handshaker.cc index 86f8699e044..ad3250b7e92 100644 --- a/src/core/lib/channel/handshaker.cc +++ b/src/core/lib/channel/handshaker.cc @@ -223,18 +223,23 @@ static bool call_next_handshaker_locked(grpc_handshake_manager* mgr, mgr->index == mgr->count) { if (error == GRPC_ERROR_NONE && mgr->shutdown) { error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("handshaker shutdown"); - // TODO(roth): It is currently necessary to shutdown endpoints - // before destroying then, even when we know that there are no - // pending read/write callbacks. This should be fixed, at which - // point this can be removed. - grpc_endpoint_shutdown(mgr->args.endpoint, GRPC_ERROR_REF(error)); - grpc_endpoint_destroy(mgr->args.endpoint); - mgr->args.endpoint = nullptr; - grpc_channel_args_destroy(mgr->args.args); - mgr->args.args = nullptr; - grpc_slice_buffer_destroy_internal(mgr->args.read_buffer); - gpr_free(mgr->args.read_buffer); - mgr->args.read_buffer = nullptr; + // It is possible that the endpoint has already been destroyed by + // a shutdown call while this callback was sitting on the ExecCtx + // with no error. + if (mgr->args.endpoint != nullptr) { + // TODO(roth): It is currently necessary to shutdown endpoints + // before destroying then, even when we know that there are no + // pending read/write callbacks. This should be fixed, at which + // point this can be removed. + grpc_endpoint_shutdown(mgr->args.endpoint, GRPC_ERROR_REF(error)); + grpc_endpoint_destroy(mgr->args.endpoint); + mgr->args.endpoint = nullptr; + grpc_channel_args_destroy(mgr->args.args); + mgr->args.args = nullptr; + grpc_slice_buffer_destroy_internal(mgr->args.read_buffer); + gpr_free(mgr->args.read_buffer); + mgr->args.read_buffer = nullptr; + } } if (grpc_handshaker_trace.enabled()) { gpr_log(GPR_INFO, From 537ca01c39172973effc0ccf0a92cabec8f1e70a Mon Sep 17 00:00:00 2001 From: Mehrdad Afshari Date: Fri, 15 Jun 2018 14:40:50 -0400 Subject: [PATCH 32/57] Bump v1.13.x to v1.13.0-pre2 --- BUILD | 4 ++-- build.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/BUILD b/BUILD index 0dacfd9e3cf..7cd7a50f194 100644 --- a/BUILD +++ b/BUILD @@ -66,9 +66,9 @@ config_setting( # This should be updated along with build.yaml g_stands_for = "gloriosa" -core_version = "6.0.0-pre1" +core_version = "6.0.0-pre2" -version = "1.13.0-pre1" +version = "1.13.0-pre2" GPR_PUBLIC_HDRS = [ "include/grpc/support/alloc.h", diff --git a/build.yaml b/build.yaml index 2a34681d96e..ca2057911d9 100644 --- a/build.yaml +++ b/build.yaml @@ -12,9 +12,9 @@ settings: '#08': Use "-preN" suffixes to identify pre-release versions '#09': Per-language overrides are possible with (eg) ruby_version tag here '#10': See the expand_version.py for all the quirks here - core_version: 6.0.0-pre1 + core_version: 6.0.0-pre2 g_stands_for: gloriosa - version: 1.13.0-pre1 + version: 1.13.0-pre2 filegroups: - name: alts_proto headers: From 561630dfe20a8e460b2e3aed5c55eb34cc0dc46d Mon Sep 17 00:00:00 2001 From: Mehrdad Afshari Date: Fri, 15 Jun 2018 14:49:47 -0400 Subject: [PATCH 33/57] Regenerate projects --- CMakeLists.txt | 2 +- Makefile | 6 +++--- gRPC-C++.podspec | 4 ++-- gRPC-Core.podspec | 2 +- gRPC-ProtoRPC.podspec | 2 +- gRPC-RxLibrary.podspec | 2 +- gRPC.podspec | 2 +- package.xml | 4 ++-- src/core/lib/surface/version.cc | 2 +- src/cpp/common/version_cc.cc | 2 +- src/csharp/Grpc.Core/Version.csproj.include | 2 +- src/csharp/Grpc.Core/VersionInfo.cs | 2 +- src/csharp/build_packages_dotnetcli.bat | 2 +- src/csharp/build_packages_dotnetcli.sh | 6 +++--- src/objective-c/!ProtoCompiler-gRPCPlugin.podspec | 2 +- src/objective-c/GRPCClient/private/version.h | 2 +- src/objective-c/tests/version.h | 4 ++-- src/php/ext/grpc/version.h | 2 +- src/python/grpcio/grpc/_grpcio_metadata.py | 2 +- src/python/grpcio/grpc_version.py | 2 +- src/python/grpcio_health_checking/grpc_version.py | 2 +- src/python/grpcio_reflection/grpc_version.py | 2 +- src/python/grpcio_testing/grpc_version.py | 2 +- src/python/grpcio_tests/grpc_version.py | 2 +- src/ruby/lib/grpc/version.rb | 2 +- src/ruby/tools/version.rb | 2 +- tools/distrib/python/grpcio_tools/grpc_version.py | 2 +- tools/doxygen/Doxyfile.c++ | 2 +- tools/doxygen/Doxyfile.c++.internal | 2 +- tools/doxygen/Doxyfile.core | 2 +- tools/doxygen/Doxyfile.core.internal | 2 +- 31 files changed, 38 insertions(+), 38 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b38d48ac03b..0782a227f05 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ cmake_minimum_required(VERSION 2.8) set(PACKAGE_NAME "grpc") -set(PACKAGE_VERSION "1.13.0-pre1") +set(PACKAGE_VERSION "1.13.0-pre2") set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_TARNAME "${PACKAGE_NAME}-${PACKAGE_VERSION}") set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/") diff --git a/Makefile b/Makefile index 6c9ca5211e5..17b9adcc183 100644 --- a/Makefile +++ b/Makefile @@ -420,9 +420,9 @@ E = @echo Q = @ endif -CORE_VERSION = 6.0.0-pre1 -CPP_VERSION = 1.13.0-pre1 -CSHARP_VERSION = 1.13.0-pre1 +CORE_VERSION = 6.0.0-pre2 +CPP_VERSION = 1.13.0-pre2 +CSHARP_VERSION = 1.13.0-pre2 CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES)) CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS) diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index e6fadf5d387..9fb53f76334 100644 --- a/gRPC-C++.podspec +++ b/gRPC-C++.podspec @@ -23,7 +23,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-C++' # TODO (mxyan): use version that match gRPC version when pod is stabilized - # version = '1.13.0-pre1' + # version = '1.13.0-pre2' version = '0.0.2' s.version = version s.summary = 'gRPC C++ library' @@ -31,7 +31,7 @@ Pod::Spec.new do |s| s.license = 'Apache License, Version 2.0' s.authors = { 'The gRPC contributors' => 'grpc-packages@google.com' } - grpc_version = '1.13.0-pre1' + grpc_version = '1.13.0-pre2' s.source = { :git => 'https://github.com/grpc/grpc.git', diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 45766ceec73..9b17420fd99 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -22,7 +22,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-Core' - version = '1.13.0-pre1' + version = '1.13.0-pre2' s.version = version s.summary = 'Core cross-platform gRPC library, written in C' s.homepage = 'https://grpc.io' diff --git a/gRPC-ProtoRPC.podspec b/gRPC-ProtoRPC.podspec index 59c6a09d428..fc8090a8dd4 100644 --- a/gRPC-ProtoRPC.podspec +++ b/gRPC-ProtoRPC.podspec @@ -21,7 +21,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-ProtoRPC' - version = '1.13.0-pre1' + version = '1.13.0-pre2' s.version = version s.summary = 'RPC library for Protocol Buffers, based on gRPC' s.homepage = 'https://grpc.io' diff --git a/gRPC-RxLibrary.podspec b/gRPC-RxLibrary.podspec index 81d9a2bda29..0e22082457c 100644 --- a/gRPC-RxLibrary.podspec +++ b/gRPC-RxLibrary.podspec @@ -21,7 +21,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-RxLibrary' - version = '1.13.0-pre1' + version = '1.13.0-pre2' s.version = version s.summary = 'Reactive Extensions library for iOS/OSX.' s.homepage = 'https://grpc.io' diff --git a/gRPC.podspec b/gRPC.podspec index bec5f21ab95..5d6b314abe3 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -20,7 +20,7 @@ Pod::Spec.new do |s| s.name = 'gRPC' - version = '1.13.0-pre1' + version = '1.13.0-pre2' s.version = version s.summary = 'gRPC client library for iOS/OSX' s.homepage = 'https://grpc.io' diff --git a/package.xml b/package.xml index 58c754765fd..a54985ac287 100644 --- a/package.xml +++ b/package.xml @@ -13,8 +13,8 @@ 2018-01-19 - 1.13.0RC1 - 1.13.0RC1 + 1.13.0RC2 + 1.13.0RC2 beta diff --git a/src/core/lib/surface/version.cc b/src/core/lib/surface/version.cc index 2de5e5266ed..6b562df8a76 100644 --- a/src/core/lib/surface/version.cc +++ b/src/core/lib/surface/version.cc @@ -23,6 +23,6 @@ #include -const char* grpc_version_string(void) { return "6.0.0-pre1"; } +const char* grpc_version_string(void) { return "6.0.0-pre2"; } const char* grpc_g_stands_for(void) { return "gloriosa"; } diff --git a/src/cpp/common/version_cc.cc b/src/cpp/common/version_cc.cc index 6877d8f67f5..383cd4fc421 100644 --- a/src/cpp/common/version_cc.cc +++ b/src/cpp/common/version_cc.cc @@ -22,5 +22,5 @@ #include namespace grpc { -grpc::string Version() { return "1.13.0-pre1"; } +grpc::string Version() { return "1.13.0-pre2"; } } // namespace grpc diff --git a/src/csharp/Grpc.Core/Version.csproj.include b/src/csharp/Grpc.Core/Version.csproj.include index e27bd731212..2333d7462bf 100755 --- a/src/csharp/Grpc.Core/Version.csproj.include +++ b/src/csharp/Grpc.Core/Version.csproj.include @@ -1,7 +1,7 @@ - 1.13.0-pre1 + 1.13.0-pre2 3.5.1 diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs index 2e1c0c972e7..ec04935800b 100644 --- a/src/csharp/Grpc.Core/VersionInfo.cs +++ b/src/csharp/Grpc.Core/VersionInfo.cs @@ -38,6 +38,6 @@ namespace Grpc.Core /// /// Current version of gRPC C# /// - public const string CurrentVersion = "1.13.0-pre1"; + public const string CurrentVersion = "1.13.0-pre2"; } } diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat index 8390efcff01..7a8eb6eee18 100755 --- a/src/csharp/build_packages_dotnetcli.bat +++ b/src/csharp/build_packages_dotnetcli.bat @@ -13,7 +13,7 @@ @rem limitations under the License. @rem Current package versions -set VERSION=1.13.0-pre1 +set VERSION=1.13.0-pre2 @rem Adjust the location of nuget.exe set NUGET=C:\nuget\nuget.exe diff --git a/src/csharp/build_packages_dotnetcli.sh b/src/csharp/build_packages_dotnetcli.sh index cfdbaa2518b..7b8bd135bf7 100755 --- a/src/csharp/build_packages_dotnetcli.sh +++ b/src/csharp/build_packages_dotnetcli.sh @@ -45,8 +45,8 @@ dotnet pack --configuration Release Grpc.Auth --output ../../../artifacts dotnet pack --configuration Release Grpc.HealthCheck --output ../../../artifacts dotnet pack --configuration Release Grpc.Reflection --output ../../../artifacts -nuget pack Grpc.nuspec -Version "1.13.0-pre1" -OutputDirectory ../../artifacts -nuget pack Grpc.Core.NativeDebug.nuspec -Version "1.13.0-pre1" -OutputDirectory ../../artifacts -nuget pack Grpc.Tools.nuspec -Version "1.13.0-pre1" -OutputDirectory ../../artifacts +nuget pack Grpc.nuspec -Version "1.13.0-pre2" -OutputDirectory ../../artifacts +nuget pack Grpc.Core.NativeDebug.nuspec -Version "1.13.0-pre2" -OutputDirectory ../../artifacts +nuget pack Grpc.Tools.nuspec -Version "1.13.0-pre2" -OutputDirectory ../../artifacts (cd ../../artifacts && zip csharp_nugets_dotnetcli.zip *.nupkg) diff --git a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec index f6be759b0c6..099fd66849c 100644 --- a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec +++ b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec @@ -42,7 +42,7 @@ Pod::Spec.new do |s| # exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed # before them. s.name = '!ProtoCompiler-gRPCPlugin' - v = '1.13.0-pre1' + v = '1.13.0-pre2' s.version = v s.summary = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.' s.description = <<-DESC diff --git a/src/objective-c/GRPCClient/private/version.h b/src/objective-c/GRPCClient/private/version.h index ef828518262..a2866a555e1 100644 --- a/src/objective-c/GRPCClient/private/version.h +++ b/src/objective-c/GRPCClient/private/version.h @@ -22,4 +22,4 @@ // instead. This file can be regenerated from the template by running // `tools/buildgen/generate_projects.sh`. -#define GRPC_OBJC_VERSION_STRING @"1.13.0-pre1" +#define GRPC_OBJC_VERSION_STRING @"1.13.0-pre2" diff --git a/src/objective-c/tests/version.h b/src/objective-c/tests/version.h index 4c8278dca16..b253bdf2f70 100644 --- a/src/objective-c/tests/version.h +++ b/src/objective-c/tests/version.h @@ -22,5 +22,5 @@ // instead. This file can be regenerated from the template by running // `tools/buildgen/generate_projects.sh`. -#define GRPC_OBJC_VERSION_STRING @"1.13.0-pre1" -#define GRPC_C_VERSION_STRING @"6.0.0-pre1" +#define GRPC_OBJC_VERSION_STRING @"1.13.0-pre2" +#define GRPC_C_VERSION_STRING @"6.0.0-pre2" diff --git a/src/php/ext/grpc/version.h b/src/php/ext/grpc/version.h index 1672a9706b5..7db0fce1e20 100644 --- a/src/php/ext/grpc/version.h +++ b/src/php/ext/grpc/version.h @@ -20,6 +20,6 @@ #ifndef VERSION_H #define VERSION_H -#define PHP_GRPC_VERSION "1.13.0RC1" +#define PHP_GRPC_VERSION "1.13.0RC2" #endif /* VERSION_H */ diff --git a/src/python/grpcio/grpc/_grpcio_metadata.py b/src/python/grpcio/grpc/_grpcio_metadata.py index 3150f3e4bc0..a485103d9c9 100644 --- a/src/python/grpcio/grpc/_grpcio_metadata.py +++ b/src/python/grpcio/grpc/_grpcio_metadata.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc/_grpcio_metadata.py.template`!!! -__version__ = """1.13.0rc1""" +__version__ = """1.13.0rc2""" diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py index 43a620f6e15..dfce6a1cb23 100644 --- a/src/python/grpcio/grpc_version.py +++ b/src/python/grpcio/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!! -VERSION = '1.13.0rc1' +VERSION = '1.13.0rc2' diff --git a/src/python/grpcio_health_checking/grpc_version.py b/src/python/grpcio_health_checking/grpc_version.py index c52d72a9778..ffaf8e41542 100644 --- a/src/python/grpcio_health_checking/grpc_version.py +++ b/src/python/grpcio_health_checking/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!! -VERSION = '1.13.0rc1' +VERSION = '1.13.0rc2' diff --git a/src/python/grpcio_reflection/grpc_version.py b/src/python/grpcio_reflection/grpc_version.py index 657df1e6be3..657152df2b2 100644 --- a/src/python/grpcio_reflection/grpc_version.py +++ b/src/python/grpcio_reflection/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!! -VERSION = '1.13.0rc1' +VERSION = '1.13.0rc2' diff --git a/src/python/grpcio_testing/grpc_version.py b/src/python/grpcio_testing/grpc_version.py index 345c3e6c8a9..70d297dbdde 100644 --- a/src/python/grpcio_testing/grpc_version.py +++ b/src/python/grpcio_testing/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_testing/grpc_version.py.template`!!! -VERSION = '1.13.0rc1' +VERSION = '1.13.0rc2' diff --git a/src/python/grpcio_tests/grpc_version.py b/src/python/grpcio_tests/grpc_version.py index 17e4b9d1da0..317ef73eb79 100644 --- a/src/python/grpcio_tests/grpc_version.py +++ b/src/python/grpcio_tests/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!! -VERSION = '1.13.0rc1' +VERSION = '1.13.0rc2' diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb index b5f7960b0f2..309e02bdc2a 100644 --- a/src/ruby/lib/grpc/version.rb +++ b/src/ruby/lib/grpc/version.rb @@ -14,5 +14,5 @@ # GRPC contains the General RPC module. module GRPC - VERSION = '1.13.0.pre1' + VERSION = '1.13.0.pre2' end diff --git a/src/ruby/tools/version.rb b/src/ruby/tools/version.rb index 20fdc0e36fc..e0be368327e 100644 --- a/src/ruby/tools/version.rb +++ b/src/ruby/tools/version.rb @@ -14,6 +14,6 @@ module GRPC module Tools - VERSION = '1.13.0.pre1' + VERSION = '1.13.0.pre2' end end diff --git a/tools/distrib/python/grpcio_tools/grpc_version.py b/tools/distrib/python/grpcio_tools/grpc_version.py index df98a4319a4..fdfea65794b 100644 --- a/tools/distrib/python/grpcio_tools/grpc_version.py +++ b/tools/distrib/python/grpcio_tools/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!! -VERSION = '1.13.0rc1' +VERSION = '1.13.0rc2' diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++ index e96b8def2fa..438240f39e0 100644 --- a/tools/doxygen/Doxyfile.c++ +++ b/tools/doxygen/Doxyfile.c++ @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.13.0-pre1 +PROJECT_NUMBER = 1.13.0-pre2 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 8a513f51fcd..35b64fa5975 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.13.0-pre1 +PROJECT_NUMBER = 1.13.0-pre2 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/tools/doxygen/Doxyfile.core b/tools/doxygen/Doxyfile.core index e2d4e06ec7d..d5dcb119802 100644 --- a/tools/doxygen/Doxyfile.core +++ b/tools/doxygen/Doxyfile.core @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC Core" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 6.0.0-pre1 +PROJECT_NUMBER = 6.0.0-pre2 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 26ddd87c00f..de089c3e911 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC Core" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 6.0.0-pre1 +PROJECT_NUMBER = 6.0.0-pre2 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a From 4d1da600b525a514f0a5c1d768fa3a58d65ecded Mon Sep 17 00:00:00 2001 From: ncteisen Date: Fri, 15 Jun 2018 14:54:26 -0400 Subject: [PATCH 34/57] Fix ASAN and sanity --- CMakeLists.txt | 1 + test/core/channel/channelz_test.cc | 1 + 2 files changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0fd612b5c6d..a875b8c73e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10797,6 +10797,7 @@ target_include_directories(channelz_test PRIVATE ${_gRPC_CARES_INCLUDE_DIR} PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR} PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR} PRIVATE third_party/googletest/googletest/include PRIVATE third_party/googletest/googletest PRIVATE third_party/googletest/googlemock/include diff --git a/test/core/channel/channelz_test.cc b/test/core/channel/channelz_test.cc index e1dc76e4aa5..cfd029f8fce 100644 --- a/test/core/channel/channelz_test.cc +++ b/test/core/channel/channelz_test.cc @@ -153,6 +153,7 @@ TEST(ChannelzChannelTest, ChannelzDisabled) { ChannelNode* channelz_channel = grpc_channel_get_channelz_node(channel); char* json_str = channelz_channel->RenderJSON(); ASSERT_EQ(json_str, nullptr); + grpc_channel_destroy(channel); } TEST_P(ChannelzChannelTest, BasicChannelAPIFunctionality) { From f15c6f24c1074a1e1891e4cfbac7e70b027b2eb6 Mon Sep 17 00:00:00 2001 From: ganmacs Date: Mon, 18 Jun 2018 18:59:10 +0900 Subject: [PATCH 35/57] Delete unused @metadata_tag --- src/ruby/lib/grpc/generic/active_call.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ruby/lib/grpc/generic/active_call.rb b/src/ruby/lib/grpc/generic/active_call.rb index 86240814bd1..6e601bdc917 100644 --- a/src/ruby/lib/grpc/generic/active_call.rb +++ b/src/ruby/lib/grpc/generic/active_call.rb @@ -120,7 +120,7 @@ module GRPC @send_initial_md_mutex.synchronize do return if @metadata_sent @metadata_to_send.merge!(new_metadata) - @metadata_tag = ActiveCall.client_invoke(@call, @metadata_to_send) + ActiveCall.client_invoke(@call, @metadata_to_send) @metadata_sent = true end end From 332b32555cb70f40ed15808d7194dcda7b9f9c00 Mon Sep 17 00:00:00 2001 From: Juanli Shen Date: Mon, 18 Jun 2018 15:22:04 -0700 Subject: [PATCH 36/57] Add endianness conversion for long --- src/core/lib/iomgr/socket_utils.h | 6 ++++++ src/core/lib/iomgr/socket_utils_common_posix.cc | 4 ++++ src/core/lib/iomgr/socket_utils_uv.cc | 4 ++++ src/core/lib/iomgr/socket_utils_windows.cc | 4 ++++ 4 files changed, 18 insertions(+) diff --git a/src/core/lib/iomgr/socket_utils.h b/src/core/lib/iomgr/socket_utils.h index cf1a7be6489..dba2896b742 100644 --- a/src/core/lib/iomgr/socket_utils.h +++ b/src/core/lib/iomgr/socket_utils.h @@ -29,6 +29,12 @@ uint16_t grpc_htons(uint16_t hostshort); /* A wrapper for ntohs on POSIX and WINDOWS */ uint16_t grpc_ntohs(uint16_t netshort); +/* A wrapper for htonl on POSIX and Windows */ +uint32_t grpc_htonl(uint32_t hostlong); + +/* A wrapper for ntohl on POSIX and WINDOWS */ +uint32_t grpc_ntohl(uint32_t netlong); + /* A wrapper for inet_pton on POSIX and WINDOWS */ int grpc_inet_pton(int af, const char* src, void* dst); diff --git a/src/core/lib/iomgr/socket_utils_common_posix.cc b/src/core/lib/iomgr/socket_utils_common_posix.cc index 04a17677312..069b4764377 100644 --- a/src/core/lib/iomgr/socket_utils_common_posix.cc +++ b/src/core/lib/iomgr/socket_utils_common_posix.cc @@ -339,6 +339,10 @@ uint16_t grpc_htons(uint16_t hostshort) { return htons(hostshort); } uint16_t grpc_ntohs(uint16_t netshort) { return ntohs(netshort); } +uint32_t grpc_htonl(uint32_t hostlong) { return htonl(hostlong); } + +uint32_t grpc_ntohl(uint32_t netlong) { return ntohl(netlong); } + int grpc_inet_pton(int af, const char* src, void* dst) { return inet_pton(af, src, dst); } diff --git a/src/core/lib/iomgr/socket_utils_uv.cc b/src/core/lib/iomgr/socket_utils_uv.cc index 7eba40c46bf..b5f96b52df5 100644 --- a/src/core/lib/iomgr/socket_utils_uv.cc +++ b/src/core/lib/iomgr/socket_utils_uv.cc @@ -33,6 +33,10 @@ uint16_t grpc_htons(uint16_t hostshort) { return htons(hostshort); } uint16_t grpc_ntohs(uint16_t netshort) { return ntohs(netshort); } +uint32_t grpc_htonl(uint32_t hostlong) { return htonl(hostlong); } + +uint32_t grpc_ntohl(uint32_t netlong) { return ntohl(netlong); } + int grpc_inet_pton(int af, const char* src, void* dst) { return inet_pton(af, src, dst); } diff --git a/src/core/lib/iomgr/socket_utils_windows.cc b/src/core/lib/iomgr/socket_utils_windows.cc index 3e7b5b812db..9137ab98e60 100644 --- a/src/core/lib/iomgr/socket_utils_windows.cc +++ b/src/core/lib/iomgr/socket_utils_windows.cc @@ -31,6 +31,10 @@ uint16_t grpc_htons(uint16_t hostshort) { return htons(hostshort); } uint16_t grpc_ntohs(uint16_t netshort) { return ntohs(netshort); } +uint32_t grpc_htonl(uint32_t hostlong) { return htonl(hostlong); } + +uint32_t grpc_ntohl(uint32_t netlong) { return ntohl(netlong); } + int grpc_inet_pton(int af, const char* src, void* dst) { return inet_pton(af, src, dst); } From ac1b24f55579a7ef8112b50637f43281ef7474bc Mon Sep 17 00:00:00 2001 From: Juanli Shen Date: Mon, 18 Jun 2018 16:38:58 -0700 Subject: [PATCH 37/57] TODO --- src/core/lib/iomgr/socket_utils.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/lib/iomgr/socket_utils.h b/src/core/lib/iomgr/socket_utils.h index dba2896b742..14bb081e935 100644 --- a/src/core/lib/iomgr/socket_utils.h +++ b/src/core/lib/iomgr/socket_utils.h @@ -23,6 +23,9 @@ #include +// TODO(juanlishen): The following functions might be simple enough to implement +// ourselves, so that they don't cause any portability hassle. + /* A wrapper for htons on POSIX and Windows */ uint16_t grpc_htons(uint16_t hostshort); From 5bacf2e4f6c77a2c90f41b6f6c2b62321e5ce432 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Tue, 19 Jun 2018 08:19:58 -0700 Subject: [PATCH 38/57] Allocate retry payload fields with subchannel call instead of with each batch. --- .../filters/client_channel/client_channel.cc | 129 ++++++++++-------- 1 file changed, 72 insertions(+), 57 deletions(-) diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc index 34ea97e23eb..520431e63b6 100644 --- a/src/core/ext/filters/client_channel/client_channel.cc +++ b/src/core/ext/filters/client_channel/client_channel.cc @@ -794,6 +794,15 @@ typedef struct { // The batch to use in the subchannel call. // Its payload field points to subchannel_call_retry_state.batch_payload. grpc_transport_stream_op_batch batch; + // For intercepting on_complete. + grpc_closure on_complete; +} subchannel_batch_data; + +// Retry state associated with a subchannel call. +// Stored in the parent_data of the subchannel call object. +typedef struct { + // subchannel_batch_data.batch.payload points to this. + grpc_transport_stream_op_batch_payload batch_payload; // For send_initial_metadata. // Note that we need to make a copy of the initial metadata for each // subchannel call instead of just referring to the copy in call_data, @@ -818,15 +827,6 @@ typedef struct { grpc_metadata_batch recv_trailing_metadata; grpc_transport_stream_stats collect_stats; grpc_closure recv_trailing_metadata_ready; - // For intercepting on_complete. - grpc_closure on_complete; -} subchannel_batch_data; - -// Retry state associated with a subchannel call. -// Stored in the parent_data of the subchannel call object. -typedef struct { - // subchannel_batch_data.batch.payload points to this. - grpc_transport_stream_op_batch_payload batch_payload; // These fields indicate which ops have been started and completed on // this subchannel call. size_t started_send_message_count; @@ -1524,17 +1524,21 @@ static subchannel_batch_data* batch_data_create(grpc_call_element* elem, static void batch_data_unref(subchannel_batch_data* batch_data) { if (gpr_unref(&batch_data->refs)) { - if (batch_data->send_initial_metadata_storage != nullptr) { - grpc_metadata_batch_destroy(&batch_data->send_initial_metadata); + subchannel_call_retry_state* retry_state = + static_cast( + grpc_connected_subchannel_call_get_parent_data( + batch_data->subchannel_call)); + if (batch_data->batch.send_initial_metadata) { + grpc_metadata_batch_destroy(&retry_state->send_initial_metadata); } - if (batch_data->send_trailing_metadata_storage != nullptr) { - grpc_metadata_batch_destroy(&batch_data->send_trailing_metadata); + if (batch_data->batch.send_trailing_metadata) { + grpc_metadata_batch_destroy(&retry_state->send_trailing_metadata); } if (batch_data->batch.recv_initial_metadata) { - grpc_metadata_batch_destroy(&batch_data->recv_initial_metadata); + grpc_metadata_batch_destroy(&retry_state->recv_initial_metadata); } if (batch_data->batch.recv_trailing_metadata) { - grpc_metadata_batch_destroy(&batch_data->recv_trailing_metadata); + grpc_metadata_batch_destroy(&retry_state->recv_trailing_metadata); } GRPC_SUBCHANNEL_CALL_UNREF(batch_data->subchannel_call, "batch_data_unref"); call_data* calld = static_cast(batch_data->elem->call_data); @@ -1560,8 +1564,12 @@ static void invoke_recv_initial_metadata_callback(void* arg, }); GPR_ASSERT(pending != nullptr); // Return metadata. + subchannel_call_retry_state* retry_state = + static_cast( + grpc_connected_subchannel_call_get_parent_data( + batch_data->subchannel_call)); grpc_metadata_batch_move( - &batch_data->recv_initial_metadata, + &retry_state->recv_initial_metadata, pending->batch->payload->recv_initial_metadata.recv_initial_metadata); // Update bookkeeping. // Note: Need to do this before invoking the callback, since invoking @@ -1606,7 +1614,7 @@ static void recv_initial_metadata_ready(void* arg, grpc_error* error) { // the recv_trailing_metadata_ready callback, then defer propagating this // callback back to the surface. We can evaluate whether to retry when // recv_trailing_metadata comes back. - if (GPR_UNLIKELY((batch_data->trailing_metadata_available || + if (GPR_UNLIKELY((retry_state->trailing_metadata_available || error != GRPC_ERROR_NONE) && !retry_state->completed_recv_trailing_metadata)) { if (grpc_client_channel_trace.enabled()) { @@ -1651,8 +1659,12 @@ static void invoke_recv_message_callback(void* arg, grpc_error* error) { }); GPR_ASSERT(pending != nullptr); // Return payload. + subchannel_call_retry_state* retry_state = + static_cast( + grpc_connected_subchannel_call_get_parent_data( + batch_data->subchannel_call)); *pending->batch->payload->recv_message.recv_message = - std::move(batch_data->recv_message); + std::move(retry_state->recv_message); // Update bookkeeping. // Note: Need to do this before invoking the callback, since invoking // the callback will result in yielding the call combiner. @@ -1693,7 +1705,7 @@ static void recv_message_ready(void* arg, grpc_error* error) { // callback back to the surface. We can evaluate whether to retry when // recv_trailing_metadata comes back. if (GPR_UNLIKELY( - (batch_data->recv_message == nullptr || error != GRPC_ERROR_NONE) && + (retry_state->recv_message == nullptr || error != GRPC_ERROR_NONE) && !retry_state->completed_recv_trailing_metadata)) { if (grpc_client_channel_trace.enabled()) { gpr_log(GPR_INFO, @@ -1766,8 +1778,12 @@ static void add_closure_for_recv_trailing_metadata_ready( return; } // Return metadata. + subchannel_call_retry_state* retry_state = + static_cast( + grpc_connected_subchannel_call_get_parent_data( + batch_data->subchannel_call)); grpc_metadata_batch_move( - &batch_data->recv_trailing_metadata, + &retry_state->recv_trailing_metadata, pending->batch->payload->recv_trailing_metadata.recv_trailing_metadata); // Add closure. closures->Add(pending->batch->payload->recv_trailing_metadata @@ -1788,11 +1804,11 @@ static void add_closures_for_deferred_recv_callbacks( // Add closure for deferred recv_initial_metadata_ready. if (GPR_UNLIKELY(retry_state->recv_initial_metadata_ready_deferred_batch != nullptr)) { - GRPC_CLOSURE_INIT(&batch_data->recv_initial_metadata_ready, + GRPC_CLOSURE_INIT(&retry_state->recv_initial_metadata_ready, invoke_recv_initial_metadata_callback, retry_state->recv_initial_metadata_ready_deferred_batch, grpc_schedule_on_exec_ctx); - closures->Add(&batch_data->recv_initial_metadata_ready, + closures->Add(&retry_state->recv_initial_metadata_ready, retry_state->recv_initial_metadata_error, "resuming recv_initial_metadata_ready"); retry_state->recv_initial_metadata_ready_deferred_batch = nullptr; @@ -1800,11 +1816,11 @@ static void add_closures_for_deferred_recv_callbacks( // Add closure for deferred recv_message_ready. if (GPR_UNLIKELY(retry_state->recv_message_ready_deferred_batch != nullptr)) { - GRPC_CLOSURE_INIT(&batch_data->recv_message_ready, + GRPC_CLOSURE_INIT(&retry_state->recv_message_ready, invoke_recv_message_callback, retry_state->recv_message_ready_deferred_batch, grpc_schedule_on_exec_ctx); - closures->Add(&batch_data->recv_message_ready, + closures->Add(&retry_state->recv_message_ready, retry_state->recv_message_error, "resuming recv_message_ready"); retry_state->recv_message_ready_deferred_batch = nullptr; @@ -2120,28 +2136,28 @@ static void add_retriable_send_initial_metadata_op( // // If we've already completed one or more attempts, add the // grpc-retry-attempts header. - batch_data->send_initial_metadata_storage = + retry_state->send_initial_metadata_storage = static_cast(gpr_arena_alloc( calld->arena, sizeof(grpc_linked_mdelem) * (calld->send_initial_metadata.list.count + (calld->num_attempts_completed > 0)))); grpc_metadata_batch_copy(&calld->send_initial_metadata, - &batch_data->send_initial_metadata, - batch_data->send_initial_metadata_storage); - if (GPR_UNLIKELY(batch_data->send_initial_metadata.idx.named + &retry_state->send_initial_metadata, + retry_state->send_initial_metadata_storage); + if (GPR_UNLIKELY(retry_state->send_initial_metadata.idx.named .grpc_previous_rpc_attempts != nullptr)) { - grpc_metadata_batch_remove( - &batch_data->send_initial_metadata, - batch_data->send_initial_metadata.idx.named.grpc_previous_rpc_attempts); + grpc_metadata_batch_remove(&retry_state->send_initial_metadata, + retry_state->send_initial_metadata.idx.named + .grpc_previous_rpc_attempts); } if (GPR_UNLIKELY(calld->num_attempts_completed > 0)) { grpc_mdelem retry_md = grpc_mdelem_from_slices( GRPC_MDSTR_GRPC_PREVIOUS_RPC_ATTEMPTS, *retry_count_strings[calld->num_attempts_completed - 1]); grpc_error* error = grpc_metadata_batch_add_tail( - &batch_data->send_initial_metadata, - &batch_data->send_initial_metadata_storage[calld->send_initial_metadata - .list.count], + &retry_state->send_initial_metadata, + &retry_state->send_initial_metadata_storage[calld->send_initial_metadata + .list.count], retry_md); if (GPR_UNLIKELY(error != GRPC_ERROR_NONE)) { gpr_log(GPR_ERROR, "error adding retry metadata: %s", @@ -2152,7 +2168,7 @@ static void add_retriable_send_initial_metadata_op( retry_state->started_send_initial_metadata = true; batch_data->batch.send_initial_metadata = true; batch_data->batch.payload->send_initial_metadata.send_initial_metadata = - &batch_data->send_initial_metadata; + &retry_state->send_initial_metadata; batch_data->batch.payload->send_initial_metadata.send_initial_metadata_flags = calld->send_initial_metadata_flags; batch_data->batch.payload->send_initial_metadata.peer_string = @@ -2173,10 +2189,10 @@ static void add_retriable_send_message_op( grpc_core::ByteStreamCache* cache = (*calld->send_messages)[retry_state->started_send_message_count]; ++retry_state->started_send_message_count; - batch_data->send_message.Init(cache); + retry_state->send_message.Init(cache); batch_data->batch.send_message = true; batch_data->batch.payload->send_message.send_message.reset( - batch_data->send_message.get()); + retry_state->send_message.get()); } // Adds retriable send_trailing_metadata op to batch_data. @@ -2186,17 +2202,17 @@ static void add_retriable_send_trailing_metadata_op( // We need to make a copy of the metadata batch for each attempt, since // the filters in the subchannel stack may modify this batch, and we don't // want those modifications to be passed forward to subsequent attempts. - batch_data->send_trailing_metadata_storage = + retry_state->send_trailing_metadata_storage = static_cast(gpr_arena_alloc( calld->arena, sizeof(grpc_linked_mdelem) * calld->send_trailing_metadata.list.count)); grpc_metadata_batch_copy(&calld->send_trailing_metadata, - &batch_data->send_trailing_metadata, - batch_data->send_trailing_metadata_storage); + &retry_state->send_trailing_metadata, + retry_state->send_trailing_metadata_storage); retry_state->started_send_trailing_metadata = true; batch_data->batch.send_trailing_metadata = true; batch_data->batch.payload->send_trailing_metadata.send_trailing_metadata = - &batch_data->send_trailing_metadata; + &retry_state->send_trailing_metadata; } // Adds retriable recv_initial_metadata op to batch_data. @@ -2205,16 +2221,16 @@ static void add_retriable_recv_initial_metadata_op( subchannel_batch_data* batch_data) { retry_state->started_recv_initial_metadata = true; batch_data->batch.recv_initial_metadata = true; - grpc_metadata_batch_init(&batch_data->recv_initial_metadata); + grpc_metadata_batch_init(&retry_state->recv_initial_metadata); batch_data->batch.payload->recv_initial_metadata.recv_initial_metadata = - &batch_data->recv_initial_metadata; + &retry_state->recv_initial_metadata; batch_data->batch.payload->recv_initial_metadata.trailing_metadata_available = - &batch_data->trailing_metadata_available; - GRPC_CLOSURE_INIT(&batch_data->recv_initial_metadata_ready, + &retry_state->trailing_metadata_available; + GRPC_CLOSURE_INIT(&retry_state->recv_initial_metadata_ready, recv_initial_metadata_ready, batch_data, grpc_schedule_on_exec_ctx); batch_data->batch.payload->recv_initial_metadata.recv_initial_metadata_ready = - &batch_data->recv_initial_metadata_ready; + &retry_state->recv_initial_metadata_ready; } // Adds retriable recv_message op to batch_data. @@ -2224,11 +2240,11 @@ static void add_retriable_recv_message_op( ++retry_state->started_recv_message_count; batch_data->batch.recv_message = true; batch_data->batch.payload->recv_message.recv_message = - &batch_data->recv_message; - GRPC_CLOSURE_INIT(&batch_data->recv_message_ready, recv_message_ready, + &retry_state->recv_message; + GRPC_CLOSURE_INIT(&retry_state->recv_message_ready, recv_message_ready, batch_data, grpc_schedule_on_exec_ctx); batch_data->batch.payload->recv_message.recv_message_ready = - &batch_data->recv_message_ready; + &retry_state->recv_message_ready; } // Adds retriable recv_trailing_metadata op to batch_data. @@ -2237,16 +2253,17 @@ static void add_retriable_recv_trailing_metadata_op( subchannel_batch_data* batch_data) { retry_state->started_recv_trailing_metadata = true; batch_data->batch.recv_trailing_metadata = true; - grpc_metadata_batch_init(&batch_data->recv_trailing_metadata); + grpc_metadata_batch_init(&retry_state->recv_trailing_metadata); batch_data->batch.payload->recv_trailing_metadata.recv_trailing_metadata = - &batch_data->recv_trailing_metadata; + &retry_state->recv_trailing_metadata; batch_data->batch.payload->recv_trailing_metadata.collect_stats = - &batch_data->collect_stats; - GRPC_CLOSURE_INIT(&batch_data->recv_trailing_metadata_ready, + &retry_state->collect_stats; + GRPC_CLOSURE_INIT(&retry_state->recv_trailing_metadata_ready, recv_trailing_metadata_ready, batch_data, grpc_schedule_on_exec_ctx); batch_data->batch.payload->recv_trailing_metadata - .recv_trailing_metadata_ready = &batch_data->recv_trailing_metadata_ready; + .recv_trailing_metadata_ready = + &retry_state->recv_trailing_metadata_ready; } // Helper function used to start a recv_trailing_metadata batch. This @@ -2400,11 +2417,9 @@ static void add_subchannel_batches_for_pending_batches( // started subchannel batch, since we'll propagate the // completion when it completes. if (retry_state->completed_recv_trailing_metadata) { - subchannel_batch_data* batch_data = - retry_state->recv_trailing_metadata_internal_batch; // Batches containing recv_trailing_metadata always succeed. closures->Add( - &batch_data->recv_trailing_metadata_ready, GRPC_ERROR_NONE, + &retry_state->recv_trailing_metadata_ready, GRPC_ERROR_NONE, "re-executing recv_trailing_metadata_ready to propagate " "internally triggered result"); } else { From bbdee16b992c7777476ffaba5a9df3f8c0e9f60c Mon Sep 17 00:00:00 2001 From: Jozef Izso Date: Thu, 26 Apr 2018 17:39:17 +0200 Subject: [PATCH 39/57] Allow conditional builds of grpc_csharp_ext for vcpkg manager --- templates/CMakeLists.txt.template | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/templates/CMakeLists.txt.template b/templates/CMakeLists.txt.template index a7f59e15a7b..de13d02e2a3 100644 --- a/templates/CMakeLists.txt.template +++ b/templates/CMakeLists.txt.template @@ -87,6 +87,7 @@ # Options option(gRPC_BUILD_TESTS "Build tests" OFF) option(gRPC_BUILD_CODEGEN "Build codegen" ON) + option(gRPC_BUILD_CSHARP_EXT "Build C# extensions" ON) set(gRPC_INSTALL_default ON) if (NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) @@ -298,6 +299,11 @@ if (gRPC_BUILD_TESTS) ${cc_library(lib)} endif (gRPC_BUILD_TESTS) + % elif lib.name in ['grpc_csharp_ext']: + if (gRPC_BUILD_CSHARP_EXT) + ${cc_library(lib)} + ${cc_install(lib)} + endif (gRPC_BUILD_CSHARP_EXT) % else: ${cc_library(lib)} % if not lib.build in ["tool"]: From ec4779416a1f93f52df85b417b778cf5e24a6882 Mon Sep 17 00:00:00 2001 From: Jozef Izso Date: Tue, 19 Jun 2018 17:33:48 +0200 Subject: [PATCH 40/57] Regenerate CMakeLists.txt from generate_projects.sh --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index d92d7c0558c..d6b2adc1b45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,7 @@ set(gRPC_INSTALL_SHAREDIR "share/grpc" CACHE STRING "Installation directory for # Options option(gRPC_BUILD_TESTS "Build tests" OFF) option(gRPC_BUILD_CODEGEN "Build codegen" ON) +option(gRPC_BUILD_CSHARP_EXT "Build C# extensions" ON) set(gRPC_INSTALL_default ON) if (NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) @@ -5167,6 +5168,7 @@ target_link_libraries(qps endif (gRPC_BUILD_CODEGEN) endif (gRPC_BUILD_TESTS) +if (gRPC_BUILD_CSHARP_EXT) add_library(grpc_csharp_ext SHARED src/csharp/ext/grpc_csharp_ext.c @@ -5213,6 +5215,7 @@ if (gRPC_INSTALL) ) endif() +endif (gRPC_BUILD_CSHARP_EXT) if (gRPC_BUILD_TESTS) add_library(bad_client_test From 0f20212d38f7f55229467f26293a5e2b3f39d5a0 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Tue, 19 Jun 2018 16:05:08 -0700 Subject: [PATCH 41/57] Regenerate project --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 96858473511..8d878ae7c76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7520,6 +7520,7 @@ target_include_directories(handshake_verify_peer_options PRIVATE ${_gRPC_CARES_INCLUDE_DIR} PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR} PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR} ) target_link_libraries(handshake_verify_peer_options From c0d251a10ed82144958a34b04fd7ed832764a052 Mon Sep 17 00:00:00 2001 From: Vizerai Date: Tue, 19 Jun 2018 16:21:26 -0700 Subject: [PATCH 42/57] Fixing trailing metadata ops. --- src/cpp/ext/filters/census/client_filter.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/cpp/ext/filters/census/client_filter.cc b/src/cpp/ext/filters/census/client_filter.cc index 293f4b1c253..940d42d1000 100644 --- a/src/cpp/ext/filters/census/client_filter.cc +++ b/src/cpp/ext/filters/census/client_filter.cc @@ -119,8 +119,10 @@ void CensusClientCallData::StartTransportStreamOpBatch( } if (op->recv_trailing_metadata() != nullptr) { recv_trailing_metadata_ = op->recv_trailing_metadata()->batch(); - initial_on_done_recv_trailing_metadata_ = op->on_complete(); - op->set_on_complete(&on_done_recv_trailing_metadata_); + initial_on_done_recv_trailing_metadata_ = + op->op()->payload->recv_trailing_metadata.recv_trailing_metadata_ready; + op->op()->payload->recv_trailing_metadata.recv_trailing_metadata_ready = + &on_done_recv_trailing_metadata_; } // Call next op. grpc_call_next_op(elem, op->op()); From 76283c4e572cf39fe9ce7f38495f831133720365 Mon Sep 17 00:00:00 2001 From: Noah Eisen Date: Tue, 19 Jun 2018 16:43:18 -0700 Subject: [PATCH 43/57] Fix sanitY --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6371521f6a5..ab7ae5b4003 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7511,6 +7511,7 @@ target_include_directories(handshake_verify_peer_options PRIVATE ${_gRPC_CARES_INCLUDE_DIR} PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR} PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR} ) target_link_libraries(handshake_verify_peer_options From 1ab1287ac77972bee4e2f516d81230a7f0044f14 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Tue, 19 Jun 2018 17:09:53 -0700 Subject: [PATCH 44/57] Reviewer feedback --- include/grpc/impl/codegen/grpc_types.h | 3 +- src/core/lib/channel/channelz.cc | 12 ++----- src/core/lib/channel/channelz.h | 8 +---- src/core/lib/surface/call.cc | 14 +++++--- src/core/lib/surface/channel.cc | 24 ++++++------- test/core/channel/channel_trace_test.cc | 10 +++--- test/core/channel/channelz_test.cc | 3 +- test/core/end2end/tests/channelz.cc | 46 +++---------------------- 8 files changed, 36 insertions(+), 84 deletions(-) diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h index 786c070c140..c32e99ed4c0 100644 --- a/include/grpc/impl/codegen/grpc_types.h +++ b/include/grpc/impl/codegen/grpc_types.h @@ -290,7 +290,8 @@ typedef struct { #define GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE \ "grpc.max_channel_trace_events_per_node" /** If non-zero, gRPC library will track stats and information at at per channel - * level. Disabling channelz naturally disabled channel tracing. */ + * level. Disabling channelz naturally disables channel tracing. The default + * is for channelz to be disabled. */ #define GRPC_ARG_ENABLE_CHANNELZ "grpc.enable_channelz" /** If non-zero, Cronet transport will coalesce packets to fewer frames * when possible. */ diff --git a/src/core/lib/channel/channelz.cc b/src/core/lib/channel/channelz.cc index 40c0932f3f8..3550fc0551e 100644 --- a/src/core/lib/channel/channelz.cc +++ b/src/core/lib/channel/channelz.cc @@ -89,14 +89,9 @@ grpc_json* add_num_str(grpc_json* parent, grpc_json* it, const char* name, } // namespace -ChannelNode::ChannelNode(bool enabled, grpc_channel* channel, - size_t channel_tracer_max_nodes) - : enabled_(enabled), - channel_(channel), - target_(nullptr), - channel_uuid_(-1) { +ChannelNode::ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes) + : channel_(channel), target_(nullptr), channel_uuid_(-1) { trace_.Init(channel_tracer_max_nodes); - if (!enabled_) return; target_ = UniquePtr(grpc_channel_get_target(channel_)); channel_uuid_ = ChannelzRegistry::Register(this); gpr_atm_no_barrier_store(&last_call_started_millis_, @@ -105,12 +100,10 @@ ChannelNode::ChannelNode(bool enabled, grpc_channel* channel, ChannelNode::~ChannelNode() { trace_.Destroy(); - if (!enabled_) return; ChannelzRegistry::Unregister(channel_uuid_); } void ChannelNode::RecordCallStarted() { - if (!enabled_) return; gpr_atm_no_barrier_fetch_add(&calls_started_, (gpr_atm)1); gpr_atm_no_barrier_store(&last_call_started_millis_, (gpr_atm)ExecCtx::Get()->Now()); @@ -125,7 +118,6 @@ grpc_connectivity_state ChannelNode::GetConnectivityState() { } char* ChannelNode::RenderJSON() { - if (!enabled_) return nullptr; // We need to track these three json objects to build our object grpc_json* top_level_json = grpc_json_create(GRPC_JSON_OBJECT); grpc_json* json = top_level_json; diff --git a/src/core/lib/channel/channelz.h b/src/core/lib/channel/channelz.h index 3352daccd09..2aad1e82f48 100644 --- a/src/core/lib/channel/channelz.h +++ b/src/core/lib/channel/channelz.h @@ -40,17 +40,14 @@ class ChannelNodePeer; class ChannelNode : public RefCounted { public: - ChannelNode(bool enabled, grpc_channel* channel, - size_t channel_tracer_max_nodes); + ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes); ~ChannelNode(); void RecordCallStarted(); void RecordCallFailed() { - if (!enabled_) return; gpr_atm_no_barrier_fetch_add(&calls_failed_, (gpr_atm(1))); } void RecordCallSucceeded() { - if (!enabled_) return; gpr_atm_no_barrier_fetch_add(&calls_succeeded_, (gpr_atm(1))); } @@ -59,7 +56,6 @@ class ChannelNode : public RefCounted { ChannelTrace* trace() { return trace_.get(); } void set_channel_destroyed() { - if (!enabled_) return; GPR_ASSERT(channel_ != nullptr); channel_ = nullptr; } @@ -73,8 +69,6 @@ class ChannelNode : public RefCounted { // helper for getting connectivity state. grpc_connectivity_state GetConnectivityState(); - // Not owned. Will be set to nullptr when the channel is destroyed. - const bool enabled_; grpc_channel* channel_ = nullptr; UniquePtr target_; gpr_atm calls_started_ = 0; diff --git a/src/core/lib/surface/call.cc b/src/core/lib/surface/call.cc index f94035459f0..556eb234b44 100644 --- a/src/core/lib/surface/call.cc +++ b/src/core/lib/surface/call.cc @@ -491,7 +491,9 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args, grpc_core::channelz::ChannelNode* channelz_channel = grpc_channel_get_channelz_node(call->channel); - channelz_channel->RecordCallStarted(); + if (channelz_channel != nullptr) { + channelz_channel->RecordCallStarted(); + } grpc_slice_unref_internal(path); @@ -1264,10 +1266,12 @@ static void post_batch_completion(batch_control* bctl) { } grpc_core::channelz::ChannelNode* channelz_channel = grpc_channel_get_channelz_node(call->channel); - if (*call->final_op.client.status != GRPC_STATUS_OK) { - channelz_channel->RecordCallFailed(); - } else { - channelz_channel->RecordCallSucceeded(); + if (channelz_channel != nullptr) { + if (*call->final_op.client.status != GRPC_STATUS_OK) { + channelz_channel->RecordCallFailed(); + } else { + channelz_channel->RecordCallSucceeded(); + } } GRPC_ERROR_UNREF(error); error = GRPC_ERROR_NONE; diff --git a/src/core/lib/surface/channel.cc b/src/core/lib/surface/channel.cc index b8255706058..d5d75fcb2aa 100644 --- a/src/core/lib/surface/channel.cc +++ b/src/core/lib/surface/channel.cc @@ -149,12 +149,14 @@ grpc_channel* grpc_channel_create_with_builder( } grpc_channel_args_destroy(args); - channel->channelz_channel = - grpc_core::MakeRefCounted( - channelz_enabled, channel, channel_tracer_max_nodes); - channel->channelz_channel->trace()->AddTraceEvent( - grpc_core::channelz::ChannelTrace::Severity::Info, - grpc_slice_from_static_string("Channel created")); + if (channelz_enabled) { + channel->channelz_channel = + grpc_core::MakeRefCounted( + channel, channel_tracer_max_nodes); + channel->channelz_channel->trace()->AddTraceEvent( + grpc_core::channelz::ChannelTrace::Severity::Info, + grpc_slice_from_static_string("Channel created")); + } return channel; } @@ -189,10 +191,6 @@ static grpc_channel_args* build_channel_args( return grpc_channel_args_copy_and_add(input_args, new_args, num_new_args); } -char* grpc_channel_render_channelz(grpc_channel* channel) { - return channel->channelz_channel->RenderJSON(); -} - grpc_core::channelz::ChannelNode* grpc_channel_get_channelz_node( grpc_channel* channel) { return channel->channelz_channel.get(); @@ -401,8 +399,10 @@ void grpc_channel_internal_unref(grpc_channel* c REF_ARG) { static void destroy_channel(void* arg, grpc_error* error) { grpc_channel* channel = static_cast(arg); - channel->channelz_channel->set_channel_destroyed(); - channel->channelz_channel.reset(); + if (channel->channelz_channel != nullptr) { + channel->channelz_channel->set_channel_destroyed(); + channel->channelz_channel.reset(); + } grpc_channel_stack_destroy(CHANNEL_STACK_FROM_CHANNEL(channel)); while (channel->registered_calls) { registered_call* rc = channel->registered_calls; diff --git a/test/core/channel/channel_trace_test.cc b/test/core/channel/channel_trace_test.cc index e1bde4e6d4b..bbddee3f14e 100644 --- a/test/core/channel/channel_trace_test.cc +++ b/test/core/channel/channel_trace_test.cc @@ -157,7 +157,7 @@ TEST_P(ChannelTracerTest, ComplexTest) { AddSimpleTrace(&tracer); ChannelFixture channel1(GetParam()); RefCountedPtr sc1 = - MakeRefCounted(true, channel1.channel(), GetParam()); + MakeRefCounted(channel1.channel(), GetParam()); tracer.AddTraceEventReferencingSubchannel( ChannelTrace::Severity::Info, grpc_slice_from_static_string("subchannel one created"), sc1); @@ -175,7 +175,7 @@ TEST_P(ChannelTracerTest, ComplexTest) { ValidateChannelTrace(&tracer, 5, GetParam()); ChannelFixture channel2(GetParam()); RefCountedPtr sc2 = - MakeRefCounted(true, channel2.channel(), GetParam()); + MakeRefCounted(channel2.channel(), GetParam()); tracer.AddTraceEventReferencingChannel( ChannelTrace::Severity::Info, grpc_slice_from_static_string("LB channel two created"), sc2); @@ -204,7 +204,7 @@ TEST_P(ChannelTracerTest, TestNesting) { ValidateChannelTrace(&tracer, 2, GetParam()); ChannelFixture channel1(GetParam()); RefCountedPtr sc1 = - MakeRefCounted(true, channel1.channel(), GetParam()); + MakeRefCounted(channel1.channel(), GetParam()); tracer.AddTraceEventReferencingChannel( ChannelTrace::Severity::Info, grpc_slice_from_static_string("subchannel one created"), sc1); @@ -212,7 +212,7 @@ TEST_P(ChannelTracerTest, TestNesting) { AddSimpleTrace(sc1->trace()); ChannelFixture channel2(GetParam()); RefCountedPtr conn1 = - MakeRefCounted(true, channel2.channel(), GetParam()); + MakeRefCounted(channel2.channel(), GetParam()); // nesting one level deeper. sc1->trace()->AddTraceEventReferencingSubchannel( ChannelTrace::Severity::Info, @@ -225,7 +225,7 @@ TEST_P(ChannelTracerTest, TestNesting) { ValidateChannelTrace(conn1->trace(), 1, GetParam()); ChannelFixture channel3(GetParam()); RefCountedPtr sc2 = - MakeRefCounted(true, channel3.channel(), GetParam()); + MakeRefCounted(channel3.channel(), GetParam()); tracer.AddTraceEventReferencingSubchannel( ChannelTrace::Severity::Info, grpc_slice_from_static_string("subchannel two created"), sc2); diff --git a/test/core/channel/channelz_test.cc b/test/core/channel/channelz_test.cc index cfd029f8fce..058eea914c2 100644 --- a/test/core/channel/channelz_test.cc +++ b/test/core/channel/channelz_test.cc @@ -151,8 +151,7 @@ TEST(ChannelzChannelTest, ChannelzDisabled) { grpc_channel* channel = grpc_insecure_channel_create("fake_target", nullptr, nullptr); ChannelNode* channelz_channel = grpc_channel_get_channelz_node(channel); - char* json_str = channelz_channel->RenderJSON(); - ASSERT_EQ(json_str, nullptr); + ASSERT_EQ(channelz_channel, nullptr); grpc_channel_destroy(channel); } diff --git a/test/core/end2end/tests/channelz.cc b/test/core/end2end/tests/channelz.cc index 06343c46b4f..847b900af1b 100644 --- a/test/core/end2end/tests/channelz.cc +++ b/test/core/end2end/tests/channelz.cc @@ -208,6 +208,7 @@ static void test_channelz(grpc_end2end_test_config config) { grpc_core::channelz::ChannelNode* channelz_channel = grpc_channel_get_channelz_node(f.client); + GPR_ASSERT(channelz_channel); char* json = channelz_channel->RenderJSON(); GPR_ASSERT(json != nullptr); GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"0\"")); @@ -262,6 +263,7 @@ static void test_channelz_with_channel_trace(grpc_end2end_test_config config) { grpc_core::channelz::ChannelNode* channelz_channel = grpc_channel_get_channelz_node(f.client); + GPR_ASSERT(channelz_channel); char* json = channelz_channel->RenderJSON(); GPR_ASSERT(json != nullptr); gpr_log(GPR_INFO, "%s", json); @@ -280,49 +282,10 @@ static void test_channelz_disabled(grpc_end2end_test_config config) { f = begin_test(config, "test_channelz_disabled", nullptr, nullptr); grpc_core::channelz::ChannelNode* channelz_channel = grpc_channel_get_channelz_node(f.client); - char* json_str = channelz_channel->RenderJSON(); - GPR_ASSERT(json_str == nullptr); - grpc_json* json = channelz_channel->trace()->RenderJSON(); - GPR_ASSERT(json == nullptr); + GPR_ASSERT(channelz_channel == nullptr); // one successful request run_one_request(config, f, true); - json_str = channelz_channel->RenderJSON(); - GPR_ASSERT(json_str == nullptr); - GPR_ASSERT(json == nullptr); - end_test(&f); - config.tear_down_data(&f); -} - -static void test_channelz_disabled_with_channel_trace( - grpc_end2end_test_config config) { - grpc_end2end_test_fixture f; - - grpc_arg client_a; - client_a.type = GRPC_ARG_INTEGER; - client_a.key = const_cast(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE); - client_a.value.integer = 5; - grpc_channel_args client_args = {1, &client_a}; - - f = begin_test(config, "test_channelz_disabled_with_channel_trace", - &client_args, nullptr); - grpc_core::channelz::ChannelNode* channelz_channel = - grpc_channel_get_channelz_node(f.client); - // channelz is disabled so rendering return null. - char* json_str = channelz_channel->RenderJSON(); - GPR_ASSERT(json_str == nullptr); - // channel trace is explicitly requested, so this works as it should - grpc_json* json = channelz_channel->trace()->RenderJSON(); - GPR_ASSERT(json != nullptr); - json_str = grpc_json_dump_to_string(json, 0); - GPR_ASSERT(json_str != nullptr); - gpr_log(GPR_INFO, "%s", json_str); - GPR_ASSERT(nullptr != - strstr(json_str, "\"description\":\"Channel created\"")); - GPR_ASSERT(nullptr != strstr(json_str, "\"severity\":\"CT_INFO\"")); - GPR_ASSERT(nullptr != strstr(json_str, "\"numEventsLogged\":")); - grpc_json_destroy(json); - gpr_free(json_str); - + GPR_ASSERT(channelz_channel == nullptr); end_test(&f); config.tear_down_data(&f); } @@ -331,7 +294,6 @@ void channelz(grpc_end2end_test_config config) { test_channelz(config); test_channelz_with_channel_trace(config); test_channelz_disabled(config); - test_channelz_disabled_with_channel_trace(config); } void channelz_pre_init(void) {} From 97c6648a49a618e6fee79b9d5f6e5f3af393cbec Mon Sep 17 00:00:00 2001 From: Vizerai Date: Tue, 19 Jun 2018 17:59:36 -0700 Subject: [PATCH 45/57] update --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6371521f6a5..ab7ae5b4003 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7511,6 +7511,7 @@ target_include_directories(handshake_verify_peer_options PRIVATE ${_gRPC_CARES_INCLUDE_DIR} PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR} PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR} ) target_link_libraries(handshake_verify_peer_options From db53a61b8f02571ce914071a0a1f30fc65a4d073 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 20 Jun 2018 15:06:51 +0200 Subject: [PATCH 46/57] deduplicate C++ routeguide --- examples/cpp/cpptutorial.md | 488 ----------------------------- examples/cpp/route_guide/README.md | 6 + 2 files changed, 6 insertions(+), 488 deletions(-) delete mode 100644 examples/cpp/cpptutorial.md create mode 100644 examples/cpp/route_guide/README.md diff --git a/examples/cpp/cpptutorial.md b/examples/cpp/cpptutorial.md deleted file mode 100644 index 7d98367da43..00000000000 --- a/examples/cpp/cpptutorial.md +++ /dev/null @@ -1,488 +0,0 @@ -# gRPC Basics: C++ - -This tutorial provides a basic C++ programmer's introduction to working with -gRPC. By walking through this example you'll learn how to: - -- Define a service in a `.proto` file. -- Generate server and client code using the protocol buffer compiler. -- Use the C++ gRPC API to write a simple client and server for your service. - -It assumes that you are familiar with -[protocol buffers](https://developers.google.com/protocol-buffers/docs/overview). -Note that the example in this tutorial uses the proto3 version of the protocol -buffers language, which is currently in alpha release: you can find out more in -the [proto3 language guide](https://developers.google.com/protocol-buffers/docs/proto3) -and see the [release notes](https://github.com/google/protobuf/releases) for the -new version in the protocol buffers Github repository. - -## Why use gRPC? - -Our example is a simple route mapping application that lets clients get -information about features on their route, create a summary of their route, and -exchange route information such as traffic updates with the server and other -clients. - -With gRPC we can define our service once in a `.proto` file and implement clients -and servers in any of gRPC's supported languages, which in turn can be run in -environments ranging from servers inside Google to your own tablet - all the -complexity of communication between different languages and environments is -handled for you by gRPC. We also get all the advantages of working with protocol -buffers, including efficient serialization, a simple IDL, and easy interface -updating. - -## Example code and setup - -The example code for our tutorial is in [examples/cpp/route_guide](route_guide). -You also should have the relevant tools installed to generate the server and -client interface code - if you don't already, follow the setup instructions in -[INSTALL.md](../../INSTALL.md). - -## Defining the service - -Our first step is to define the gRPC *service* and the method *request* and -*response* types using -[protocol buffers](https://developers.google.com/protocol-buffers/docs/overview). -You can see the complete `.proto` file in -[`examples/protos/route_guide.proto`](../protos/route_guide.proto). - -To define a service, you specify a named `service` in your `.proto` file: - -```protobuf -service RouteGuide { - ... -} -``` - -Then you define `rpc` methods inside your service definition, specifying their -request and response types. gRPC lets you define four kinds of service method, -all of which are used in the `RouteGuide` service: - -- A *simple RPC* where the client sends a request to the server using the stub - and waits for a response to come back, just like a normal function call. - -```protobuf - // Obtains the feature at a given position. - rpc GetFeature(Point) returns (Feature) {} -``` - -- A *server-side streaming RPC* where the client sends a request to the server - and gets a stream to read a sequence of messages back. The client reads from - the returned stream until there are no more messages. As you can see in our - example, you specify a server-side streaming method by placing the `stream` - keyword before the *response* type. - -```protobuf - // Obtains the Features available within the given Rectangle. Results are - // streamed rather than returned at once (e.g. in a response message with a - // repeated field), as the rectangle may cover a large area and contain a - // huge number of features. - rpc ListFeatures(Rectangle) returns (stream Feature) {} -``` - -- A *client-side streaming RPC* where the client writes a sequence of messages - and sends them to the server, again using a provided stream. Once the client - has finished writing the messages, it waits for the server to read them all - and return its response. You specify a client-side streaming method by placing - the `stream` keyword before the *request* type. - -```protobuf - // Accepts a stream of Points on a route being traversed, returning a - // RouteSummary when traversal is completed. - rpc RecordRoute(stream Point) returns (RouteSummary) {} -``` - -- A *bidirectional streaming RPC* where both sides send a sequence of messages - using a read-write stream. The two streams operate independently, so clients - and servers can read and write in whatever order they like: for example, the - server could wait to receive all the client messages before writing its - responses, or it could alternately read a message then write a message, or - some other combination of reads and writes. The order of messages in each - stream is preserved. You specify this type of method by placing the `stream` - keyword before both the request and the response. - -```protobuf - // Accepts a stream of RouteNotes sent while a route is being traversed, - // while receiving other RouteNotes (e.g. from other users). - rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} -``` - -Our `.proto` file also contains protocol buffer message type definitions for all -the request and response types used in our service methods - for example, here's -the `Point` message type: - -```protobuf -// Points are represented as latitude-longitude pairs in the E7 representation -// (degrees multiplied by 10**7 and rounded to the nearest integer). -// Latitudes should be in the range +/- 90 degrees and longitude should be in -// the range +/- 180 degrees (inclusive). -message Point { - int32 latitude = 1; - int32 longitude = 2; -} -``` - -## Generating client and server code - -Next we need to generate the gRPC client and server interfaces from our `.proto` -service definition. We do this using the protocol buffer compiler `protoc` with -a special gRPC C++ plugin. - -For simplicity, we've provided a [Makefile](route_guide/Makefile) that runs -`protoc` for you with the appropriate plugin, input, and output (if you want to -run this yourself, make sure you've installed protoc and followed the gRPC code -[installation instructions](../../INSTALL.md) first): - -```shell -$ make route_guide.grpc.pb.cc route_guide.pb.cc -``` - -which actually runs: - -```shell -$ protoc -I ../../protos --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` ../../protos/route_guide.proto -$ protoc -I ../../protos --cpp_out=. ../../protos/route_guide.proto -``` - -Running this command generates the following files in your current directory: -- `route_guide.pb.h`, the header which declares your generated message classes -- `route_guide.pb.cc`, which contains the implementation of your message classes -- `route_guide.grpc.pb.h`, the header which declares your generated service - classes -- `route_guide.grpc.pb.cc`, which contains the implementation of your service - classes - -These contain: -- All the protocol buffer code to populate, serialize, and retrieve our request - and response message types -- A class called `RouteGuide` that contains - - a remote interface type (or *stub*) for clients to call with the methods - defined in the `RouteGuide` service. - - two abstract interfaces for servers to implement, also with the methods - defined in the `RouteGuide` service. - - - -## Creating the server - -First let's look at how we create a `RouteGuide` server. If you're only -interested in creating gRPC clients, you can skip this section and go straight -to [Creating the client](#client) (though you might find it interesting -anyway!). - -There are two parts to making our `RouteGuide` service do its job: -- Implementing the service interface generated from our service definition: - doing the actual "work" of our service. -- Running a gRPC server to listen for requests from clients and return the - service responses. - -You can find our example `RouteGuide` server in -[route_guide/route_guide_server.cc](route_guide/route_guide_server.cc). Let's -take a closer look at how it works. - -### Implementing RouteGuide - -As you can see, our server has a `RouteGuideImpl` class that implements the -generated `RouteGuide::Service` interface: - -```cpp -class RouteGuideImpl final : public RouteGuide::Service { -... -} -``` -In this case we're implementing the *synchronous* version of `RouteGuide`, which -provides our default gRPC server behaviour. It's also possible to implement an -asynchronous interface, `RouteGuide::AsyncService`, which allows you to further -customize your server's threading behaviour, though we won't look at this in -this tutorial. - -`RouteGuideImpl` implements all our service methods. Let's look at the simplest -type first, `GetFeature`, which just gets a `Point` from the client and returns -the corresponding feature information from its database in a `Feature`. - -```cpp - Status GetFeature(ServerContext* context, const Point* point, - Feature* feature) override { - feature->set_name(GetFeatureName(*point, feature_list_)); - feature->mutable_location()->CopyFrom(*point); - return Status::OK; - } -``` - -The method is passed a context object for the RPC, the client's `Point` protocol -buffer request, and a `Feature` protocol buffer to fill in with the response -information. In the method we populate the `Feature` with the appropriate -information, and then `return` with an `OK` status to tell gRPC that we've -finished dealing with the RPC and that the `Feature` can be returned to the -client. - -Now let's look at something a bit more complicated - a streaming RPC. -`ListFeatures` is a server-side streaming RPC, so we need to send back multiple -`Feature`s to our client. - -```cpp -Status ListFeatures(ServerContext* context, const Rectangle* rectangle, - ServerWriter* writer) override { - auto lo = rectangle->lo(); - auto hi = rectangle->hi(); - long left = std::min(lo.longitude(), hi.longitude()); - long right = std::max(lo.longitude(), hi.longitude()); - long top = std::max(lo.latitude(), hi.latitude()); - long bottom = std::min(lo.latitude(), hi.latitude()); - for (const Feature& f : feature_list_) { - if (f.location().longitude() >= left && - f.location().longitude() <= right && - f.location().latitude() >= bottom && - f.location().latitude() <= top) { - writer->Write(f); - } - } - return Status::OK; -} -``` - -As you can see, instead of getting simple request and response objects in our -method parameters, this time we get a request object (the `Rectangle` in which -our client wants to find `Feature`s) and a special `ServerWriter` object. In the -method, we populate as many `Feature` objects as we need to return, writing them -to the `ServerWriter` using its `Write()` method. Finally, as in our simple RPC, -we `return Status::OK` to tell gRPC that we've finished writing responses. - -If you look at the client-side streaming method `RecordRoute` you'll see it's -quite similar, except this time we get a `ServerReader` instead of a request -object and a single response. We use the `ServerReader`s `Read()` method to -repeatedly read in our client's requests to a request object (in this case a -`Point`) until there are no more messages: the server needs to check the return -value of `Read()` after each call. If `true`, the stream is still good and it -can continue reading; if `false` the message stream has ended. - -```cpp -while (stream->Read(&point)) { - ...//process client input -} -``` -Finally, let's look at our bidirectional streaming RPC `RouteChat()`. - -```cpp - Status RouteChat(ServerContext* context, - ServerReaderWriter* stream) override { - std::vector received_notes; - RouteNote note; - while (stream->Read(¬e)) { - for (const RouteNote& n : received_notes) { - if (n.location().latitude() == note.location().latitude() && - n.location().longitude() == note.location().longitude()) { - stream->Write(n); - } - } - received_notes.push_back(note); - } - - return Status::OK; - } -``` - -This time we get a `ServerReaderWriter` that can be used to read *and* write -messages. The syntax for reading and writing here is exactly the same as for our -client-streaming and server-streaming methods. Although each side will always -get the other's messages in the order they were written, both the client and -server can read and write in any order — the streams operate completely -independently. - -### Starting the server - -Once we've implemented all our methods, we also need to start up a gRPC server -so that clients can actually use our service. The following snippet shows how we -do this for our `RouteGuide` service: - -```cpp -void RunServer(const std::string& db_path) { - std::string server_address("0.0.0.0:50051"); - RouteGuideImpl service(db_path); - - ServerBuilder builder; - builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); - builder.RegisterService(&service); - std::unique_ptr server(builder.BuildAndStart()); - std::cout << "Server listening on " << server_address << std::endl; - server->Wait(); -} -``` -As you can see, we build and start our server using a `ServerBuilder`. To do this, we: - -1. Create an instance of our service implementation class `RouteGuideImpl`. -1. Create an instance of the factory `ServerBuilder` class. -1. Specify the address and port we want to use to listen for client requests - using the builder's `AddListeningPort()` method. -1. Register our service implementation with the builder. -1. Call `BuildAndStart()` on the builder to create and start an RPC server for - our service. -1. Call `Wait()` on the server to do a blocking wait until process is killed or - `Shutdown()` is called. - - -## Creating the client - -In this section, we'll look at creating a C++ client for our `RouteGuide` -service. You can see our complete example client code in -[route_guide/route_guide_client.cc](route_guide/route_guide_client.cc). - -### Creating a stub - -To call service methods, we first need to create a *stub*. - -First we need to create a gRPC *channel* for our stub, specifying the server -address and port we want to connect to without SSL: - -```cpp -grpc::CreateChannel("localhost:50051", grpc::InsecureChannelCredentials()); -``` - -Now we can use the channel to create our stub using the `NewStub` method -provided in the `RouteGuide` class we generated from our `.proto`. - -```cpp -public: - RouteGuideClient(std::shared_ptr channel, const std::string& db) - : stub_(RouteGuide::NewStub(channel)) { - ... - } -``` - -### Calling service methods - -Now let's look at how we call our service methods. Note that in this tutorial -we're calling the *blocking/synchronous* versions of each method: this means -that the RPC call waits for the server to respond, and will either return a -response or raise an exception. - -#### Simple RPC - -Calling the simple RPC `GetFeature` is nearly as straightforward as calling a -local method. - -```cpp - Point point; - Feature feature; - point = MakePoint(409146138, -746188906); - GetOneFeature(point, &feature); - -... - - bool GetOneFeature(const Point& point, Feature* feature) { - ClientContext context; - Status status = stub_->GetFeature(&context, point, feature); - ... - } -``` - -As you can see, we create and populate a request protocol buffer object (in our -case `Point`), and create a response protocol buffer object for the server to -fill in. We also create a `ClientContext` object for our call - you can -optionally set RPC configuration values on this object, such as deadlines, -though for now we'll use the default settings. Note that you cannot reuse this -object between calls. Finally, we call the method on the stub, passing it the -context, request, and response. If the method returns `OK`, then we can read the -response information from the server from our response object. - -```cpp -std::cout << "Found feature called " << feature->name() << " at " - << feature->location().latitude()/kCoordFactor_ << ", " - << feature->location().longitude()/kCoordFactor_ << std::endl; -``` - -#### Streaming RPCs - -Now let's look at our streaming methods. If you've already read [Creating the -server](#server) some of this may look very familiar - streaming RPCs are -implemented in a similar way on both sides. Here's where we call the server-side -streaming method `ListFeatures`, which returns a stream of geographical -`Feature`s: - -```cpp -std::unique_ptr > reader( - stub_->ListFeatures(&context, rect)); -while (reader->Read(&feature)) { - std::cout << "Found feature called " - << feature.name() << " at " - << feature.location().latitude()/kCoordFactor_ << ", " - << feature.location().longitude()/kCoordFactor_ << std::endl; -} -Status status = reader->Finish(); -``` - -Instead of passing the method a context, request, and response, we pass it a -context and request and get a `ClientReader` object back. The client can use the -`ClientReader` to read the server's responses. We use the `ClientReader`s -`Read()` method to repeatedly read in the server's responses to a response -protocol buffer object (in this case a `Feature`) until there are no more -messages: the client needs to check the return value of `Read()` after each -call. If `true`, the stream is still good and it can continue reading; if -`false` the message stream has ended. Finally, we call `Finish()` on the stream -to complete the call and get our RPC status. - -The client-side streaming method `RecordRoute` is similar, except there we pass -the method a context and response object and get back a `ClientWriter`. - -```cpp - std::unique_ptr > writer( - stub_->RecordRoute(&context, &stats)); - for (int i = 0; i < kPoints; i++) { - const Feature& f = feature_list_[feature_distribution(generator)]; - std::cout << "Visiting point " - << f.location().latitude()/kCoordFactor_ << ", " - << f.location().longitude()/kCoordFactor_ << std::endl; - if (!writer->Write(f.location())) { - // Broken stream. - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds( - delay_distribution(generator))); - } - writer->WritesDone(); - Status status = writer->Finish(); - if (status.IsOk()) { - std::cout << "Finished trip with " << stats.point_count() << " points\n" - << "Passed " << stats.feature_count() << " features\n" - << "Travelled " << stats.distance() << " meters\n" - << "It took " << stats.elapsed_time() << " seconds" - << std::endl; - } else { - std::cout << "RecordRoute rpc failed." << std::endl; - } -``` - -Once we've finished writing our client's requests to the stream using `Write()`, -we need to call `WritesDone()` on the stream to let gRPC know that we've -finished writing, then `Finish()` to complete the call and get our RPC status. -If the status is `OK`, our response object that we initially passed to -`RecordRoute()` will be populated with the server's response. - -Finally, let's look at our bidirectional streaming RPC `RouteChat()`. In this -case, we just pass a context to the method and get back a `ClientReaderWriter`, -which we can use to both write and read messages. - -```cpp -std::shared_ptr > stream( - stub_->RouteChat(&context)); -``` - -The syntax for reading and writing here is exactly the same as for our -client-streaming and server-streaming methods. Although each side will always -get the other's messages in the order they were written, both the client and -server can read and write in any order — the streams operate completely -independently. - -## Try it out! - -Build client and server: -```shell -$ make -``` -Run the server, which will listen on port 50051: -```shell -$ ./route_guide_server -``` -Run the client (in a different terminal): -```shell -$ ./route_guide_client -``` diff --git a/examples/cpp/route_guide/README.md b/examples/cpp/route_guide/README.md new file mode 100644 index 00000000000..1cb5a409f87 --- /dev/null +++ b/examples/cpp/route_guide/README.md @@ -0,0 +1,6 @@ +# gRPC Basics: C++ sample code + +The files in this folder are the samples used in [gRPC Basics: C++][], +a detailed tutorial for using gRPC in C++. + +[gRPC Basics: C++]:https://grpc.io/docs/tutorials/basic/c.html From 48d03394066c48fdeb2818187eaf356135b04b6d Mon Sep 17 00:00:00 2001 From: ncteisen Date: Wed, 20 Jun 2018 08:52:27 -0700 Subject: [PATCH 47/57] reviewer feedback --- test/core/end2end/tests/channelz.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/core/end2end/tests/channelz.cc b/test/core/end2end/tests/channelz.cc index 847b900af1b..eb052119ca8 100644 --- a/test/core/end2end/tests/channelz.cc +++ b/test/core/end2end/tests/channelz.cc @@ -208,7 +208,7 @@ static void test_channelz(grpc_end2end_test_config config) { grpc_core::channelz::ChannelNode* channelz_channel = grpc_channel_get_channelz_node(f.client); - GPR_ASSERT(channelz_channel); + GPR_ASSERT(channelz_channel != nullptr); char* json = channelz_channel->RenderJSON(); GPR_ASSERT(json != nullptr); GPR_ASSERT(nullptr != strstr(json, "\"callsStarted\":\"0\"")); @@ -263,7 +263,7 @@ static void test_channelz_with_channel_trace(grpc_end2end_test_config config) { grpc_core::channelz::ChannelNode* channelz_channel = grpc_channel_get_channelz_node(f.client); - GPR_ASSERT(channelz_channel); + GPR_ASSERT(channelz_channel != nullptr); char* json = channelz_channel->RenderJSON(); GPR_ASSERT(json != nullptr); gpr_log(GPR_INFO, "%s", json); From a4fd2d183a24e931d6eca75d7f6046550b5c1bb9 Mon Sep 17 00:00:00 2001 From: Matt Kwong Date: Wed, 20 Jun 2018 09:09:21 -0700 Subject: [PATCH 48/57] Fix test failure detection when doing RBE uploads --- tools/run_tests/python_utils/upload_rbe_results.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/run_tests/python_utils/upload_rbe_results.py b/tools/run_tests/python_utils/upload_rbe_results.py index 7236227f7c3..cbeb1ad9418 100644 --- a/tools/run_tests/python_utils/upload_rbe_results.py +++ b/tools/run_tests/python_utils/upload_rbe_results.py @@ -161,7 +161,7 @@ if __name__ == "__main__": test_cases = action['testAction']['testSuite']['tests'][0][ 'testSuite']['tests'] for test_case in test_cases: - if 'errors' in test_case['testCase']: + if any(s in test_case['testCase'] for s in ['errors', 'failures']): result = 'FAILED' elif 'timedOut' in test_case['testCase']: result = 'TIMEOUT' From 258667cc1cd6885ebef701aff5222f10774eabfc Mon Sep 17 00:00:00 2001 From: Mehrdad Afshari Date: Wed, 20 Jun 2018 09:19:40 -0700 Subject: [PATCH 49/57] Build grpcio_testing in Python artifact process --- tools/run_tests/artifacts/build_artifact_python.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/run_tests/artifacts/build_artifact_python.sh b/tools/run_tests/artifacts/build_artifact_python.sh index 846a4153962..2878005bb20 100755 --- a/tools/run_tests/artifacts/build_artifact_python.sh +++ b/tools/run_tests/artifacts/build_artifact_python.sh @@ -99,12 +99,16 @@ then "${PIP}" install grpcio --no-index --find-links "file://$ARTIFACT_DIR/" "${PIP}" install grpcio-tools --no-index --find-links "file://$ARTIFACT_DIR/" - # Build gRPC health-checking source distribution + # Build grpcio_testing source distribution + ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_testing/setup.py sdist + cp -r src/python/grpcio_testing/dist/* "$ARTIFACT_DIR" + + # Build grpcio_health_checking source distribution ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_health_checking/setup.py \ preprocess build_package_protos sdist cp -r src/python/grpcio_health_checking/dist/* "$ARTIFACT_DIR" - # Build gRPC reflection source distribution + # Build grpcio_reflection source distribution ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_reflection/setup.py \ preprocess build_package_protos sdist cp -r src/python/grpcio_reflection/dist/* "$ARTIFACT_DIR" From 1a92cd0b52127bda66e9669462a17b8cce5da01a Mon Sep 17 00:00:00 2001 From: Mehrdad Afshari Date: Wed, 20 Jun 2018 09:23:14 -0700 Subject: [PATCH 50/57] More consistent source/binary Python distribtests --- test/distrib/python/test_packages.sh | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/test/distrib/python/test_packages.sh b/test/distrib/python/test_packages.sh index 6bf49d45b99..6c3a51c69dd 100755 --- a/test/distrib/python/test_packages.sh +++ b/test/distrib/python/test_packages.sh @@ -28,10 +28,11 @@ else echo "Testing Python source distribution" ARCHIVES=("$EXTERNAL_GIT_ROOT"/input_artifacts/grpcio-[0-9]*.tar.gz) TOOLS_ARCHIVES=("$EXTERNAL_GIT_ROOT"/input_artifacts/grpcio-tools-[0-9]*.tar.gz) - HEALTH_ARCHIVES=("$EXTERNAL_GIT_ROOT"/input_artifacts/grpcio-health-checking-[0-9]*.tar.gz) - REFLECTION_ARCHIVES=("$EXTERNAL_GIT_ROOT"/input_artifacts/grpcio-reflection-[0-9]*.tar.gz) fi +HEALTH_ARCHIVES=("$EXTERNAL_GIT_ROOT"/input_artifacts/grpcio-health-checking-[0-9]*.tar.gz) +REFLECTION_ARCHIVES=("$EXTERNAL_GIT_ROOT"/input_artifacts/grpcio-reflection-[0-9]*.tar.gz) + VIRTUAL_ENV=$(mktemp -d) virtualenv "$VIRTUAL_ENV" PYTHON=$VIRTUAL_ENV/bin/python @@ -53,13 +54,8 @@ function at_least_one_installs() { at_least_one_installs "${ARCHIVES[@]}" at_least_one_installs "${TOOLS_ARCHIVES[@]}" - -if [[ "$1" == "source" ]] -then - echo "Testing Python health and reflection packages" - at_least_one_installs "${HEALTH_ARCHIVES[@]}" - at_least_one_installs "${REFLECTION_ARCHIVES[@]}" -fi +at_least_one_installs "${HEALTH_ARCHIVES[@]}" +at_least_one_installs "${REFLECTION_ARCHIVES[@]}" # From 2cb912c71621194b3d4d72ffbe841a480eb24f16 Mon Sep 17 00:00:00 2001 From: Mehrdad Afshari Date: Wed, 20 Jun 2018 09:23:48 -0700 Subject: [PATCH 51/57] Add grpcio-testing to Python distribtests --- test/distrib/python/test_packages.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/distrib/python/test_packages.sh b/test/distrib/python/test_packages.sh index 6c3a51c69dd..755daa10211 100755 --- a/test/distrib/python/test_packages.sh +++ b/test/distrib/python/test_packages.sh @@ -32,6 +32,7 @@ fi HEALTH_ARCHIVES=("$EXTERNAL_GIT_ROOT"/input_artifacts/grpcio-health-checking-[0-9]*.tar.gz) REFLECTION_ARCHIVES=("$EXTERNAL_GIT_ROOT"/input_artifacts/grpcio-reflection-[0-9]*.tar.gz) +TESTING_ARCHIVES=("$EXTERNAL_GIT_ROOT"/input_artifacts/grpcio-testing-[0-9]*.tar.gz) VIRTUAL_ENV=$(mktemp -d) virtualenv "$VIRTUAL_ENV" @@ -56,6 +57,7 @@ at_least_one_installs "${ARCHIVES[@]}" at_least_one_installs "${TOOLS_ARCHIVES[@]}" at_least_one_installs "${HEALTH_ARCHIVES[@]}" at_least_one_installs "${REFLECTION_ARCHIVES[@]}" +at_least_one_installs "${TESTING_ARCHIVES[@]}" # From 650fcb6b8d4f0f8d4adfc6148d17a29790d02d5f Mon Sep 17 00:00:00 2001 From: Mehrdad Afshari Date: Wed, 20 Jun 2018 11:26:04 -0700 Subject: [PATCH 52/57] Add MANIFEST and README to grpcio_testing package --- src/python/grpcio_testing/MANIFEST.in | 3 +++ src/python/grpcio_testing/README.rst | 10 ++++++++++ 2 files changed, 13 insertions(+) create mode 100644 src/python/grpcio_testing/MANIFEST.in create mode 100644 src/python/grpcio_testing/README.rst diff --git a/src/python/grpcio_testing/MANIFEST.in b/src/python/grpcio_testing/MANIFEST.in new file mode 100644 index 00000000000..39b35652173 --- /dev/null +++ b/src/python/grpcio_testing/MANIFEST.in @@ -0,0 +1,3 @@ +include grpc_version.py +recursive-include grpc_testing *.py +global-exclude *.pyc diff --git a/src/python/grpcio_testing/README.rst b/src/python/grpcio_testing/README.rst new file mode 100644 index 00000000000..c699b80fb67 --- /dev/null +++ b/src/python/grpcio_testing/README.rst @@ -0,0 +1,10 @@ +gRPC Python Testing Package +=========================== + +Testing utilities for gRPC Python + +Dependencies +------------ + +Depends on the `grpcio` package, available from PyPI via `pip install grpcio`. + From f389e5267afe7a7f735fd7e4c2f923640d2f72c5 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 12 Jun 2018 17:26:31 +0200 Subject: [PATCH 53/57] overhaul of top-level .md files --- INSTALL.md => BUILDING.md | 110 ++-- CONCEPTS.md | 62 +++ CONTRIBUTING.md | 31 +- README.md | 120 ++--- doc/command_line_tool.md | 2 +- examples/cpp/README.md | 2 +- examples/cpp/cpptutorial.md | 488 ++++++++++++++++++ examples/cpp/helloworld/README.md | 4 +- src/cpp/README.md | 64 ++- src/csharp/README.md | 4 +- .../python_utils/filter_pull_request_tests.py | 2 +- vsprojects/.gitignore | 12 - vsprojects/README.md | 11 - 13 files changed, 724 insertions(+), 188 deletions(-) rename INSTALL.md => BUILDING.md (62%) create mode 100644 CONCEPTS.md create mode 100644 examples/cpp/cpptutorial.md delete mode 100644 vsprojects/.gitignore delete mode 100644 vsprojects/README.md diff --git a/INSTALL.md b/BUILDING.md similarity index 62% rename from INSTALL.md rename to BUILDING.md index a61af3479c6..e1d63a74613 100644 --- a/INSTALL.md +++ b/BUILDING.md @@ -1,18 +1,5 @@ -# If you are in a hurry - -For language-specific installation instructions for gRPC runtime, please -refer to these documents - - * [C++](examples/cpp): Currently to install gRPC for C++, you need to build from source as described below. - * [C#](src/csharp): NuGet package `Grpc` - * [Go](https://github.com/grpc/grpc-go): `go get google.golang.org/grpc` - * [Java](https://github.com/grpc/grpc-java) - * [Node](src/node): `npm install grpc` - * [Objective-C](src/objective-c) - * [PHP](src/php): `pecl install grpc` - * [Python](src/python/grpcio): `pip install grpcio` - * [Ruby](src/ruby): `gem install grpc` - +gRPC C++ - Building from source +=========================== # Pre-requisites @@ -28,7 +15,7 @@ If you plan to build from source and run tests, install the following as well: $ [sudo] apt-get install clang libc++-dev ``` -## macOS +## MacOS On a Mac, you will first need to install Xcode or @@ -60,6 +47,17 @@ installed by `brew` is being used: $ LIBTOOL=glibtool LIBTOOLIZE=glibtoolize make ``` +## Windows + +To prepare for cmake + Microsoft Visual C++ compiler build +- Install Visual Studio 2015 or 2017 (Visual C++ compiler will be used). +- Install [Git](https://git-scm.com/). +- Install [CMake](https://cmake.org/download/). +- Install [Active State Perl](https://www.activestate.com/activeperl/) (`choco install activeperl`) - *required by boringssl* +- Install [Go](https://golang.org/dl/) (`choco install golang`) - *required by boringssl* +- Install [yasm](http://yasm.tortall.net/) and add it to `PATH` (`choco install yasm`) - *required by boringssl* +- (Optional) Install [Ninja](https://ninja-build.org/) (`choco install ninja`) + ## Protoc By default gRPC uses [protocol buffers](https://github.com/google/protobuf), @@ -77,48 +75,49 @@ $ cd grpc/third_party/protobuf $ sudo make install # 'make' should have been run by core grpc ``` -# Build from Source +# Clone the repository (including submodules) -For developers who are interested to contribute, the following commands show how to compile the -gRPC C Core library. +Before building, you need to clone the gRPC github repository and download submodules containing source code +for gRPC's dependencies (that's done by the `submodule` command or `--recursive` flag). The following commands will clone the gRPC +repository at the latest stable version. + +## Unix ```sh $ git clone -b $(curl -L https://grpc.io/release) https://github.com/grpc/grpc $ cd grpc $ git submodule update --init - $ make - $ [sudo] make install -``` + ``` ## Windows -There are several ways to build under Windows, of varying complexity depending -on experience with the tools involved. +``` +> @rem You can also do just "git clone --recursive -b THE_BRANCH_YOU_WANT https://github.com/grpc/grpc" +> powershell git clone --recursive -b ((New-Object System.Net.WebClient).DownloadString(\"https://grpc.io/release\").Trim()) https://github.com/grpc/grpc +> cd grpc +> @rem To update submodules at later time, run "git submodule update --init" +``` +# Build from source +In the C++ world, there's no "standard" build system that would work for in all supported use cases and on all supported platforms. +Therefore, gRPC supports several major build systems, which should satisfy most users. -### Building using CMake (RECOMMENDED) +## make (on UNIX systems) -Builds gRPC C and C++ with boringssl. -- Install Visual Studio 2015 or 2017 (Visual C++ compiler will be used). -- Install [Git](https://git-scm.com/). -- Install [CMake](https://cmake.org/download/). -- Install [Active State Perl](https://www.activestate.com/activeperl/) (`choco install activeperl`) - *required by boringssl* -- Install [Go](https://golang.org/dl/) (`choco install golang`) - *required by boringssl* -- Install [yasm](http://yasm.tortall.net/) and add it to `PATH` (`choco install yasm`) - *required by boringssl* -- (Optional) Install [Ninja](https://ninja-build.org/) (`choco install ninja`) +From the grpc repository root +```sh + $ make +``` -#### Clone grpc sources including submodules -Before building, you need to clone the gRPC github repository and download submodules containing source code -for gRPC's dependencies (that's done by the `submodule` command). +## bazel + +From the grpc repository root ``` -> @rem You can also do just "git clone --recursive -b THE_BRANCH_YOU_WANT https://github.com/grpc/grpc" -> powershell git clone --recursive -b ((New-Object System.Net.WebClient).DownloadString(\"https://grpc.io/release\").Trim()) https://github.com/grpc/grpc -> cd grpc -> @rem To update submodules at later time, run "git submodule update --init" +bazel build :all ``` -#### cmake: Using Visual Studio 2015 or 2017 (can only build with OPENSSL_NO_ASM). +## cmake: Windows, Using Visual Studio 2015 or 2017 (can only build with OPENSSL_NO_ASM). When using the "Visual Studio" generator, cmake will generate a solution (`grpc.sln`) that contains a VS project for every target defined in `CMakeLists.txt` (+ few extra convenience projects @@ -132,7 +131,7 @@ you will be able to browse and build the code. > cmake --build . ``` -#### cmake: Using Ninja (faster build, supports boringssl's assembly optimizations). +## cmake: Windows, Using Ninja (faster build, supports boringssl's assembly optimizations). Please note that when using Ninja, you will still need Visual C++ (part of Visual Studio) installed to be able to compile the C/C++ sources. ``` @@ -143,30 +142,3 @@ installed to be able to compile the C/C++ sources. > cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release > cmake --build . ``` - -### msys2 (with mingw) - -The Makefile (and source code) should support msys2's mingw32 and mingw64 -compilers. Building with msys2's native compiler is possible, but -difficult. - -This approach requires having [msys2](https://msys2.github.io/) installed. - -``` -# Install prerequisites -MSYS2$ pacman -S autoconf automake gcc libtool mingw-w64-x86_64-toolchain perl pkg-config zlib -MSYS2$ pacman -S mingw-w64-x86_64-gflags -``` - -``` -# From mingw shell -MINGW64$ export CPPFLAGS="-D_WIN32_WINNT=0x0600" -MINGW64$ make -``` - -NOTE: Though most of the make targets are buildable under Mingw, some haven't been ported to Windows yet -and may fail to build (mostly trying to include POSIX headers not available on Mingw). - -### Pre-generated Visual Studio solution (DELETED) - -*WARNING: This used to be the recommended way to build on Windows, but because of significant limitations (hard to build dependencies including boringssl, .proto codegen is hard to support, ..) we are no longer providing them. Use cmake to build on Windows instead.* diff --git a/CONCEPTS.md b/CONCEPTS.md new file mode 100644 index 00000000000..6855d43d39b --- /dev/null +++ b/CONCEPTS.md @@ -0,0 +1,62 @@ +# gRPC Concepts Overview + +Remote Procedure Calls (RPCs) provide a useful abstraction for building +distributed applications and services. The libraries in this repository +provide a concrete implementation of the gRPC protocol, layered over HTTP/2. +These libraries enable communication between clients and servers using any +combination of the supported languages. + + +## Interface + +Developers using gRPC start with the description of an RPC service (a collection +of methods), and generate client and server side interfaces. The server implements +the service interface, which can be remotely invoked by the client interface. + +By default, gRPC uses [Protocol Buffers](https://github.com/google/protobuf) as the +Interface Definition Language (IDL) for describing both the service interface +and the structure of the payload messages. It is possible to use other +alternatives if desired. + +### Invoking & handling remote calls +Starting from an interface definition in a .proto file, gRPC provides +Protocol Compiler plugins that generate Client- and Server-side APIs. +gRPC users call into these APIs on the Client side and implement +the corresponding API on the server side. + +#### Synchronous vs. asynchronous +Synchronous RPC calls, that block until a response arrives from the server, are +the closest approximation to the abstraction of a procedure call that RPC +aspires to. + +On the other hand, networks are inherently asynchronous and in many scenarios, +it is desirable to have the ability to start RPCs without blocking the current +thread. + +The gRPC programming surface in most languages comes in both synchronous and +asynchronous flavors. + + +## Streaming + +gRPC supports streaming semantics, where either the client or the server (or both) +send a stream of messages on a single RPC call. The most general case is +Bidirectional Streaming where a single gRPC call establishes a stream where both +the client and the server can send a stream of messages to each other. The streamed +messages are delivered in the order they were sent. + + +# Protocol + +The [gRPC protocol](doc/PROTOCOL-HTTP2.md) specifies the abstract requirements for communication between +clients and servers. A concrete embedding over HTTP/2 completes the picture by +fleshing out the details of each of the required operations. + +## Abstract gRPC protocol +A gRPC call comprises of a bidirectional stream of messages, initiated by the client. In the client-to-server direction, this stream begins with a mandatory `Call Header`, followed by optional `Initial-Metadata`, followed by zero or more `Payload Messages`. The server-to-client direction contains an optional `Initial-Metadata`, followed by zero or more `Payload Messages` terminated with a mandatory `Status` and optional `Status-Metadata` (a.k.a.,`Trailing-Metadata`). + +## Implementation over HTTP/2 +The abstract protocol defined above is implemented over [HTTP/2](https://http2.github.io/). gRPC bidirectional streams are mapped to HTTP/2 streams. The contents of `Call Header` and `Initial Metadata` are sent as HTTP/2 headers and subject to HPACK compression. `Payload Messages` are serialized into a byte stream of length prefixed gRPC frames which are then fragmented into HTTP/2 frames at the sender and reassembled at the receiver. `Status` and `Trailing-Metadata` are sent as HTTP/2 trailing headers (a.k.a., trailers). + +## Flow Control +gRPC uses the flow control mechanism in HTTP/2. This enables fine-grained control of memory used for buffering in-flight messages. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2f90ccf2814..abd7a5eb78c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,13 +11,34 @@ In order to protect both you and ourselves, you will need to sign the [Contributor License Agreement](https://identity.linuxfoundation.org/projects/cncf). -## Running tests +## Cloning the repository -Use `tools/run_tests/run_tests.py` script to run the unit tests. See -[tools/run_tests](tools/run_tests) for how to run tests for a given language. +Before starting any development work you will need a local copy of the gRPC repository. +Please follow the instructions in [Building gRPC C++: Clone the repository](BUILDING.md#clone-the-repository-including-submodules). -Prerequisites for building and running tests are listed in -[INSTALL.md](INSTALL.md) and in `src/YOUR-LANGUAGE` (e.g. `src/csharp`) +## Building & Running tests + +Different languages use different build systems. To hide the complexity +of needing to build with many different build systems, a portable python +script that unifies the experience of building and testing gRPC in different +languages and on different platforms is provided. + +To build gRPC in the language of choice (e.g. `c++`, `csharp`, `php`, `python`, `ruby`, ...) +- Prepare you development environment based on language-specific instructions in `src/YOUR-LANGUAGE` directory. +- The language-specific instructions might involve installing C/C++ prerequisites listed in + [Building gRPC C++: Prerequisites](BUILDING.md#pre-requisites) as gRPC implementations + in this repository are using the native gRPC "core" library internally. +- Run + ``` + python tools/run_tests/run_tests.py -l YOUR_LANGUAGE --build_only + ``` +- To also run all the unit tests after building + ``` + python tools/run_tests/run_tests.py -l YOUR_LANGUAGE + ``` + +You can also run `python tools/run_tests/run_tests.py --help` to discover useful command line flags supported. For more details, +see [tools/run_tests](tools/run_tests) where you will also find guidance on how to run various other test suites (e.g. interop tests, benchmarks) ## Generated project files diff --git a/README.md b/README.md index 21a9910e3ef..23964e7fc63 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,59 @@ -[gRPC - An RPC library and framework](http://github.com/grpc/grpc) +gRPC - An RPC library and framework =================================== +gRPC is a modern, open source, high-performance remote procedure call (RPC) framework that can run anywhere. It enables client and server applications to communicate transparently, and makes it easier to build connected systems. + + + + + + + + + + +
Homepage:grpc.io
Mailing List:grpc-io@googlegroups.com
+ [![Join the chat at https://gitter.im/grpc/grpc](https://badges.gitter.im/grpc/grpc.svg)](https://gitter.im/grpc/grpc?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -Copyright 2015 -[The gRPC Authors](https://github.com/grpc/grpc/blob/master/AUTHORS) +# To start using gRPC + +To maximize usability, gRPC supports the standard way of adding dependencies in your language of choice (if there is one). +In most languages, the gRPC runtime comes in form of a package available in your language's package manager. + +For instructions on how to use the language-specific gRPC runtime in your project, please refer to these documents -# Documentation + * [C++](src/cpp): follow the instructions under the `src/cpp` directory + * [C#](src/csharp): NuGet package `Grpc` + * [Dart](https://github.com/grpc/grpc-dart): pub package `grpc` + * [Go](https://github.com/grpc/grpc-go): `go get google.golang.org/grpc` + * [Java](https://github.com/grpc/grpc-java): Use JARs from Maven Central Repository + * [Node](https://github.com/grpc/grpc-node): `npm install grpc` + * [Objective-C](src/objective-c): Add `gRPC-ProtoRPC` dependency to podspec + * [PHP](src/php): `pecl install grpc` + * [Python](src/python/grpcio): `pip install grpcio` + * [Ruby](src/ruby): `gem install grpc` + * [WebJS](https://github.com/grpc/grpc-web): follow the grpc-web instructions -You can find more detailed documentation and examples in the [doc](doc) and [examples](examples) directories respectively. +You can find per-language quickstart guides and tutorials in [Documentation section on grpc.io website](https://grpc.io/docs/). The code examples are available in the [examples](examples) directory. -# Installation & Testing +# To start developing gRPC -See [INSTALL](INSTALL.md) for installation instructions for various platforms. +Contributions are welcome! -See [tools/run_tests](tools/run_tests) for more guidance on how to run various test suites (e.g. unit tests, interop tests, benchmarks) +Please read [How to contribute](CONTRIBUTING.md) which will guide you through the entire workflow of how to build the source code, how to run the tests and how to contribute your changes to +the gRPC codebase. +The document also contains info on how the contributing process works and contains best practices for creating contributions. + +# Performance See [Performance dashboard](http://performance-dot-grpc-testing.appspot.com/explore?dashboard=5636470266134528) for the performance numbers for the latest released version. -# Repository Structure & Status +# Concepts + +See [gRPC Concepts](CONCEPTS.md) + +# About This Repository This repository contains source code for gRPC libraries for multiple languages written on top of shared C core library [src/core](src/core). @@ -42,70 +77,3 @@ Libraries in different languages may be in different states of development. We a | WebJS | [grpc-web](https://github.com/grpc/grpc-web) | | Dart | [grpc-dart](https://github.com/grpc/grpc-dart) | -See [MANIFEST.md](MANIFEST.md) for a listing of top-level items in the -repository. - -# Overview - - -Remote Procedure Calls (RPCs) provide a useful abstraction for building -distributed applications and services. The libraries in this repository -provide a concrete implementation of the gRPC protocol, layered over HTTP/2. -These libraries enable communication between clients and servers using any -combination of the supported languages. - - -## Interface - - -Developers using gRPC typically start with the description of an RPC service -(a collection of methods), and generate client and server side interfaces -which they use on the client-side and implement on the server side. - -By default, gRPC uses [Protocol Buffers](https://github.com/google/protobuf) as the -Interface Definition Language (IDL) for describing both the service interface -and the structure of the payload messages. It is possible to use other -alternatives if desired. - -### Surface API -Starting from an interface definition in a .proto file, gRPC provides -Protocol Compiler plugins that generate Client- and Server-side APIs. -gRPC users typically call into these APIs on the Client side and implement -the corresponding API on the server side. - -#### Synchronous vs. asynchronous -Synchronous RPC calls, that block until a response arrives from the server, are -the closest approximation to the abstraction of a procedure call that RPC -aspires to. - -On the other hand, networks are inherently asynchronous and in many scenarios, -it is desirable to have the ability to start RPCs without blocking the current -thread. - -The gRPC programming surface in most languages comes in both synchronous and -asynchronous flavors. - - -## Streaming - -gRPC supports streaming semantics, where either the client or the server (or both) -send a stream of messages on a single RPC call. The most general case is -Bidirectional Streaming where a single gRPC call establishes a stream where both -the client and the server can send a stream of messages to each other. The streamed -messages are delivered in the order they were sent. - - -# Protocol - -The [gRPC protocol](doc/PROTOCOL-HTTP2.md) specifies the abstract requirements for communication between -clients and servers. A concrete embedding over HTTP/2 completes the picture by -fleshing out the details of each of the required operations. - -## Abstract gRPC protocol -A gRPC RPC comprises of a bidirectional stream of messages, initiated by the client. In the client-to-server direction, this stream begins with a mandatory `Call Header`, followed by optional `Initial-Metadata`, followed by zero or more `Payload Messages`. The server-to-client direction contains an optional `Initial-Metadata`, followed by zero or more `Payload Messages` terminated with a mandatory `Status` and optional `Status-Metadata` (a.k.a.,`Trailing-Metadata`). - -## Implementation over HTTP/2 -The abstract protocol defined above is implemented over [HTTP/2](https://http2.github.io/). gRPC bidirectional streams are mapped to HTTP/2 streams. The contents of `Call Header` and `Initial Metadata` are sent as HTTP/2 headers and subject to HPACK compression. `Payload Messages` are serialized into a byte stream of length prefixed gRPC frames which are then fragmented into HTTP/2 frames at the sender and reassembled at the receiver. `Status` and `Trailing-Metadata` are sent as HTTP/2 trailing headers (a.k.a., trailers). - -## Flow Control -gRPC inherits the flow control mechanisms in HTTP/2 and uses them to enable fine-grained control of the amount of memory used for buffering in-flight messages. diff --git a/doc/command_line_tool.md b/doc/command_line_tool.md index 082e6402eb8..6337acaf60a 100644 --- a/doc/command_line_tool.md +++ b/doc/command_line_tool.md @@ -32,7 +32,7 @@ The command line tool should support the following things: To use the tool, you need to get the grpc repository and make sure your system has the prerequisites for building grpc from source, given in the [installation -instructions](https://github.com/grpc/grpc/blob/master/INSTALL.md). +instructions](../BUILDING.md). In order to build the grpc command line tool from a fresh clone of the grpc repository, you need to run the following command to update submodules: diff --git a/examples/cpp/README.md b/examples/cpp/README.md index 8e2bb5d13b1..0e358bf9a22 100644 --- a/examples/cpp/README.md +++ b/examples/cpp/README.md @@ -3,7 +3,7 @@ ## Installation To install gRPC on your system, follow the instructions to build from source -[here](../../INSTALL.md). This also installs the protocol buffer compiler +[here](../../BUILDING.md). This also installs the protocol buffer compiler `protoc` (if you don't have it already), and the C++ gRPC plugin for `protoc`. ## Hello C++ gRPC! diff --git a/examples/cpp/cpptutorial.md b/examples/cpp/cpptutorial.md new file mode 100644 index 00000000000..c40676de134 --- /dev/null +++ b/examples/cpp/cpptutorial.md @@ -0,0 +1,488 @@ +# gRPC Basics: C++ + +This tutorial provides a basic C++ programmer's introduction to working with +gRPC. By walking through this example you'll learn how to: + +- Define a service in a `.proto` file. +- Generate server and client code using the protocol buffer compiler. +- Use the C++ gRPC API to write a simple client and server for your service. + +It assumes that you are familiar with +[protocol buffers](https://developers.google.com/protocol-buffers/docs/overview). +Note that the example in this tutorial uses the proto3 version of the protocol +buffers language, which is currently in alpha release: you can find out more in +the [proto3 language guide](https://developers.google.com/protocol-buffers/docs/proto3) +and see the [release notes](https://github.com/google/protobuf/releases) for the +new version in the protocol buffers Github repository. + +## Why use gRPC? + +Our example is a simple route mapping application that lets clients get +information about features on their route, create a summary of their route, and +exchange route information such as traffic updates with the server and other +clients. + +With gRPC we can define our service once in a `.proto` file and implement clients +and servers in any of gRPC's supported languages, which in turn can be run in +environments ranging from servers inside Google to your own tablet - all the +complexity of communication between different languages and environments is +handled for you by gRPC. We also get all the advantages of working with protocol +buffers, including efficient serialization, a simple IDL, and easy interface +updating. + +## Example code and setup + +The example code for our tutorial is in [examples/cpp/route_guide](route_guide). +You also should have the relevant tools installed to generate the server and +client interface code - if you don't already, follow the setup instructions in +[BUILDING.md](../../BUILDING.md). + +## Defining the service + +Our first step is to define the gRPC *service* and the method *request* and +*response* types using +[protocol buffers](https://developers.google.com/protocol-buffers/docs/overview). +You can see the complete `.proto` file in +[`examples/protos/route_guide.proto`](../protos/route_guide.proto). + +To define a service, you specify a named `service` in your `.proto` file: + +```protobuf +service RouteGuide { + ... +} +``` + +Then you define `rpc` methods inside your service definition, specifying their +request and response types. gRPC lets you define four kinds of service method, +all of which are used in the `RouteGuide` service: + +- A *simple RPC* where the client sends a request to the server using the stub + and waits for a response to come back, just like a normal function call. + +```protobuf + // Obtains the feature at a given position. + rpc GetFeature(Point) returns (Feature) {} +``` + +- A *server-side streaming RPC* where the client sends a request to the server + and gets a stream to read a sequence of messages back. The client reads from + the returned stream until there are no more messages. As you can see in our + example, you specify a server-side streaming method by placing the `stream` + keyword before the *response* type. + +```protobuf + // Obtains the Features available within the given Rectangle. Results are + // streamed rather than returned at once (e.g. in a response message with a + // repeated field), as the rectangle may cover a large area and contain a + // huge number of features. + rpc ListFeatures(Rectangle) returns (stream Feature) {} +``` + +- A *client-side streaming RPC* where the client writes a sequence of messages + and sends them to the server, again using a provided stream. Once the client + has finished writing the messages, it waits for the server to read them all + and return its response. You specify a client-side streaming method by placing + the `stream` keyword before the *request* type. + +```protobuf + // Accepts a stream of Points on a route being traversed, returning a + // RouteSummary when traversal is completed. + rpc RecordRoute(stream Point) returns (RouteSummary) {} +``` + +- A *bidirectional streaming RPC* where both sides send a sequence of messages + using a read-write stream. The two streams operate independently, so clients + and servers can read and write in whatever order they like: for example, the + server could wait to receive all the client messages before writing its + responses, or it could alternately read a message then write a message, or + some other combination of reads and writes. The order of messages in each + stream is preserved. You specify this type of method by placing the `stream` + keyword before both the request and the response. + +```protobuf + // Accepts a stream of RouteNotes sent while a route is being traversed, + // while receiving other RouteNotes (e.g. from other users). + rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} +``` + +Our `.proto` file also contains protocol buffer message type definitions for all +the request and response types used in our service methods - for example, here's +the `Point` message type: + +```protobuf +// Points are represented as latitude-longitude pairs in the E7 representation +// (degrees multiplied by 10**7 and rounded to the nearest integer). +// Latitudes should be in the range +/- 90 degrees and longitude should be in +// the range +/- 180 degrees (inclusive). +message Point { + int32 latitude = 1; + int32 longitude = 2; +} +``` + +## Generating client and server code + +Next we need to generate the gRPC client and server interfaces from our `.proto` +service definition. We do this using the protocol buffer compiler `protoc` with +a special gRPC C++ plugin. + +For simplicity, we've provided a [Makefile](route_guide/Makefile) that runs +`protoc` for you with the appropriate plugin, input, and output (if you want to +run this yourself, make sure you've installed protoc and followed the gRPC code +[installation instructions](../../BUILDING.md) first): + +```shell +$ make route_guide.grpc.pb.cc route_guide.pb.cc +``` + +which actually runs: + +```shell +$ protoc -I ../../protos --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` ../../protos/route_guide.proto +$ protoc -I ../../protos --cpp_out=. ../../protos/route_guide.proto +``` + +Running this command generates the following files in your current directory: +- `route_guide.pb.h`, the header which declares your generated message classes +- `route_guide.pb.cc`, which contains the implementation of your message classes +- `route_guide.grpc.pb.h`, the header which declares your generated service + classes +- `route_guide.grpc.pb.cc`, which contains the implementation of your service + classes + +These contain: +- All the protocol buffer code to populate, serialize, and retrieve our request + and response message types +- A class called `RouteGuide` that contains + - a remote interface type (or *stub*) for clients to call with the methods + defined in the `RouteGuide` service. + - two abstract interfaces for servers to implement, also with the methods + defined in the `RouteGuide` service. + + + +## Creating the server + +First let's look at how we create a `RouteGuide` server. If you're only +interested in creating gRPC clients, you can skip this section and go straight +to [Creating the client](#client) (though you might find it interesting +anyway!). + +There are two parts to making our `RouteGuide` service do its job: +- Implementing the service interface generated from our service definition: + doing the actual "work" of our service. +- Running a gRPC server to listen for requests from clients and return the + service responses. + +You can find our example `RouteGuide` server in +[route_guide/route_guide_server.cc](route_guide/route_guide_server.cc). Let's +take a closer look at how it works. + +### Implementing RouteGuide + +As you can see, our server has a `RouteGuideImpl` class that implements the +generated `RouteGuide::Service` interface: + +```cpp +class RouteGuideImpl final : public RouteGuide::Service { +... +} +``` +In this case we're implementing the *synchronous* version of `RouteGuide`, which +provides our default gRPC server behaviour. It's also possible to implement an +asynchronous interface, `RouteGuide::AsyncService`, which allows you to further +customize your server's threading behaviour, though we won't look at this in +this tutorial. + +`RouteGuideImpl` implements all our service methods. Let's look at the simplest +type first, `GetFeature`, which just gets a `Point` from the client and returns +the corresponding feature information from its database in a `Feature`. + +```cpp + Status GetFeature(ServerContext* context, const Point* point, + Feature* feature) override { + feature->set_name(GetFeatureName(*point, feature_list_)); + feature->mutable_location()->CopyFrom(*point); + return Status::OK; + } +``` + +The method is passed a context object for the RPC, the client's `Point` protocol +buffer request, and a `Feature` protocol buffer to fill in with the response +information. In the method we populate the `Feature` with the appropriate +information, and then `return` with an `OK` status to tell gRPC that we've +finished dealing with the RPC and that the `Feature` can be returned to the +client. + +Now let's look at something a bit more complicated - a streaming RPC. +`ListFeatures` is a server-side streaming RPC, so we need to send back multiple +`Feature`s to our client. + +```cpp +Status ListFeatures(ServerContext* context, const Rectangle* rectangle, + ServerWriter* writer) override { + auto lo = rectangle->lo(); + auto hi = rectangle->hi(); + long left = std::min(lo.longitude(), hi.longitude()); + long right = std::max(lo.longitude(), hi.longitude()); + long top = std::max(lo.latitude(), hi.latitude()); + long bottom = std::min(lo.latitude(), hi.latitude()); + for (const Feature& f : feature_list_) { + if (f.location().longitude() >= left && + f.location().longitude() <= right && + f.location().latitude() >= bottom && + f.location().latitude() <= top) { + writer->Write(f); + } + } + return Status::OK; +} +``` + +As you can see, instead of getting simple request and response objects in our +method parameters, this time we get a request object (the `Rectangle` in which +our client wants to find `Feature`s) and a special `ServerWriter` object. In the +method, we populate as many `Feature` objects as we need to return, writing them +to the `ServerWriter` using its `Write()` method. Finally, as in our simple RPC, +we `return Status::OK` to tell gRPC that we've finished writing responses. + +If you look at the client-side streaming method `RecordRoute` you'll see it's +quite similar, except this time we get a `ServerReader` instead of a request +object and a single response. We use the `ServerReader`s `Read()` method to +repeatedly read in our client's requests to a request object (in this case a +`Point`) until there are no more messages: the server needs to check the return +value of `Read()` after each call. If `true`, the stream is still good and it +can continue reading; if `false` the message stream has ended. + +```cpp +while (stream->Read(&point)) { + ...//process client input +} +``` +Finally, let's look at our bidirectional streaming RPC `RouteChat()`. + +```cpp + Status RouteChat(ServerContext* context, + ServerReaderWriter* stream) override { + std::vector received_notes; + RouteNote note; + while (stream->Read(¬e)) { + for (const RouteNote& n : received_notes) { + if (n.location().latitude() == note.location().latitude() && + n.location().longitude() == note.location().longitude()) { + stream->Write(n); + } + } + received_notes.push_back(note); + } + + return Status::OK; + } +``` + +This time we get a `ServerReaderWriter` that can be used to read *and* write +messages. The syntax for reading and writing here is exactly the same as for our +client-streaming and server-streaming methods. Although each side will always +get the other's messages in the order they were written, both the client and +server can read and write in any order — the streams operate completely +independently. + +### Starting the server + +Once we've implemented all our methods, we also need to start up a gRPC server +so that clients can actually use our service. The following snippet shows how we +do this for our `RouteGuide` service: + +```cpp +void RunServer(const std::string& db_path) { + std::string server_address("0.0.0.0:50051"); + RouteGuideImpl service(db_path); + + ServerBuilder builder; + builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); + builder.RegisterService(&service); + std::unique_ptr server(builder.BuildAndStart()); + std::cout << "Server listening on " << server_address << std::endl; + server->Wait(); +} +``` +As you can see, we build and start our server using a `ServerBuilder`. To do this, we: + +1. Create an instance of our service implementation class `RouteGuideImpl`. +1. Create an instance of the factory `ServerBuilder` class. +1. Specify the address and port we want to use to listen for client requests + using the builder's `AddListeningPort()` method. +1. Register our service implementation with the builder. +1. Call `BuildAndStart()` on the builder to create and start an RPC server for + our service. +1. Call `Wait()` on the server to do a blocking wait until process is killed or + `Shutdown()` is called. + + +## Creating the client + +In this section, we'll look at creating a C++ client for our `RouteGuide` +service. You can see our complete example client code in +[route_guide/route_guide_client.cc](route_guide/route_guide_client.cc). + +### Creating a stub + +To call service methods, we first need to create a *stub*. + +First we need to create a gRPC *channel* for our stub, specifying the server +address and port we want to connect to without SSL: + +```cpp +grpc::CreateChannel("localhost:50051", grpc::InsecureChannelCredentials()); +``` + +Now we can use the channel to create our stub using the `NewStub` method +provided in the `RouteGuide` class we generated from our `.proto`. + +```cpp +public: + RouteGuideClient(std::shared_ptr channel, const std::string& db) + : stub_(RouteGuide::NewStub(channel)) { + ... + } +``` + +### Calling service methods + +Now let's look at how we call our service methods. Note that in this tutorial +we're calling the *blocking/synchronous* versions of each method: this means +that the RPC call waits for the server to respond, and will either return a +response or raise an exception. + +#### Simple RPC + +Calling the simple RPC `GetFeature` is nearly as straightforward as calling a +local method. + +```cpp + Point point; + Feature feature; + point = MakePoint(409146138, -746188906); + GetOneFeature(point, &feature); + +... + + bool GetOneFeature(const Point& point, Feature* feature) { + ClientContext context; + Status status = stub_->GetFeature(&context, point, feature); + ... + } +``` + +As you can see, we create and populate a request protocol buffer object (in our +case `Point`), and create a response protocol buffer object for the server to +fill in. We also create a `ClientContext` object for our call - you can +optionally set RPC configuration values on this object, such as deadlines, +though for now we'll use the default settings. Note that you cannot reuse this +object between calls. Finally, we call the method on the stub, passing it the +context, request, and response. If the method returns `OK`, then we can read the +response information from the server from our response object. + +```cpp +std::cout << "Found feature called " << feature->name() << " at " + << feature->location().latitude()/kCoordFactor_ << ", " + << feature->location().longitude()/kCoordFactor_ << std::endl; +``` + +#### Streaming RPCs + +Now let's look at our streaming methods. If you've already read [Creating the +server](#server) some of this may look very familiar - streaming RPCs are +implemented in a similar way on both sides. Here's where we call the server-side +streaming method `ListFeatures`, which returns a stream of geographical +`Feature`s: + +```cpp +std::unique_ptr > reader( + stub_->ListFeatures(&context, rect)); +while (reader->Read(&feature)) { + std::cout << "Found feature called " + << feature.name() << " at " + << feature.location().latitude()/kCoordFactor_ << ", " + << feature.location().longitude()/kCoordFactor_ << std::endl; +} +Status status = reader->Finish(); +``` + +Instead of passing the method a context, request, and response, we pass it a +context and request and get a `ClientReader` object back. The client can use the +`ClientReader` to read the server's responses. We use the `ClientReader`s +`Read()` method to repeatedly read in the server's responses to a response +protocol buffer object (in this case a `Feature`) until there are no more +messages: the client needs to check the return value of `Read()` after each +call. If `true`, the stream is still good and it can continue reading; if +`false` the message stream has ended. Finally, we call `Finish()` on the stream +to complete the call and get our RPC status. + +The client-side streaming method `RecordRoute` is similar, except there we pass +the method a context and response object and get back a `ClientWriter`. + +```cpp + std::unique_ptr > writer( + stub_->RecordRoute(&context, &stats)); + for (int i = 0; i < kPoints; i++) { + const Feature& f = feature_list_[feature_distribution(generator)]; + std::cout << "Visiting point " + << f.location().latitude()/kCoordFactor_ << ", " + << f.location().longitude()/kCoordFactor_ << std::endl; + if (!writer->Write(f.location())) { + // Broken stream. + break; + } + std::this_thread::sleep_for(std::chrono::milliseconds( + delay_distribution(generator))); + } + writer->WritesDone(); + Status status = writer->Finish(); + if (status.IsOk()) { + std::cout << "Finished trip with " << stats.point_count() << " points\n" + << "Passed " << stats.feature_count() << " features\n" + << "Travelled " << stats.distance() << " meters\n" + << "It took " << stats.elapsed_time() << " seconds" + << std::endl; + } else { + std::cout << "RecordRoute rpc failed." << std::endl; + } +``` + +Once we've finished writing our client's requests to the stream using `Write()`, +we need to call `WritesDone()` on the stream to let gRPC know that we've +finished writing, then `Finish()` to complete the call and get our RPC status. +If the status is `OK`, our response object that we initially passed to +`RecordRoute()` will be populated with the server's response. + +Finally, let's look at our bidirectional streaming RPC `RouteChat()`. In this +case, we just pass a context to the method and get back a `ClientReaderWriter`, +which we can use to both write and read messages. + +```cpp +std::shared_ptr > stream( + stub_->RouteChat(&context)); +``` + +The syntax for reading and writing here is exactly the same as for our +client-streaming and server-streaming methods. Although each side will always +get the other's messages in the order they were written, both the client and +server can read and write in any order — the streams operate completely +independently. + +## Try it out! + +Build client and server: +```shell +$ make +``` +Run the server, which will listen on port 50051: +```shell +$ ./route_guide_server +``` +Run the client (in a different terminal): +```shell +$ ./route_guide_client +``` diff --git a/examples/cpp/helloworld/README.md b/examples/cpp/helloworld/README.md index 18d3d79dcce..c598658b1d7 100644 --- a/examples/cpp/helloworld/README.md +++ b/examples/cpp/helloworld/README.md @@ -1,8 +1,8 @@ # gRPC C++ Hello World Tutorial ### Install gRPC -Make sure you have installed gRPC on your system. Follow the instructions here: -[https://github.com/grpc/grpc/blob/master/INSTALL](../../../INSTALL.md). +Make sure you have installed gRPC on your system. Follow the +[BUILDING.md](../../../BUILDING.md) instructions. ### Get the tutorial source code diff --git a/src/cpp/README.md b/src/cpp/README.md index ac76bf74ed2..f16cab1f448 100644 --- a/src/cpp/README.md +++ b/src/cpp/README.md @@ -1,13 +1,62 @@ # Overview -This directory contains source code for C++ implementation of gRPC. +A C++ implementation of gRPC -To install gRPC for C++ on your system, follow the instructions to build from source -[here](../../INSTALL.md). This also installs the protocol buffer compiler -`protoc` (if you don't have it already), and the C++ gRPC plugin for `protoc`. +# To start using gRPC C++ -# Documentation +In the C++ world, there's no universally accepted standard for managing project dependencies. +Therefore, gRPC supports several major build systems, which should satisfy most users. + +## bazel + +We recommend using Bazel for projects that use gRPC as it will give you the best developer experience +(easy handling of dependencies that support bazel & fast builds). + +To add gRPC as a dependency in bazel: +1. determine commit SHA for the grpc release you want to use +2. Use the [http_archive](https://docs.bazel.build/versions/master/be/workspace.html#http_archive) bazel rule to include gRPC source + ``` + http_archive( + name = "grpc", + urls = [ + "https://github.com/grpc/grpc/archive/YOUR_GRPC_COMMIT_SHA.tar.gz", + ], + strip_prefix = "grpc-YOUR_GRPC_COMMIT_SHA", + ) + ``` + +NOTE: currently bazel is only supported for building gRPC on Linux. + +## make + +Currently the default choice for building on UNIX based systems is `make`. + +To install gRPC for C++ on your system using `make`, follow the [Building gRPC C++](../../BUILDING.md) +instructions to build from source and then install locally using `make install`. +This also installs the protocol buffer compiler `protoc` (if you don't have it already), +and the C++ gRPC plugin for `protoc`. + +WARNING: After installing with `make install` there is no easy way to uninstall, which can cause issues +if you later want to remove the grpc and/or protobuf installation or upgrade to a newer version. + +## cmake + +`cmake` is the default build option on Windows, but also works on Linux, MacOS. `cmake` has good +support for crosscompiling and can be used for targeting Android platform. + +If your project is using cmake, there are several ways to add gRPC dependency. +- install gRPC via cmake first and then locate it with `find_package(gRPC CONFIG)`. [Example](../../examples/cpp/helloworld/CMakeLists.txt) +- via cmake's `ExternalProject_Add` using a technique called "superbuild". [Example](../../examples/cpp/helloworld/cmake_externalproject/CMakeLists.txt) +- add gRPC source tree to your project (preferrably as a git submodule) and add it to your cmake project with `add_subdirectory`. [Example](../../examples/cpp/helloworld/CMakeLists.txt) + +## Packaging systems + +There's no standard packaging system for C++. We've looked into supporting some (e.g. Conan and vcpkg) but we are not there yet. +Contributions and community-maintained packages for popular packaging systems are welcome! + + +## Examples & Additional Documentation You can find out how to build and run our simplest gRPC C++ example in our [C++ quick start](../../examples/cpp). @@ -25,7 +74,6 @@ documentation site at [grpc.io](https://grpc.io), specifically: APIs. -# Examples +# To start developing gRPC C++ -Code examples for gRPC C++ live in this repository's -[examples/cpp](../../examples/cpp) directory. +For instructions on how to build gRPC C++ from source, follow the [Building gRPC C++](../../BUILDING.md) instructions. diff --git a/src/csharp/README.md b/src/csharp/README.md index e117e66afd6..92be4bf1e54 100644 --- a/src/csharp/README.md +++ b/src/csharp/README.md @@ -42,7 +42,7 @@ If you are a user of gRPC C#, go to Usage section above. - [dotnet SDK](https://www.microsoft.com/net/core) - [Mono 4+](https://www.mono-project.com/) (only needed for Linux and MacOS) -- Prerequisites mentioned in [INSTALL.md](../../INSTALL.md#pre-requisites) +- Prerequisites mentioned in [BUILDING.md](../../BUILDING.md#pre-requisites) to be able to compile the native code. **Windows, Linux or Mac OS X** @@ -93,6 +93,6 @@ THE NATIVE DEPENDENCY Internally, gRPC C# uses a native library written in C (gRPC C core) and invokes its functionality via P/Invoke. The fact that a native library is used should be fully transparent to the users and just installing the `Grpc.Core` NuGet package is the only step needed to use gRPC C# on all supported platforms. -[API Reference]: https://grpc.io/grpc/csharp/ +[API Reference]: https://grpc.io/grpc/csharp/api/Grpc.Core.html [Helloworld Example]: ../../examples/csharp/helloworld [RouteGuide Tutorial]: https://grpc.io/docs/tutorials/basic/csharp.html diff --git a/tools/run_tests/python_utils/filter_pull_request_tests.py b/tools/run_tests/python_utils/filter_pull_request_tests.py index 4c09b3414e3..98a17fd1a7c 100644 --- a/tools/run_tests/python_utils/filter_pull_request_tests.py +++ b/tools/run_tests/python_utils/filter_pull_request_tests.py @@ -96,7 +96,7 @@ _WHITELIST_DICT = { 'gRPC\-Core\.podspec$': [_OBJC_TEST_SUITE], 'gRPC\-ProtoRPC\.podspec$': [_OBJC_TEST_SUITE], 'gRPC\-RxLibrary\.podspec$': [_OBJC_TEST_SUITE], - 'INSTALL\.md$': [], + 'BUILDING\.md$': [], 'LICENSE$': [], 'MANIFEST\.md$': [], 'package\.json$': [_PHP_TEST_SUITE], diff --git a/vsprojects/.gitignore b/vsprojects/.gitignore deleted file mode 100644 index 8df1dcf0bf5..00000000000 --- a/vsprojects/.gitignore +++ /dev/null @@ -1,12 +0,0 @@ -Debug -Debug-DLL -Release -Release-DLL -*.suo -*.user -test_bin -*.opensdf -*.sdf -third_party/*.user -/packages -/IntDir diff --git a/vsprojects/README.md b/vsprojects/README.md deleted file mode 100644 index ee32ecab9ae..00000000000 --- a/vsprojects/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Pre-generated MS Visual Studio project & solution files: DELETED - -**The pre-generated MS Visual Studio project & solution files are no longer available, please use cmake instead (it can generate Visual Studio projects for you).** - -**Pre-generated MS Visual Studio projects used to be the recommended way to build on Windows, but there were some limitations:** -- **hard to build dependencies, expecially boringssl (deps usually support cmake quite well)** -- **the nuget-based openssl & zlib dependencies are hard to maintain and update. We've received issues indicating that they are flawed.** -- **.proto codegen is hard to support in Visual Studio directly (but we have a pretty decent support in cmake)** -- **It's a LOT of generated files. We prefer not to have too much generated code in our github repo.** - -See [INSTALL.md](/INSTALL.md) for detailed instructions how to build using cmake on Windows. From de4e53162ea13d1491e0dd3197c185cd93e3ad29 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 20 Jun 2018 21:42:33 +0200 Subject: [PATCH 54/57] address comments --- CONCEPTS.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CONCEPTS.md b/CONCEPTS.md index 6855d43d39b..034d58e4275 100644 --- a/CONCEPTS.md +++ b/CONCEPTS.md @@ -9,8 +9,9 @@ combination of the supported languages. ## Interface -Developers using gRPC start with the description of an RPC service (a collection -of methods), and generate client and server side interfaces. The server implements +Developers using gRPC start with a language agnostic description of an RPC service (a collection +of methods). From this description, gRPC will generate client and server side interfaces +in any of the supported languages. The server implements the service interface, which can be remotely invoked by the client interface. By default, gRPC uses [Protocol Buffers](https://github.com/google/protobuf) as the @@ -41,7 +42,7 @@ asynchronous flavors. gRPC supports streaming semantics, where either the client or the server (or both) send a stream of messages on a single RPC call. The most general case is -Bidirectional Streaming where a single gRPC call establishes a stream where both +Bidirectional Streaming where a single gRPC call establishes a stream in which both the client and the server can send a stream of messages to each other. The streamed messages are delivered in the order they were sent. From 73a124fcfbf4af301e993fd3dafe8750dbc9a6a1 Mon Sep 17 00:00:00 2001 From: Yash Tibrewal Date: Wed, 20 Jun 2018 13:34:33 -0700 Subject: [PATCH 55/57] Wire to socket doc change --- include/grpcpp/impl/codegen/call.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/grpcpp/impl/codegen/call.h b/include/grpcpp/impl/codegen/call.h index e324f6b14d3..a5e930aaa5c 100644 --- a/include/grpcpp/impl/codegen/call.h +++ b/include/grpcpp/impl/codegen/call.h @@ -171,8 +171,8 @@ class WriteOptions { return *this; } - /// Guarantee that all bytes have been written to the wire before completing - /// this write (usually writes are completed when they pass flow control) + /// Guarantee that all bytes have been written to the socket before completing + /// this write (usually writes are completed when they pass flow control). inline WriteOptions& set_write_through() { SetBit(GRPC_WRITE_THROUGH); return *this; From 45915f7963949047be3f0993432b488ac7f4df06 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Wed, 20 Jun 2018 11:21:16 -0700 Subject: [PATCH 56/57] Add caveat to noisy comment, push to dbg mode --- .../ext/transport/chttp2/transport/writing.cc | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/core/ext/transport/chttp2/transport/writing.cc b/src/core/ext/transport/chttp2/transport/writing.cc index 34d5e6e2180..8b73b01dea2 100644 --- a/src/core/ext/transport/chttp2/transport/writing.cc +++ b/src/core/ext/transport/chttp2/transport/writing.cc @@ -139,22 +139,27 @@ static bool update_list(grpc_chttp2_transport* t, grpc_chttp2_stream* s, static void report_stall(grpc_chttp2_transport* t, grpc_chttp2_stream* s, const char* staller) { - gpr_log( - GPR_DEBUG, - "%s:%p stream %d stalled by %s [fc:pending=%" PRIdPTR - ":pending-compressed=%" PRIdPTR ":flowed=%" PRId64 - ":peer_initwin=%d:t_win=%" PRId64 ":s_win=%d:s_delta=%" PRId64 "]", - t->peer_string, t, s->id, staller, s->flow_controlled_buffer.length, - s->compressed_data_buffer.length, s->flow_controlled_bytes_flowed, - t->settings[GRPC_ACKED_SETTINGS] - [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE], - t->flow_control->remote_window(), - static_cast GPR_MAX( - 0, - s->flow_control->remote_window_delta() + - (int64_t)t->settings[GRPC_PEER_SETTINGS] - [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]), - s->flow_control->remote_window_delta()); + if (grpc_flowctl_trace.enabled()) { + gpr_log( + GPR_DEBUG, + "%s:%p stream %d moved to stalled list by %s. This is FULLY expected " + "to happen in a healthy program that is not seeing flow control stalls." + " However, if you know that there are unwanted stalls, here is some " + "helpful data: [fc:pending=%" PRIdPTR ":pending-compressed=%" PRIdPTR + ":flowed=%" PRId64 ":peer_initwin=%d:t_win=%" PRId64 + ":s_win=%d:s_delta=%" PRId64 "]", + t->peer_string, t, s->id, staller, s->flow_controlled_buffer.length, + s->compressed_data_buffer.length, s->flow_controlled_bytes_flowed, + t->settings[GRPC_ACKED_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE], + t->flow_control->remote_window(), + static_cast GPR_MAX( + 0, + s->flow_control->remote_window_delta() + + (int64_t)t->settings[GRPC_PEER_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]), + s->flow_control->remote_window_delta()); + } } static bool stream_ref_if_not_destroyed(gpr_refcount* r) { From 8771dab571e4495bc2f1172c65cd1ab9f9fea84d Mon Sep 17 00:00:00 2001 From: ZhouyihaiDing Date: Tue, 19 Jun 2018 14:15:08 -0700 Subject: [PATCH 57/57] PHP: fix distribtest test by adding -Ithird_party/nanopb --- config.m4 | 5 +++-- config.w32 | 5 +++-- templates/config.m4.template | 5 +++-- templates/config.w32.template | 5 +++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/config.m4 b/config.m4 index 781fd08fa10..29f293f6136 100644 --- a/config.m4 +++ b/config.m4 @@ -9,11 +9,12 @@ if test "$PHP_GRPC" != "no"; then PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/src/php/ext/grpc) PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/boringssl/include) PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/address_sorting/include) + PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/nanopb) LIBS="-lpthread $LIBS" - CFLAGS="-Wall -Werror -Wno-parentheses-equality -Wno-unused-value -std=c11 -g -O2 -D PB_FIELD_16BIT=1" - CXXFLAGS="-std=c++11 -fno-exceptions -fno-rtti -g -O2 -D PB_FIELD_16BIT=1" + CFLAGS="-Wall -Werror -Wno-parentheses-equality -Wno-unused-value -std=c11 -g -O2 -D PB_FIELD_32BIT=1" + CXXFLAGS="-std=c++11 -fno-exceptions -fno-rtti -g -O2 -D PB_FIELD_32BIT=1" GRPC_SHARED_LIBADD="-lpthread $GRPC_SHARED_LIBADD" PHP_REQUIRE_CXX() PHP_ADD_LIBRARY(pthread) diff --git a/config.w32 b/config.w32 index b87b261772d..74406eca23a 100644 --- a/config.w32 +++ b/config.w32 @@ -638,13 +638,14 @@ if (PHP_GRPC != "no") { EXTENSION("grpc", grpc_source, null, "/DOPENSSL_NO_ASM /D_GNU_SOURCE /DWIN32_LEAN_AND_MEAN "+ "/D_HAS_EXCEPTIONS=0 /DNOMINMAX /DGRPC_ARES=0 /D_WIN32_WINNT=0x600 "+ - "/DPB_FIELD_16BIT "+ + "/DPB_FIELD_32BIT "+ "/I"+configure_module_dirname+" "+ "/I"+configure_module_dirname+"\\include "+ "/I"+configure_module_dirname+"\\src\\php\\ext\\grpc "+ "/I"+configure_module_dirname+"\\third_party\\boringssl\\include "+ "/I"+configure_module_dirname+"\\third_party\\zlib "+ - "/I"+configure_module_dirname+"\\third_party\\address_sorting\\include"); + "/I"+configure_module_dirname+"\\third_party\\address_sorting\\include "+ + "/I"+configure_module_dirname+"\\third_party\\nanopb"); base_dir = get_define('BUILD_DIR'); FSO.CreateFolder(base_dir+"\\ext"); diff --git a/templates/config.m4.template b/templates/config.m4.template index cc19d98375f..19f99049111 100644 --- a/templates/config.m4.template +++ b/templates/config.m4.template @@ -11,11 +11,12 @@ PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/src/php/ext/grpc) PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/boringssl/include) PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/address_sorting/include) + PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/nanopb) LIBS="-lpthread $LIBS" - CFLAGS="-Wall -Werror -Wno-parentheses-equality -Wno-unused-value -std=c11 -g -O2 -D PB_FIELD_16BIT=1" - CXXFLAGS="-std=c++11 -fno-exceptions -fno-rtti -g -O2 -D PB_FIELD_16BIT=1" + CFLAGS="-Wall -Werror -Wno-parentheses-equality -Wno-unused-value -std=c11 -g -O2 -D PB_FIELD_32BIT=1" + CXXFLAGS="-std=c++11 -fno-exceptions -fno-rtti -g -O2 -D PB_FIELD_32BIT=1" GRPC_SHARED_LIBADD="-lpthread $GRPC_SHARED_LIBADD" PHP_REQUIRE_CXX() PHP_ADD_LIBRARY(pthread) diff --git a/templates/config.w32.template b/templates/config.w32.template index ef25e555966..5e37cf568c2 100644 --- a/templates/config.w32.template +++ b/templates/config.w32.template @@ -23,13 +23,14 @@ EXTENSION("grpc", grpc_source, null, "/DOPENSSL_NO_ASM /D_GNU_SOURCE /DWIN32_LEAN_AND_MEAN "+ "/D_HAS_EXCEPTIONS=0 /DNOMINMAX /DGRPC_ARES=0 /D_WIN32_WINNT=0x600 "+ - "/DPB_FIELD_16BIT "+ + "/DPB_FIELD_32BIT "+ "/I"+configure_module_dirname+" "+ "/I"+configure_module_dirname+"\\include "+ "/I"+configure_module_dirname+"\\src\\php\\ext\\grpc "+ "/I"+configure_module_dirname+"\\third_party\\boringssl\\include "+ "/I"+configure_module_dirname+"\\third_party\\zlib "+ - "/I"+configure_module_dirname+"\\third_party\\address_sorting\\include"); + "/I"+configure_module_dirname+"\\third_party\\address_sorting\\include "+ + "/I"+configure_module_dirname+"\\third_party\\nanopb"); <% dirs = {} for lib in libs: