Merge branch 'master' into epollex-ownerfd-fix

pull/15776/head
Sree Kuchibhotla 7 years ago
commit 1517f80908
  1. 2
      BUILD
  2. 110
      BUILDING.md
  3. 59
      CMakeLists.txt
  4. 63
      CONCEPTS.md
  5. 35
      CONTRIBUTING.md
  6. 60
      Makefile
  7. 120
      README.md
  8. 19
      build.yaml
  9. 6
      config.m4
  10. 6
      config.w32
  11. 2
      doc/command_line_tool.md
  12. 2
      examples/cpp/README.md
  13. 4
      examples/cpp/cpptutorial.md
  14. 4
      examples/cpp/helloworld/README.md
  15. 6
      examples/cpp/route_guide/README.md
  16. 2
      gRPC-C++.podspec
  17. 4
      gRPC-Core.podspec
  18. 2
      grpc.def
  19. 2
      grpc.gemspec
  20. 6
      grpc.gyp
  21. 8
      include/grpc/grpc.h
  22. 4
      include/grpc/impl/codegen/grpc_types.h
  23. 4
      include/grpcpp/impl/codegen/call.h
  24. 2
      package.xml
  25. 129
      src/core/ext/filters/client_channel/client_channel.cc
  26. 37
      src/core/ext/transport/chttp2/transport/writing.cc
  27. 49
      src/core/lib/channel/channel_trace.cc
  28. 30
      src/core/lib/channel/channel_trace.h
  29. 185
      src/core/lib/channel/channelz.cc
  30. 85
      src/core/lib/channel/channelz.h
  31. 9
      src/core/lib/iomgr/socket_utils.h
  32. 4
      src/core/lib/iomgr/socket_utils_common_posix.cc
  33. 4
      src/core/lib/iomgr/socket_utils_uv.cc
  34. 4
      src/core/lib/iomgr/socket_utils_windows.cc
  35. 29
      src/core/lib/surface/call.cc
  36. 33
      src/core/lib/surface/channel.cc
  37. 4
      src/core/lib/surface/channel.h
  38. 64
      src/cpp/README.md
  39. 6
      src/cpp/ext/filters/census/client_filter.cc
  40. 4
      src/csharp/README.md
  41. 143
      src/proto/grpc/channelz/channelz.proto
  42. 1
      src/python/grpcio/grpc_core_dependencies.py
  43. 3
      src/python/grpcio_testing/MANIFEST.in
  44. 10
      src/python/grpcio_testing/README.rst
  45. 4
      src/ruby/end2end/multiple_killed_watching_threads_driver.rb
  46. 4
      src/ruby/ext/grpc/rb_grpc_imports.generated.c
  47. 6
      src/ruby/ext/grpc/rb_grpc_imports.generated.h
  48. 2
      src/ruby/lib/grpc/generic/active_call.rb
  49. 6
      templates/CMakeLists.txt.template
  50. 5
      templates/config.m4.template
  51. 5
      templates/config.w32.template
  52. 17
      test/core/channel/BUILD
  53. 196
      test/core/channel/channel_trace_test.cc
  54. 216
      test/core/channel/channelz_test.cc
  55. 8
      test/core/end2end/end2end_nosec_tests.cc
  56. 8
      test/core/end2end/end2end_tests.cc
  57. 1
      test/core/end2end/fuzzers/api_fuzzer.cc
  58. 1
      test/core/end2end/gen_build_yaml.py
  59. 1
      test/core/end2end/generate_tests.bzl
  60. 299
      test/core/end2end/tests/channelz.cc
  61. 2
      test/core/surface/public_headers_must_be_c89.c
  62. 41
      test/cpp/util/channel_trace_proto_helper.cc
  63. 1
      test/cpp/util/channel_trace_proto_helper.h
  64. 16
      test/distrib/python/test_packages.sh
  65. 1
      tools/doxygen/Doxyfile.c++.internal
  66. 2
      tools/doxygen/Doxyfile.core.internal
  67. 8
      tools/run_tests/artifacts/build_artifact_python.sh
  68. 26
      tools/run_tests/generated/sources_and_headers.json
  69. 927
      tools/run_tests/generated/tests.json
  70. 22
      tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh
  71. 2
      tools/run_tests/python_utils/filter_pull_request_tests.py
  72. 2
      tools/run_tests/python_utils/upload_rbe_results.py
  73. 2
      tools/run_tests/run_tests.py
  74. 12
      vsprojects/.gitignore
  75. 11
      vsprojects/README.md

@ -676,6 +676,7 @@ grpc_cc_library(
"src/core/lib/channel/channel_stack_builder.cc", "src/core/lib/channel/channel_stack_builder.cc",
"src/core/lib/channel/channel_trace.cc", "src/core/lib/channel/channel_trace.cc",
"src/core/lib/channel/channelz_registry.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/connected_channel.cc",
"src/core/lib/channel/handshaker.cc", "src/core/lib/channel/handshaker.cc",
"src/core/lib/channel/handshaker_factory.cc", "src/core/lib/channel/handshaker_factory.cc",
@ -823,6 +824,7 @@ grpc_cc_library(
"src/core/lib/channel/channel_stack_builder.h", "src/core/lib/channel/channel_stack_builder.h",
"src/core/lib/channel/channel_trace.h", "src/core/lib/channel/channel_trace.h",
"src/core/lib/channel/channelz_registry.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/connected_channel.h",
"src/core/lib/channel/context.h", "src/core/lib/channel/context.h",
"src/core/lib/channel/handshaker.h", "src/core/lib/channel/handshaker.h",

@ -1,18 +1,5 @@
# If you are in a hurry gRPC C++ - Building from source
===========================
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`
# Pre-requisites # 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 $ [sudo] apt-get install clang libc++-dev
``` ```
## macOS ## MacOS
On a Mac, you will first need to On a Mac, you will first need to
install Xcode or install Xcode or
@ -60,6 +47,17 @@ installed by `brew` is being used:
$ LIBTOOL=glibtool LIBTOOLIZE=glibtoolize make $ 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 ## Protoc
By default gRPC uses [protocol buffers](https://github.com/google/protobuf), 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 $ 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 Before building, you need to clone the gRPC github repository and download submodules containing source code
gRPC C Core library. 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 ```sh
$ git clone -b $(curl -L https://grpc.io/release) https://github.com/grpc/grpc $ git clone -b $(curl -L https://grpc.io/release) https://github.com/grpc/grpc
$ cd grpc $ cd grpc
$ git submodule update --init $ git submodule update --init
$ make ```
$ [sudo] make install
```
## Windows ## 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. From the grpc repository root
- Install Visual Studio 2015 or 2017 (Visual C++ compiler will be used). ```sh
- Install [Git](https://git-scm.com/). $ make
- 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`)
#### Clone grpc sources including submodules ## bazel
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). From the grpc repository root
``` ```
> @rem You can also do just "git clone --recursive -b THE_BRANCH_YOU_WANT https://github.com/grpc/grpc" bazel build :all
> 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"
``` ```
#### 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, When using the "Visual Studio" generator,
cmake will generate a solution (`grpc.sln`) that contains a VS project for cmake will generate a solution (`grpc.sln`) that contains a VS project for
every target defined in `CMakeLists.txt` (+ few extra convenience projects 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 --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) 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. 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 .. -GNinja -DCMAKE_BUILD_TYPE=Release
> cmake --build . > 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.*

@ -39,6 +39,7 @@ set(gRPC_INSTALL_SHAREDIR "share/grpc" CACHE STRING "Installation directory for
# Options # Options
option(gRPC_BUILD_TESTS "Build tests" OFF) option(gRPC_BUILD_TESTS "Build tests" OFF)
option(gRPC_BUILD_CODEGEN "Build codegen" ON) option(gRPC_BUILD_CODEGEN "Build codegen" ON)
option(gRPC_BUILD_CSHARP_EXT "Build C# extensions" ON)
set(gRPC_INSTALL_default ON) set(gRPC_INSTALL_default ON)
if (NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) if (NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
@ -546,6 +547,7 @@ add_dependencies(buildtests_cxx channel_arguments_test)
add_dependencies(buildtests_cxx channel_filter_test) add_dependencies(buildtests_cxx channel_filter_test)
add_dependencies(buildtests_cxx channel_trace_test) add_dependencies(buildtests_cxx channel_trace_test)
add_dependencies(buildtests_cxx channelz_registry_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_linux_test)
add_dependencies(buildtests_cxx check_gcp_environment_windows_test) add_dependencies(buildtests_cxx check_gcp_environment_windows_test)
add_dependencies(buildtests_cxx chttp2_settings_timeout_test) add_dependencies(buildtests_cxx chttp2_settings_timeout_test)
@ -938,6 +940,7 @@ add_library(grpc
src/core/lib/channel/channel_stack.cc src/core/lib/channel/channel_stack.cc
src/core/lib/channel/channel_stack_builder.cc src/core/lib/channel/channel_stack_builder.cc
src/core/lib/channel/channel_trace.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/channelz_registry.cc
src/core/lib/channel/connected_channel.cc src/core/lib/channel/connected_channel.cc
src/core/lib/channel/handshaker.cc src/core/lib/channel/handshaker.cc
@ -1333,6 +1336,7 @@ add_library(grpc_cronet
src/core/lib/channel/channel_stack.cc src/core/lib/channel/channel_stack.cc
src/core/lib/channel/channel_stack_builder.cc src/core/lib/channel/channel_stack_builder.cc
src/core/lib/channel/channel_trace.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/channelz_registry.cc
src/core/lib/channel/connected_channel.cc src/core/lib/channel/connected_channel.cc
src/core/lib/channel/handshaker.cc src/core/lib/channel/handshaker.cc
@ -1719,6 +1723,7 @@ add_library(grpc_test_util
src/core/lib/channel/channel_stack.cc src/core/lib/channel/channel_stack.cc
src/core/lib/channel/channel_stack_builder.cc src/core/lib/channel/channel_stack_builder.cc
src/core/lib/channel/channel_trace.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/channelz_registry.cc
src/core/lib/channel/connected_channel.cc src/core/lib/channel/connected_channel.cc
src/core/lib/channel/handshaker.cc src/core/lib/channel/handshaker.cc
@ -2024,6 +2029,7 @@ add_library(grpc_test_util_unsecure
src/core/lib/channel/channel_stack.cc src/core/lib/channel/channel_stack.cc
src/core/lib/channel/channel_stack_builder.cc src/core/lib/channel/channel_stack_builder.cc
src/core/lib/channel/channel_trace.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/channelz_registry.cc
src/core/lib/channel/connected_channel.cc src/core/lib/channel/connected_channel.cc
src/core/lib/channel/handshaker.cc src/core/lib/channel/handshaker.cc
@ -2308,6 +2314,7 @@ add_library(grpc_unsecure
src/core/lib/channel/channel_stack.cc src/core/lib/channel/channel_stack.cc
src/core/lib/channel/channel_stack_builder.cc src/core/lib/channel/channel_stack_builder.cc
src/core/lib/channel/channel_trace.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/channelz_registry.cc
src/core/lib/channel/connected_channel.cc src/core/lib/channel/connected_channel.cc
src/core/lib/channel/handshaker.cc src/core/lib/channel/handshaker.cc
@ -3140,6 +3147,7 @@ add_library(grpc++_cronet
src/core/lib/channel/channel_stack.cc src/core/lib/channel/channel_stack.cc
src/core/lib/channel/channel_stack_builder.cc src/core/lib/channel/channel_stack_builder.cc
src/core/lib/channel/channel_trace.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/channelz_registry.cc
src/core/lib/channel/connected_channel.cc src/core/lib/channel/connected_channel.cc
src/core/lib/channel/handshaker.cc src/core/lib/channel/handshaker.cc
@ -5173,6 +5181,7 @@ target_link_libraries(qps
endif (gRPC_BUILD_CODEGEN) endif (gRPC_BUILD_CODEGEN)
endif (gRPC_BUILD_TESTS) endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_CSHARP_EXT)
add_library(grpc_csharp_ext SHARED add_library(grpc_csharp_ext SHARED
src/csharp/ext/grpc_csharp_ext.c src/csharp/ext/grpc_csharp_ext.c
@ -5219,6 +5228,7 @@ if (gRPC_INSTALL)
) )
endif() endif()
endif (gRPC_BUILD_CSHARP_EXT)
if (gRPC_BUILD_TESTS) if (gRPC_BUILD_TESTS)
add_library(bad_client_test add_library(bad_client_test
@ -5319,6 +5329,7 @@ add_library(end2end_tests
test/core/end2end/tests/cancel_before_invoke.cc test/core/end2end/tests/cancel_before_invoke.cc
test/core/end2end/tests/cancel_in_a_vacuum.cc test/core/end2end/tests/cancel_in_a_vacuum.cc
test/core/end2end/tests/cancel_with_status.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/compressed_payload.cc
test/core/end2end/tests/connectivity.cc test/core/end2end/tests/connectivity.cc
test/core/end2end/tests/default_host.cc test/core/end2end/tests/default_host.cc
@ -5439,6 +5450,7 @@ add_library(end2end_nosec_tests
test/core/end2end/tests/cancel_before_invoke.cc test/core/end2end/tests/cancel_before_invoke.cc
test/core/end2end/tests/cancel_in_a_vacuum.cc test/core/end2end/tests/cancel_in_a_vacuum.cc
test/core/end2end/tests/cancel_with_status.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/compressed_payload.cc
test/core/end2end/tests/connectivity.cc test/core/end2end/tests/connectivity.cc
test/core/end2end/tests/default_host.cc test/core/end2end/tests/default_host.cc
@ -10832,6 +10844,53 @@ target_link_libraries(channelz_registry_test
endif (gRPC_BUILD_TESTS) endif (gRPC_BUILD_TESTS)
if (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 ${_gRPC_NANOPB_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 add_executable(check_gcp_environment_linux_test
test/core/security/check_gcp_environment_linux_test.cc test/core/security/check_gcp_environment_linux_test.cc
third_party/googletest/googletest/src/gtest-all.cc third_party/googletest/googletest/src/gtest-all.cc

@ -0,0 +1,63 @@
# 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 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
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 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.
# 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.

@ -11,13 +11,34 @@ In order to protect both you and ourselves, you will need to sign the
[Contributor License [Contributor License
Agreement](https://identity.linuxfoundation.org/projects/cncf). 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 Before starting any development work you will need a local copy of the gRPC repository.
[tools/run_tests](tools/run_tests) for how to run tests for a given language. 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 ## Building & Running tests
[INSTALL.md](INSTALL.md) and in `src/YOUR-LANGUAGE` (e.g. `src/csharp`)
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 ## Generated project files

@ -1123,6 +1123,7 @@ channel_arguments_test: $(BINDIR)/$(CONFIG)/channel_arguments_test
channel_filter_test: $(BINDIR)/$(CONFIG)/channel_filter_test channel_filter_test: $(BINDIR)/$(CONFIG)/channel_filter_test
channel_trace_test: $(BINDIR)/$(CONFIG)/channel_trace_test channel_trace_test: $(BINDIR)/$(CONFIG)/channel_trace_test
channelz_registry_test: $(BINDIR)/$(CONFIG)/channelz_registry_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_linux_test: $(BINDIR)/$(CONFIG)/check_gcp_environment_linux_test
check_gcp_environment_windows_test: $(BINDIR)/$(CONFIG)/check_gcp_environment_windows_test check_gcp_environment_windows_test: $(BINDIR)/$(CONFIG)/check_gcp_environment_windows_test
chttp2_settings_timeout_test: $(BINDIR)/$(CONFIG)/chttp2_settings_timeout_test chttp2_settings_timeout_test: $(BINDIR)/$(CONFIG)/chttp2_settings_timeout_test
@ -1621,6 +1622,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/channel_filter_test \ $(BINDIR)/$(CONFIG)/channel_filter_test \
$(BINDIR)/$(CONFIG)/channel_trace_test \ $(BINDIR)/$(CONFIG)/channel_trace_test \
$(BINDIR)/$(CONFIG)/channelz_registry_test \ $(BINDIR)/$(CONFIG)/channelz_registry_test \
$(BINDIR)/$(CONFIG)/channelz_test \
$(BINDIR)/$(CONFIG)/check_gcp_environment_linux_test \ $(BINDIR)/$(CONFIG)/check_gcp_environment_linux_test \
$(BINDIR)/$(CONFIG)/check_gcp_environment_windows_test \ $(BINDIR)/$(CONFIG)/check_gcp_environment_windows_test \
$(BINDIR)/$(CONFIG)/chttp2_settings_timeout_test \ $(BINDIR)/$(CONFIG)/chttp2_settings_timeout_test \
@ -1797,6 +1799,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/channel_filter_test \ $(BINDIR)/$(CONFIG)/channel_filter_test \
$(BINDIR)/$(CONFIG)/channel_trace_test \ $(BINDIR)/$(CONFIG)/channel_trace_test \
$(BINDIR)/$(CONFIG)/channelz_registry_test \ $(BINDIR)/$(CONFIG)/channelz_registry_test \
$(BINDIR)/$(CONFIG)/channelz_test \
$(BINDIR)/$(CONFIG)/check_gcp_environment_linux_test \ $(BINDIR)/$(CONFIG)/check_gcp_environment_linux_test \
$(BINDIR)/$(CONFIG)/check_gcp_environment_windows_test \ $(BINDIR)/$(CONFIG)/check_gcp_environment_windows_test \
$(BINDIR)/$(CONFIG)/chttp2_settings_timeout_test \ $(BINDIR)/$(CONFIG)/chttp2_settings_timeout_test \
@ -2237,6 +2240,8 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/channel_trace_test || ( echo test channel_trace_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/channel_trace_test || ( echo test channel_trace_test failed ; exit 1 )
$(E) "[RUN] Testing channelz_registry_test" $(E) "[RUN] Testing channelz_registry_test"
$(Q) $(BINDIR)/$(CONFIG)/channelz_registry_test || ( echo test channelz_registry_test failed ; exit 1 ) $(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" $(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 ) $(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" $(E) "[RUN] Testing check_gcp_environment_windows_test"
@ -3315,6 +3320,7 @@ LIBGRPC_SRC = \
src/core/lib/channel/channel_stack.cc \ src/core/lib/channel/channel_stack.cc \
src/core/lib/channel/channel_stack_builder.cc \ src/core/lib/channel/channel_stack_builder.cc \
src/core/lib/channel/channel_trace.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/channelz_registry.cc \
src/core/lib/channel/connected_channel.cc \ src/core/lib/channel/connected_channel.cc \
src/core/lib/channel/handshaker.cc \ src/core/lib/channel/handshaker.cc \
@ -3709,6 +3715,7 @@ LIBGRPC_CRONET_SRC = \
src/core/lib/channel/channel_stack.cc \ src/core/lib/channel/channel_stack.cc \
src/core/lib/channel/channel_stack_builder.cc \ src/core/lib/channel/channel_stack_builder.cc \
src/core/lib/channel/channel_trace.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/channelz_registry.cc \
src/core/lib/channel/connected_channel.cc \ src/core/lib/channel/connected_channel.cc \
src/core/lib/channel/handshaker.cc \ src/core/lib/channel/handshaker.cc \
@ -4093,6 +4100,7 @@ LIBGRPC_TEST_UTIL_SRC = \
src/core/lib/channel/channel_stack.cc \ src/core/lib/channel/channel_stack.cc \
src/core/lib/channel/channel_stack_builder.cc \ src/core/lib/channel/channel_stack_builder.cc \
src/core/lib/channel/channel_trace.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/channelz_registry.cc \
src/core/lib/channel/connected_channel.cc \ src/core/lib/channel/connected_channel.cc \
src/core/lib/channel/handshaker.cc \ src/core/lib/channel/handshaker.cc \
@ -4389,6 +4397,7 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \
src/core/lib/channel/channel_stack.cc \ src/core/lib/channel/channel_stack.cc \
src/core/lib/channel/channel_stack_builder.cc \ src/core/lib/channel/channel_stack_builder.cc \
src/core/lib/channel/channel_trace.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/channelz_registry.cc \
src/core/lib/channel/connected_channel.cc \ src/core/lib/channel/connected_channel.cc \
src/core/lib/channel/handshaker.cc \ src/core/lib/channel/handshaker.cc \
@ -4651,6 +4660,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/channel/channel_stack.cc \ src/core/lib/channel/channel_stack.cc \
src/core/lib/channel/channel_stack_builder.cc \ src/core/lib/channel/channel_stack_builder.cc \
src/core/lib/channel/channel_trace.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/channelz_registry.cc \
src/core/lib/channel/connected_channel.cc \ src/core/lib/channel/connected_channel.cc \
src/core/lib/channel/handshaker.cc \ src/core/lib/channel/handshaker.cc \
@ -5471,6 +5481,7 @@ LIBGRPC++_CRONET_SRC = \
src/core/lib/channel/channel_stack.cc \ src/core/lib/channel/channel_stack.cc \
src/core/lib/channel/channel_stack_builder.cc \ src/core/lib/channel/channel_stack_builder.cc \
src/core/lib/channel/channel_trace.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/channelz_registry.cc \
src/core/lib/channel/connected_channel.cc \ src/core/lib/channel/connected_channel.cc \
src/core/lib/channel/handshaker.cc \ src/core/lib/channel/handshaker.cc \
@ -9978,6 +9989,7 @@ LIBEND2END_TESTS_SRC = \
test/core/end2end/tests/cancel_before_invoke.cc \ test/core/end2end/tests/cancel_before_invoke.cc \
test/core/end2end/tests/cancel_in_a_vacuum.cc \ test/core/end2end/tests/cancel_in_a_vacuum.cc \
test/core/end2end/tests/cancel_with_status.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/compressed_payload.cc \
test/core/end2end/tests/connectivity.cc \ test/core/end2end/tests/connectivity.cc \
test/core/end2end/tests/default_host.cc \ test/core/end2end/tests/default_host.cc \
@ -10095,6 +10107,7 @@ LIBEND2END_NOSEC_TESTS_SRC = \
test/core/end2end/tests/cancel_before_invoke.cc \ test/core/end2end/tests/cancel_before_invoke.cc \
test/core/end2end/tests/cancel_in_a_vacuum.cc \ test/core/end2end/tests/cancel_in_a_vacuum.cc \
test/core/end2end/tests/cancel_with_status.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/compressed_payload.cc \
test/core/end2end/tests/connectivity.cc \ test/core/end2end/tests/connectivity.cc \
test/core/end2end/tests/default_host.cc \ test/core/end2end/tests/default_host.cc \
@ -16460,6 +16473,53 @@ endif
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 = \ CHECK_GCP_ENVIRONMENT_LINUX_TEST_SRC = \
test/core/security/check_gcp_environment_linux_test.cc \ test/core/security/check_gcp_environment_linux_test.cc \

@ -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.
<table>
<tr>
<td><b>Homepage:</b></td>
<td><a href="https://grpc.io/">grpc.io</a></td>
</tr>
<tr>
<td><b>Mailing List:</b></td>
<td><a href="https://groups.google.com/forum/#!forum/grpc-io">grpc-io@googlegroups.com</a></td>
</tr>
</table>
[![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) [![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 # To start using gRPC
[The gRPC Authors](https://github.com/grpc/grpc/blob/master/AUTHORS)
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. 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). 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) | | WebJS | [grpc-web](https://github.com/grpc/grpc-web) |
| Dart | [grpc-dart](https://github.com/grpc/grpc-dart) | | 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.

@ -234,6 +234,7 @@ filegroups:
- src/core/lib/channel/channel_stack.cc - src/core/lib/channel/channel_stack.cc
- src/core/lib/channel/channel_stack_builder.cc - src/core/lib/channel/channel_stack_builder.cc
- src/core/lib/channel/channel_trace.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/channelz_registry.cc
- src/core/lib/channel/connected_channel.cc - src/core/lib/channel/connected_channel.cc
- src/core/lib/channel/handshaker.cc - src/core/lib/channel/handshaker.cc
@ -404,6 +405,7 @@ filegroups:
- src/core/lib/channel/channel_stack.h - src/core/lib/channel/channel_stack.h
- src/core/lib/channel/channel_stack_builder.h - src/core/lib/channel/channel_stack_builder.h
- src/core/lib/channel/channel_trace.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/channelz_registry.h
- src/core/lib/channel/connected_channel.h - src/core/lib/channel/connected_channel.h
- src/core/lib/channel/context.h - src/core/lib/channel/context.h
@ -4267,6 +4269,23 @@ targets:
uses: uses:
- grpc++_test - grpc++_test
uses_polling: false 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 - name: check_gcp_environment_linux_test
build: test build: test
language: c++ language: c++

@ -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()/src/php/ext/grpc)
PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/boringssl/include) 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/address_sorting/include)
PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/nanopb)
LIBS="-lpthread $LIBS" LIBS="-lpthread $LIBS"
CFLAGS="-Wall -Werror -Wno-parentheses-equality -Wno-unused-value -std=c11 -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_16BIT=1" CXXFLAGS="-std=c++11 -fno-exceptions -fno-rtti -g -O2 -D PB_FIELD_32BIT=1"
GRPC_SHARED_LIBADD="-lpthread $GRPC_SHARED_LIBADD" GRPC_SHARED_LIBADD="-lpthread $GRPC_SHARED_LIBADD"
PHP_REQUIRE_CXX() PHP_REQUIRE_CXX()
PHP_ADD_LIBRARY(pthread) PHP_ADD_LIBRARY(pthread)
@ -89,6 +90,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/channel/channel_stack.cc \ src/core/lib/channel/channel_stack.cc \
src/core/lib/channel/channel_stack_builder.cc \ src/core/lib/channel/channel_stack_builder.cc \
src/core/lib/channel/channel_trace.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/channelz_registry.cc \
src/core/lib/channel/connected_channel.cc \ src/core/lib/channel/connected_channel.cc \
src/core/lib/channel/handshaker.cc \ src/core/lib/channel/handshaker.cc \

@ -65,6 +65,7 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\channel\\channel_stack.cc " + "src\\core\\lib\\channel\\channel_stack.cc " +
"src\\core\\lib\\channel\\channel_stack_builder.cc " + "src\\core\\lib\\channel\\channel_stack_builder.cc " +
"src\\core\\lib\\channel\\channel_trace.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\\channelz_registry.cc " +
"src\\core\\lib\\channel\\connected_channel.cc " + "src\\core\\lib\\channel\\connected_channel.cc " +
"src\\core\\lib\\channel\\handshaker.cc " + "src\\core\\lib\\channel\\handshaker.cc " +
@ -638,13 +639,14 @@ if (PHP_GRPC != "no") {
EXTENSION("grpc", grpc_source, null, EXTENSION("grpc", grpc_source, null,
"/DOPENSSL_NO_ASM /D_GNU_SOURCE /DWIN32_LEAN_AND_MEAN "+ "/DOPENSSL_NO_ASM /D_GNU_SOURCE /DWIN32_LEAN_AND_MEAN "+
"/D_HAS_EXCEPTIONS=0 /DNOMINMAX /DGRPC_ARES=0 /D_WIN32_WINNT=0x600 "+ "/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+" "+
"/I"+configure_module_dirname+"\\include "+ "/I"+configure_module_dirname+"\\include "+
"/I"+configure_module_dirname+"\\src\\php\\ext\\grpc "+ "/I"+configure_module_dirname+"\\src\\php\\ext\\grpc "+
"/I"+configure_module_dirname+"\\third_party\\boringssl\\include "+ "/I"+configure_module_dirname+"\\third_party\\boringssl\\include "+
"/I"+configure_module_dirname+"\\third_party\\zlib "+ "/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'); base_dir = get_define('BUILD_DIR');
FSO.CreateFolder(base_dir+"\\ext"); FSO.CreateFolder(base_dir+"\\ext");

@ -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 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 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 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: repository, you need to run the following command to update submodules:

@ -3,7 +3,7 @@
## Installation ## Installation
To install gRPC on your system, follow the instructions to build from source 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`. `protoc` (if you don't have it already), and the C++ gRPC plugin for `protoc`.
## Hello C++ gRPC! ## Hello C++ gRPC!

@ -35,7 +35,7 @@ updating.
The example code for our tutorial is in [examples/cpp/route_guide](route_guide). 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 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 client interface code - if you don't already, follow the setup instructions in
[INSTALL.md](../../INSTALL.md). [BUILDING.md](../../BUILDING.md).
## Defining the service ## Defining the service
@ -130,7 +130,7 @@ a special gRPC C++ plugin.
For simplicity, we've provided a [Makefile](route_guide/Makefile) that runs 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 `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 run this yourself, make sure you've installed protoc and followed the gRPC code
[installation instructions](../../INSTALL.md) first): [installation instructions](../../BUILDING.md) first):
```shell ```shell
$ make route_guide.grpc.pb.cc route_guide.pb.cc $ make route_guide.grpc.pb.cc route_guide.pb.cc

@ -1,8 +1,8 @@
# gRPC C++ Hello World Tutorial # gRPC C++ Hello World Tutorial
### Install gRPC ### Install gRPC
Make sure you have installed gRPC on your system. Follow the instructions here: Make sure you have installed gRPC on your system. Follow the
[https://github.com/grpc/grpc/blob/master/INSTALL](../../../INSTALL.md). [BUILDING.md](../../../BUILDING.md) instructions.
### Get the tutorial source code ### Get the tutorial source code

@ -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

@ -347,6 +347,7 @@ Pod::Spec.new do |s|
'src/core/lib/channel/channel_stack.h', 'src/core/lib/channel/channel_stack.h',
'src/core/lib/channel/channel_stack_builder.h', 'src/core/lib/channel/channel_stack_builder.h',
'src/core/lib/channel/channel_trace.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/channelz_registry.h',
'src/core/lib/channel/connected_channel.h', 'src/core/lib/channel/connected_channel.h',
'src/core/lib/channel/context.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.h',
'src/core/lib/channel/channel_stack_builder.h', 'src/core/lib/channel/channel_stack_builder.h',
'src/core/lib/channel/channel_trace.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/channelz_registry.h',
'src/core/lib/channel/connected_channel.h', 'src/core/lib/channel/connected_channel.h',
'src/core/lib/channel/context.h', 'src/core/lib/channel/context.h',

@ -357,6 +357,7 @@ Pod::Spec.new do |s|
'src/core/lib/channel/channel_stack.h', 'src/core/lib/channel/channel_stack.h',
'src/core/lib/channel/channel_stack_builder.h', 'src/core/lib/channel/channel_stack_builder.h',
'src/core/lib/channel/channel_trace.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/channelz_registry.h',
'src/core/lib/channel/connected_channel.h', 'src/core/lib/channel/connected_channel.h',
'src/core/lib/channel/context.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.cc',
'src/core/lib/channel/channel_stack_builder.cc', 'src/core/lib/channel/channel_stack_builder.cc',
'src/core/lib/channel/channel_trace.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/channelz_registry.cc',
'src/core/lib/channel/connected_channel.cc', 'src/core/lib/channel/connected_channel.cc',
'src/core/lib/channel/handshaker.cc', 'src/core/lib/channel/handshaker.cc',
@ -936,6 +938,7 @@ Pod::Spec.new do |s|
'src/core/lib/channel/channel_stack.h', 'src/core/lib/channel/channel_stack.h',
'src/core/lib/channel/channel_stack_builder.h', 'src/core/lib/channel/channel_stack_builder.h',
'src/core/lib/channel/channel_trace.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/channelz_registry.h',
'src/core/lib/channel/connected_channel.h', 'src/core/lib/channel/connected_channel.h',
'src/core/lib/channel/context.h', 'src/core/lib/channel/context.h',
@ -1194,6 +1197,7 @@ Pod::Spec.new do |s|
'test/core/end2end/tests/cancel_before_invoke.cc', 'test/core/end2end/tests/cancel_before_invoke.cc',
'test/core/end2end/tests/cancel_in_a_vacuum.cc', 'test/core/end2end/tests/cancel_in_a_vacuum.cc',
'test/core/end2end/tests/cancel_with_status.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/compressed_payload.cc',
'test/core/end2end/tests/connectivity.cc', 'test/core/end2end/tests/connectivity.cc',
'test/core/end2end/tests/default_host.cc', 'test/core/end2end/tests/default_host.cc',

@ -45,8 +45,6 @@ EXPORTS
grpc_insecure_channel_create grpc_insecure_channel_create
grpc_lame_client_channel_create grpc_lame_client_channel_create
grpc_channel_destroy grpc_channel_destroy
grpc_channel_get_trace
grpc_channel_get_uuid
grpc_call_cancel grpc_call_cancel
grpc_call_cancel_with_status grpc_call_cancel_with_status
grpc_call_ref grpc_call_ref

@ -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.h )
s.files += %w( src/core/lib/channel/channel_stack_builder.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/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/channelz_registry.h )
s.files += %w( src/core/lib/channel/connected_channel.h ) s.files += %w( src/core/lib/channel/connected_channel.h )
s.files += %w( src/core/lib/channel/context.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.cc )
s.files += %w( src/core/lib/channel/channel_stack_builder.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/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/channelz_registry.cc )
s.files += %w( src/core/lib/channel/connected_channel.cc ) s.files += %w( src/core/lib/channel/connected_channel.cc )
s.files += %w( src/core/lib/channel/handshaker.cc ) s.files += %w( src/core/lib/channel/handshaker.cc )

@ -256,6 +256,7 @@
'src/core/lib/channel/channel_stack.cc', 'src/core/lib/channel/channel_stack.cc',
'src/core/lib/channel/channel_stack_builder.cc', 'src/core/lib/channel/channel_stack_builder.cc',
'src/core/lib/channel/channel_trace.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/channelz_registry.cc',
'src/core/lib/channel/connected_channel.cc', 'src/core/lib/channel/connected_channel.cc',
'src/core/lib/channel/handshaker.cc', 'src/core/lib/channel/handshaker.cc',
@ -606,6 +607,7 @@
'src/core/lib/channel/channel_stack.cc', 'src/core/lib/channel/channel_stack.cc',
'src/core/lib/channel/channel_stack_builder.cc', 'src/core/lib/channel/channel_stack_builder.cc',
'src/core/lib/channel/channel_trace.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/channelz_registry.cc',
'src/core/lib/channel/connected_channel.cc', 'src/core/lib/channel/connected_channel.cc',
'src/core/lib/channel/handshaker.cc', 'src/core/lib/channel/handshaker.cc',
@ -837,6 +839,7 @@
'src/core/lib/channel/channel_stack.cc', 'src/core/lib/channel/channel_stack.cc',
'src/core/lib/channel/channel_stack_builder.cc', 'src/core/lib/channel/channel_stack_builder.cc',
'src/core/lib/channel/channel_trace.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/channelz_registry.cc',
'src/core/lib/channel/connected_channel.cc', 'src/core/lib/channel/connected_channel.cc',
'src/core/lib/channel/handshaker.cc', 'src/core/lib/channel/handshaker.cc',
@ -1046,6 +1049,7 @@
'src/core/lib/channel/channel_stack.cc', 'src/core/lib/channel/channel_stack.cc',
'src/core/lib/channel/channel_stack_builder.cc', 'src/core/lib/channel/channel_stack_builder.cc',
'src/core/lib/channel/channel_trace.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/channelz_registry.cc',
'src/core/lib/channel/connected_channel.cc', 'src/core/lib/channel/connected_channel.cc',
'src/core/lib/channel/handshaker.cc', 'src/core/lib/channel/handshaker.cc',
@ -2616,6 +2620,7 @@
'test/core/end2end/tests/cancel_before_invoke.cc', 'test/core/end2end/tests/cancel_before_invoke.cc',
'test/core/end2end/tests/cancel_in_a_vacuum.cc', 'test/core/end2end/tests/cancel_in_a_vacuum.cc',
'test/core/end2end/tests/cancel_with_status.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/compressed_payload.cc',
'test/core/end2end/tests/connectivity.cc', 'test/core/end2end/tests/connectivity.cc',
'test/core/end2end/tests/default_host.cc', 'test/core/end2end/tests/default_host.cc',
@ -2707,6 +2712,7 @@
'test/core/end2end/tests/cancel_before_invoke.cc', 'test/core/end2end/tests/cancel_before_invoke.cc',
'test/core/end2end/tests/cancel_in_a_vacuum.cc', 'test/core/end2end/tests/cancel_in_a_vacuum.cc',
'test/core/end2end/tests/cancel_with_status.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/compressed_payload.cc',
'test/core/end2end/tests/connectivity.cc', 'test/core/end2end/tests/connectivity.cc',
'test/core/end2end/tests/default_host.cc', 'test/core/end2end/tests/default_host.cc',

@ -286,14 +286,6 @@ GRPCAPI grpc_channel* grpc_lame_client_channel_create(
/** Close and destroy a grpc channel */ /** Close and destroy a grpc channel */
GRPCAPI void grpc_channel_destroy(grpc_channel* 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);
/** Error handling for grpc_call /** Error handling for grpc_call
Most grpc_call functions return a grpc_error. If the error is not GRPC_OK Most grpc_call functions return a grpc_error. If the error is not GRPC_OK
then the operation failed due to some unsatisfied precondition. then the operation failed due to some unsatisfied precondition.

@ -289,6 +289,10 @@ typedef struct {
* subchannel. The default is 10. If set to 0, channel tracing is disabled. */ * subchannel. The default is 10. If set to 0, channel tracing is disabled. */
#define GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE \ #define GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE \
"grpc.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 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 /** If non-zero, Cronet transport will coalesce packets to fewer frames
* when possible. */ * when possible. */
#define GRPC_ARG_USE_CRONET_PACKET_COALESCING \ #define GRPC_ARG_USE_CRONET_PACKET_COALESCING \

@ -171,8 +171,8 @@ class WriteOptions {
return *this; return *this;
} }
/// Guarantee that all bytes have been written to the wire before completing /// Guarantee that all bytes have been written to the socket before completing
/// this write (usually writes are completed when they pass flow control) /// this write (usually writes are completed when they pass flow control).
inline WriteOptions& set_write_through() { inline WriteOptions& set_write_through() {
SetBit(GRPC_WRITE_THROUGH); SetBit(GRPC_WRITE_THROUGH);
return *this; return *this;

@ -299,6 +299,7 @@
<file baseinstalldir="/" name="src/core/lib/channel/channel_stack.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/channel/channel_stack.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/channel_stack_builder.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/channel/channel_stack_builder.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/channel_trace.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/channel/channel_trace.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/channelz.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/channelz_registry.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/channel/channelz_registry.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/connected_channel.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/channel/connected_channel.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/context.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/channel/context.h" role="src" />
@ -449,6 +450,7 @@
<file baseinstalldir="/" name="src/core/lib/channel/channel_stack.cc" role="src" /> <file baseinstalldir="/" name="src/core/lib/channel/channel_stack.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/channel_stack_builder.cc" role="src" /> <file baseinstalldir="/" name="src/core/lib/channel/channel_stack_builder.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/channel_trace.cc" role="src" /> <file baseinstalldir="/" name="src/core/lib/channel/channel_trace.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/channelz.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/channelz_registry.cc" role="src" /> <file baseinstalldir="/" name="src/core/lib/channel/channelz_registry.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/connected_channel.cc" role="src" /> <file baseinstalldir="/" name="src/core/lib/channel/connected_channel.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/handshaker.cc" role="src" /> <file baseinstalldir="/" name="src/core/lib/channel/handshaker.cc" role="src" />

@ -794,6 +794,15 @@ typedef struct {
// The batch to use in the subchannel call. // The batch to use in the subchannel call.
// Its payload field points to subchannel_call_retry_state.batch_payload. // Its payload field points to subchannel_call_retry_state.batch_payload.
grpc_transport_stream_op_batch batch; 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. // For send_initial_metadata.
// Note that we need to make a copy of the initial metadata for each // 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, // 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_metadata_batch recv_trailing_metadata;
grpc_transport_stream_stats collect_stats; grpc_transport_stream_stats collect_stats;
grpc_closure recv_trailing_metadata_ready; 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 // These fields indicate which ops have been started and completed on
// this subchannel call. // this subchannel call.
size_t started_send_message_count; 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) { static void batch_data_unref(subchannel_batch_data* batch_data) {
if (gpr_unref(&batch_data->refs)) { if (gpr_unref(&batch_data->refs)) {
if (batch_data->send_initial_metadata_storage != nullptr) { subchannel_call_retry_state* retry_state =
grpc_metadata_batch_destroy(&batch_data->send_initial_metadata); static_cast<subchannel_call_retry_state*>(
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) { if (batch_data->batch.send_trailing_metadata) {
grpc_metadata_batch_destroy(&batch_data->send_trailing_metadata); grpc_metadata_batch_destroy(&retry_state->send_trailing_metadata);
} }
if (batch_data->batch.recv_initial_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) { 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"); GRPC_SUBCHANNEL_CALL_UNREF(batch_data->subchannel_call, "batch_data_unref");
call_data* calld = static_cast<call_data*>(batch_data->elem->call_data); call_data* calld = static_cast<call_data*>(batch_data->elem->call_data);
@ -1560,8 +1564,12 @@ static void invoke_recv_initial_metadata_callback(void* arg,
}); });
GPR_ASSERT(pending != nullptr); GPR_ASSERT(pending != nullptr);
// Return metadata. // Return metadata.
subchannel_call_retry_state* retry_state =
static_cast<subchannel_call_retry_state*>(
grpc_connected_subchannel_call_get_parent_data(
batch_data->subchannel_call));
grpc_metadata_batch_move( grpc_metadata_batch_move(
&batch_data->recv_initial_metadata, &retry_state->recv_initial_metadata,
pending->batch->payload->recv_initial_metadata.recv_initial_metadata); pending->batch->payload->recv_initial_metadata.recv_initial_metadata);
// Update bookkeeping. // Update bookkeeping.
// Note: Need to do this before invoking the callback, since invoking // 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 // the recv_trailing_metadata_ready callback, then defer propagating this
// callback back to the surface. We can evaluate whether to retry when // callback back to the surface. We can evaluate whether to retry when
// recv_trailing_metadata comes back. // 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) && error != GRPC_ERROR_NONE) &&
!retry_state->completed_recv_trailing_metadata)) { !retry_state->completed_recv_trailing_metadata)) {
if (grpc_client_channel_trace.enabled()) { 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); GPR_ASSERT(pending != nullptr);
// Return payload. // Return payload.
subchannel_call_retry_state* retry_state =
static_cast<subchannel_call_retry_state*>(
grpc_connected_subchannel_call_get_parent_data(
batch_data->subchannel_call));
*pending->batch->payload->recv_message.recv_message = *pending->batch->payload->recv_message.recv_message =
std::move(batch_data->recv_message); std::move(retry_state->recv_message);
// Update bookkeeping. // Update bookkeeping.
// Note: Need to do this before invoking the callback, since invoking // Note: Need to do this before invoking the callback, since invoking
// the callback will result in yielding the call combiner. // 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 // callback back to the surface. We can evaluate whether to retry when
// recv_trailing_metadata comes back. // recv_trailing_metadata comes back.
if (GPR_UNLIKELY( 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)) { !retry_state->completed_recv_trailing_metadata)) {
if (grpc_client_channel_trace.enabled()) { if (grpc_client_channel_trace.enabled()) {
gpr_log(GPR_INFO, gpr_log(GPR_INFO,
@ -1766,8 +1778,12 @@ static void add_closure_for_recv_trailing_metadata_ready(
return; return;
} }
// Return metadata. // Return metadata.
subchannel_call_retry_state* retry_state =
static_cast<subchannel_call_retry_state*>(
grpc_connected_subchannel_call_get_parent_data(
batch_data->subchannel_call));
grpc_metadata_batch_move( grpc_metadata_batch_move(
&batch_data->recv_trailing_metadata, &retry_state->recv_trailing_metadata,
pending->batch->payload->recv_trailing_metadata.recv_trailing_metadata); pending->batch->payload->recv_trailing_metadata.recv_trailing_metadata);
// Add closure. // Add closure.
closures->Add(pending->batch->payload->recv_trailing_metadata 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. // Add closure for deferred recv_initial_metadata_ready.
if (GPR_UNLIKELY(retry_state->recv_initial_metadata_ready_deferred_batch != if (GPR_UNLIKELY(retry_state->recv_initial_metadata_ready_deferred_batch !=
nullptr)) { nullptr)) {
GRPC_CLOSURE_INIT(&batch_data->recv_initial_metadata_ready, GRPC_CLOSURE_INIT(&retry_state->recv_initial_metadata_ready,
invoke_recv_initial_metadata_callback, invoke_recv_initial_metadata_callback,
retry_state->recv_initial_metadata_ready_deferred_batch, retry_state->recv_initial_metadata_ready_deferred_batch,
grpc_schedule_on_exec_ctx); 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, retry_state->recv_initial_metadata_error,
"resuming recv_initial_metadata_ready"); "resuming recv_initial_metadata_ready");
retry_state->recv_initial_metadata_ready_deferred_batch = nullptr; 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. // Add closure for deferred recv_message_ready.
if (GPR_UNLIKELY(retry_state->recv_message_ready_deferred_batch != if (GPR_UNLIKELY(retry_state->recv_message_ready_deferred_batch !=
nullptr)) { nullptr)) {
GRPC_CLOSURE_INIT(&batch_data->recv_message_ready, GRPC_CLOSURE_INIT(&retry_state->recv_message_ready,
invoke_recv_message_callback, invoke_recv_message_callback,
retry_state->recv_message_ready_deferred_batch, retry_state->recv_message_ready_deferred_batch,
grpc_schedule_on_exec_ctx); grpc_schedule_on_exec_ctx);
closures->Add(&batch_data->recv_message_ready, closures->Add(&retry_state->recv_message_ready,
retry_state->recv_message_error, retry_state->recv_message_error,
"resuming recv_message_ready"); "resuming recv_message_ready");
retry_state->recv_message_ready_deferred_batch = nullptr; 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 // If we've already completed one or more attempts, add the
// grpc-retry-attempts header. // grpc-retry-attempts header.
batch_data->send_initial_metadata_storage = retry_state->send_initial_metadata_storage =
static_cast<grpc_linked_mdelem*>(gpr_arena_alloc( static_cast<grpc_linked_mdelem*>(gpr_arena_alloc(
calld->arena, sizeof(grpc_linked_mdelem) * calld->arena, sizeof(grpc_linked_mdelem) *
(calld->send_initial_metadata.list.count + (calld->send_initial_metadata.list.count +
(calld->num_attempts_completed > 0)))); (calld->num_attempts_completed > 0))));
grpc_metadata_batch_copy(&calld->send_initial_metadata, grpc_metadata_batch_copy(&calld->send_initial_metadata,
&batch_data->send_initial_metadata, &retry_state->send_initial_metadata,
batch_data->send_initial_metadata_storage); retry_state->send_initial_metadata_storage);
if (GPR_UNLIKELY(batch_data->send_initial_metadata.idx.named if (GPR_UNLIKELY(retry_state->send_initial_metadata.idx.named
.grpc_previous_rpc_attempts != nullptr)) { .grpc_previous_rpc_attempts != nullptr)) {
grpc_metadata_batch_remove( grpc_metadata_batch_remove(&retry_state->send_initial_metadata,
&batch_data->send_initial_metadata, retry_state->send_initial_metadata.idx.named
batch_data->send_initial_metadata.idx.named.grpc_previous_rpc_attempts); .grpc_previous_rpc_attempts);
} }
if (GPR_UNLIKELY(calld->num_attempts_completed > 0)) { if (GPR_UNLIKELY(calld->num_attempts_completed > 0)) {
grpc_mdelem retry_md = grpc_mdelem_from_slices( grpc_mdelem retry_md = grpc_mdelem_from_slices(
GRPC_MDSTR_GRPC_PREVIOUS_RPC_ATTEMPTS, GRPC_MDSTR_GRPC_PREVIOUS_RPC_ATTEMPTS,
*retry_count_strings[calld->num_attempts_completed - 1]); *retry_count_strings[calld->num_attempts_completed - 1]);
grpc_error* error = grpc_metadata_batch_add_tail( grpc_error* error = grpc_metadata_batch_add_tail(
&batch_data->send_initial_metadata, &retry_state->send_initial_metadata,
&batch_data->send_initial_metadata_storage[calld->send_initial_metadata &retry_state->send_initial_metadata_storage[calld->send_initial_metadata
.list.count], .list.count],
retry_md); retry_md);
if (GPR_UNLIKELY(error != GRPC_ERROR_NONE)) { if (GPR_UNLIKELY(error != GRPC_ERROR_NONE)) {
gpr_log(GPR_ERROR, "error adding retry metadata: %s", 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; retry_state->started_send_initial_metadata = true;
batch_data->batch.send_initial_metadata = true; batch_data->batch.send_initial_metadata = true;
batch_data->batch.payload->send_initial_metadata.send_initial_metadata = 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 = batch_data->batch.payload->send_initial_metadata.send_initial_metadata_flags =
calld->send_initial_metadata_flags; calld->send_initial_metadata_flags;
batch_data->batch.payload->send_initial_metadata.peer_string = batch_data->batch.payload->send_initial_metadata.peer_string =
@ -2173,10 +2189,10 @@ static void add_retriable_send_message_op(
grpc_core::ByteStreamCache* cache = grpc_core::ByteStreamCache* cache =
(*calld->send_messages)[retry_state->started_send_message_count]; (*calld->send_messages)[retry_state->started_send_message_count];
++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.send_message = true;
batch_data->batch.payload->send_message.send_message.reset( 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. // 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 // 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 // the filters in the subchannel stack may modify this batch, and we don't
// want those modifications to be passed forward to subsequent attempts. // want those modifications to be passed forward to subsequent attempts.
batch_data->send_trailing_metadata_storage = retry_state->send_trailing_metadata_storage =
static_cast<grpc_linked_mdelem*>(gpr_arena_alloc( static_cast<grpc_linked_mdelem*>(gpr_arena_alloc(
calld->arena, sizeof(grpc_linked_mdelem) * calld->arena, sizeof(grpc_linked_mdelem) *
calld->send_trailing_metadata.list.count)); calld->send_trailing_metadata.list.count));
grpc_metadata_batch_copy(&calld->send_trailing_metadata, grpc_metadata_batch_copy(&calld->send_trailing_metadata,
&batch_data->send_trailing_metadata, &retry_state->send_trailing_metadata,
batch_data->send_trailing_metadata_storage); retry_state->send_trailing_metadata_storage);
retry_state->started_send_trailing_metadata = true; retry_state->started_send_trailing_metadata = true;
batch_data->batch.send_trailing_metadata = true; batch_data->batch.send_trailing_metadata = true;
batch_data->batch.payload->send_trailing_metadata.send_trailing_metadata = 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. // 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) { subchannel_batch_data* batch_data) {
retry_state->started_recv_initial_metadata = true; retry_state->started_recv_initial_metadata = true;
batch_data->batch.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->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->batch.payload->recv_initial_metadata.trailing_metadata_available =
&batch_data->trailing_metadata_available; &retry_state->trailing_metadata_available;
GRPC_CLOSURE_INIT(&batch_data->recv_initial_metadata_ready, GRPC_CLOSURE_INIT(&retry_state->recv_initial_metadata_ready,
recv_initial_metadata_ready, batch_data, recv_initial_metadata_ready, batch_data,
grpc_schedule_on_exec_ctx); grpc_schedule_on_exec_ctx);
batch_data->batch.payload->recv_initial_metadata.recv_initial_metadata_ready = 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. // 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; ++retry_state->started_recv_message_count;
batch_data->batch.recv_message = true; batch_data->batch.recv_message = true;
batch_data->batch.payload->recv_message.recv_message = batch_data->batch.payload->recv_message.recv_message =
&batch_data->recv_message; &retry_state->recv_message;
GRPC_CLOSURE_INIT(&batch_data->recv_message_ready, recv_message_ready, GRPC_CLOSURE_INIT(&retry_state->recv_message_ready, recv_message_ready,
batch_data, grpc_schedule_on_exec_ctx); batch_data, grpc_schedule_on_exec_ctx);
batch_data->batch.payload->recv_message.recv_message_ready = 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. // 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) { subchannel_batch_data* batch_data) {
retry_state->started_recv_trailing_metadata = true; retry_state->started_recv_trailing_metadata = true;
batch_data->batch.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->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->batch.payload->recv_trailing_metadata.collect_stats =
&batch_data->collect_stats; &retry_state->collect_stats;
GRPC_CLOSURE_INIT(&batch_data->recv_trailing_metadata_ready, GRPC_CLOSURE_INIT(&retry_state->recv_trailing_metadata_ready,
recv_trailing_metadata_ready, batch_data, recv_trailing_metadata_ready, batch_data,
grpc_schedule_on_exec_ctx); grpc_schedule_on_exec_ctx);
batch_data->batch.payload->recv_trailing_metadata 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 // 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 // started subchannel batch, since we'll propagate the
// completion when it completes. // completion when it completes.
if (retry_state->completed_recv_trailing_metadata) { 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. // Batches containing recv_trailing_metadata always succeed.
closures->Add( 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 " "re-executing recv_trailing_metadata_ready to propagate "
"internally triggered result"); "internally triggered result");
} else { } else {

@ -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, static void report_stall(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
const char* staller) { const char* staller) {
gpr_log( if (grpc_flowctl_trace.enabled()) {
GPR_DEBUG, gpr_log(
"%s:%p stream %d stalled by %s [fc:pending=%" PRIdPTR GPR_DEBUG,
":pending-compressed=%" PRIdPTR ":flowed=%" PRId64 "%s:%p stream %d moved to stalled list by %s. This is FULLY expected "
":peer_initwin=%d:t_win=%" PRId64 ":s_win=%d:s_delta=%" PRId64 "]", "to happen in a healthy program that is not seeing flow control stalls."
t->peer_string, t, s->id, staller, s->flow_controlled_buffer.length, " However, if you know that there are unwanted stalls, here is some "
s->compressed_data_buffer.length, s->flow_controlled_bytes_flowed, "helpful data: [fc:pending=%" PRIdPTR ":pending-compressed=%" PRIdPTR
t->settings[GRPC_ACKED_SETTINGS] ":flowed=%" PRId64 ":peer_initwin=%d:t_win=%" PRId64
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE], ":s_win=%d:s_delta=%" PRId64 "]",
t->flow_control->remote_window(), t->peer_string, t, s->id, staller, s->flow_controlled_buffer.length,
static_cast<uint32_t> GPR_MAX( s->compressed_data_buffer.length, s->flow_controlled_bytes_flowed,
0, t->settings[GRPC_ACKED_SETTINGS]
s->flow_control->remote_window_delta() + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
(int64_t)t->settings[GRPC_PEER_SETTINGS] t->flow_control->remote_window(),
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]), static_cast<uint32_t> GPR_MAX(
s->flow_control->remote_window_delta()); 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) { static bool stream_ref_if_not_destroyed(gpr_refcount* r) {

@ -28,7 +28,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "src/core/lib/channel/channelz_registry.h"
#include "src/core/lib/channel/status_util.h" #include "src/core/lib/channel/status_util.h"
#include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h" #include "src/core/lib/gpr/useful.h"
@ -40,16 +39,17 @@
#include "src/core/lib/transport/error_utils.h" #include "src/core/lib/transport/error_utils.h"
namespace grpc_core { namespace grpc_core {
namespace channelz {
ChannelTrace::TraceEvent::TraceEvent( ChannelTrace::TraceEvent::TraceEvent(
Severity severity, grpc_slice data, Severity severity, grpc_slice data,
RefCountedPtr<ChannelTrace> referenced_tracer, ReferencedType type) RefCountedPtr<ChannelNode> referenced_channel, ReferencedType type)
: severity_(severity), : severity_(severity),
data_(data), data_(data),
timestamp_(grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(), timestamp_(grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(),
GPR_CLOCK_REALTIME)), GPR_CLOCK_REALTIME)),
next_(nullptr), next_(nullptr),
referenced_tracer_(std::move(referenced_tracer)), referenced_channel_(std::move(referenced_channel)),
referenced_type_(type) {} referenced_type_(type) {}
ChannelTrace::TraceEvent::TraceEvent(Severity severity, grpc_slice data) ChannelTrace::TraceEvent::TraceEvent(Severity severity, grpc_slice data)
@ -62,15 +62,13 @@ ChannelTrace::TraceEvent::TraceEvent(Severity severity, grpc_slice data)
ChannelTrace::TraceEvent::~TraceEvent() { grpc_slice_unref_internal(data_); } ChannelTrace::TraceEvent::~TraceEvent() { grpc_slice_unref_internal(data_); }
ChannelTrace::ChannelTrace(size_t max_events) ChannelTrace::ChannelTrace(size_t max_events)
: channel_uuid_(-1), : num_events_logged_(0),
num_events_logged_(0),
list_size_(0), list_size_(0),
max_list_size_(max_events), max_list_size_(max_events),
head_trace_(nullptr), head_trace_(nullptr),
tail_trace_(nullptr) { tail_trace_(nullptr) {
if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0 if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0
gpr_mu_init(&tracer_mu_); gpr_mu_init(&tracer_mu_);
channel_uuid_ = ChannelzRegistry::Register(this);
time_created_ = grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(), time_created_ = grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(),
GPR_CLOCK_REALTIME); GPR_CLOCK_REALTIME);
} }
@ -83,12 +81,9 @@ ChannelTrace::~ChannelTrace() {
it = it->next(); it = it->next();
Delete<TraceEvent>(to_free); Delete<TraceEvent>(to_free);
} }
ChannelzRegistry::Unregister(channel_uuid_);
gpr_mu_destroy(&tracer_mu_); gpr_mu_destroy(&tracer_mu_);
} }
intptr_t ChannelTrace::GetUuid() const { return channel_uuid_; }
void ChannelTrace::AddTraceEventHelper(TraceEvent* new_trace_event) { void ChannelTrace::AddTraceEventHelper(TraceEvent* new_trace_event) {
++num_events_logged_; ++num_events_logged_;
// first event case // first event case
@ -117,20 +112,21 @@ void ChannelTrace::AddTraceEvent(Severity severity, grpc_slice data) {
void ChannelTrace::AddTraceEventReferencingChannel( void ChannelTrace::AddTraceEventReferencingChannel(
Severity severity, grpc_slice data, Severity severity, grpc_slice data,
RefCountedPtr<ChannelTrace> referenced_tracer) { RefCountedPtr<ChannelNode> referenced_channel) {
if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0 if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0
// create and fill up the new event // create and fill up the new event
AddTraceEventHelper( AddTraceEventHelper(New<TraceEvent>(
New<TraceEvent>(severity, data, std::move(referenced_tracer), Channel)); severity, data, std::move(referenced_channel), ReferencedType::Channel));
} }
void ChannelTrace::AddTraceEventReferencingSubchannel( void ChannelTrace::AddTraceEventReferencingSubchannel(
Severity severity, grpc_slice data, Severity severity, grpc_slice data,
RefCountedPtr<ChannelTrace> referenced_tracer) { RefCountedPtr<ChannelNode> referenced_subchannel) {
if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0 if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0
// create and fill up the new event // create and fill up the new event
AddTraceEventHelper(New<TraceEvent>( AddTraceEventHelper(New<TraceEvent>(severity, data,
severity, data, std::move(referenced_tracer), Subchannel)); std::move(referenced_subchannel),
ReferencedType::Subchannel));
} }
namespace { namespace {
@ -193,22 +189,24 @@ void ChannelTrace::TraceEvent::RenderTraceEvent(grpc_json* json) const {
json_iterator = json_iterator =
grpc_json_create_child(json_iterator, json, "timestamp", grpc_json_create_child(json_iterator, json, "timestamp",
fmt_time(timestamp_), GRPC_JSON_STRING, true); fmt_time(timestamp_), GRPC_JSON_STRING, true);
if (referenced_tracer_ != nullptr) { if (referenced_channel_ != nullptr) {
char* uuid_str; 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( grpc_json* child_ref = grpc_json_create_child(
json_iterator, json, json_iterator, json,
(referenced_type_ == Channel) ? "channelRef" : "subchannelRef", nullptr, (referenced_type_ == ReferencedType::Channel) ? "channelRef"
GRPC_JSON_OBJECT, false); : "subchannelRef",
nullptr, GRPC_JSON_OBJECT, false);
json_iterator = grpc_json_create_child( json_iterator = grpc_json_create_child(
nullptr, child_ref, nullptr, child_ref,
(referenced_type_ == Channel) ? "channelId" : "subchannelId", uuid_str, (referenced_type_ == ReferencedType::Channel) ? "channelId"
GRPC_JSON_STRING, true); : "subchannelId",
uuid_str, GRPC_JSON_STRING, true);
json_iterator = child_ref; json_iterator = child_ref;
} }
} }
char* ChannelTrace::RenderTrace() const { grpc_json* ChannelTrace::RenderJSON() const {
if (!max_list_size_) if (!max_list_size_)
return nullptr; // tracing is disabled if max_events == 0 return nullptr; // tracing is disabled if max_events == 0
grpc_json* json = grpc_json_create(GRPC_JSON_OBJECT); grpc_json* json = grpc_json_create(GRPC_JSON_OBJECT);
@ -219,7 +217,7 @@ char* ChannelTrace::RenderTrace() const {
grpc_json_create_child(json_iterator, json, "numEventsLogged", grpc_json_create_child(json_iterator, json, "numEventsLogged",
num_events_logged_str, GRPC_JSON_STRING, true); num_events_logged_str, GRPC_JSON_STRING, true);
json_iterator = 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); fmt_time(time_created_), GRPC_JSON_STRING, true);
grpc_json* events = grpc_json_create_child(json_iterator, json, "events", grpc_json* events = grpc_json_create_child(json_iterator, json, "events",
nullptr, GRPC_JSON_ARRAY, false); nullptr, GRPC_JSON_ARRAY, false);
@ -231,9 +229,8 @@ char* ChannelTrace::RenderTrace() const {
it->RenderTraceEvent(json_iterator); it->RenderTraceEvent(json_iterator);
it = it->next(); it = it->next();
} }
char* json_str = grpc_json_dump_to_string(json, 0); return json;
grpc_json_destroy(json);
return json_str;
} }
} // namespace channelz
} // namespace grpc_core } // namespace grpc_core

@ -28,18 +28,18 @@
#include "src/core/lib/json/json.h" #include "src/core/lib/json/json.h"
namespace grpc_core { namespace grpc_core {
namespace channelz {
class ChannelNode;
// Object used to hold live data for a channel. This data is exposed via the // Object used to hold live data for a channel. This data is exposed via the
// channelz service: // channelz service:
// https://github.com/grpc/proposal/blob/master/A14-channelz.md // https://github.com/grpc/proposal/blob/master/A14-channelz.md
class ChannelTrace : public RefCounted<ChannelTrace> { class ChannelTrace {
public: public:
ChannelTrace(size_t max_events); ChannelTrace(size_t max_events);
~ChannelTrace(); ~ChannelTrace();
// returns the tracer's uuid
intptr_t GetUuid() const;
enum Severity { enum Severity {
Unset = 0, // never to be used Unset = 0, // never to be used
Info, // we start at 1 to avoid using proto default values Info, // we start at 1 to avoid using proto default values
@ -59,34 +59,30 @@ class ChannelTrace : public RefCounted<ChannelTrace> {
// created a new subchannel, then it would record that with a TraceEvent // created a new subchannel, then it would record that with a TraceEvent
// referencing the new subchannel. // 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 // 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 // stack, determine if it makes more sense to accept a char* instead of a
// slice. // slice.
void AddTraceEventReferencingChannel( void AddTraceEventReferencingChannel(
Severity severity, grpc_slice data, Severity severity, grpc_slice data,
RefCountedPtr<ChannelTrace> referenced_tracer); RefCountedPtr<ChannelNode> referenced_channel);
void AddTraceEventReferencingSubchannel( void AddTraceEventReferencingSubchannel(
Severity severity, grpc_slice data, Severity severity, grpc_slice data,
RefCountedPtr<ChannelTrace> referenced_tracer); RefCountedPtr<ChannelNode> referenced_subchannel);
// Returns the tracing data rendered as a grpc json string. // Creates and returns the raw grpc_json object, so a parent channelz
// The string is owned by the caller and must be freed. // object may incorporate the json before rendering.
char* RenderTrace() const; grpc_json* RenderJSON() const;
private: private:
// Types of objects that can be references by trace events. // 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 // Private class to encapsulate all the data and bookkeeping needed for a
// a trace event. // a trace event.
class TraceEvent { class TraceEvent {
public: public:
// Constructor for a TraceEvent that references a different channel. // 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, TraceEvent(Severity severity, grpc_slice data,
RefCountedPtr<ChannelTrace> referenced_tracer, RefCountedPtr<ChannelNode> referenced_channel,
ReferencedType type); ReferencedType type);
// Constructor for a TraceEvent that does not reverence a different // Constructor for a TraceEvent that does not reverence a different
@ -109,7 +105,7 @@ class ChannelTrace : public RefCounted<ChannelTrace> {
gpr_timespec timestamp_; gpr_timespec timestamp_;
TraceEvent* next_; TraceEvent* next_;
// the tracer object for the (sub)channel that this trace event refers to. // the tracer object for the (sub)channel that this trace event refers to.
RefCountedPtr<ChannelTrace> referenced_tracer_; RefCountedPtr<ChannelNode> referenced_channel_;
// the type that the referenced tracer points to. Unused if this trace // the type that the referenced tracer points to. Unused if this trace
// does not point to any channel or subchannel // does not point to any channel or subchannel
ReferencedType referenced_type_; ReferencedType referenced_type_;
@ -119,7 +115,6 @@ class ChannelTrace : public RefCounted<ChannelTrace> {
void AddTraceEventHelper(TraceEvent* new_trace_event); void AddTraceEventHelper(TraceEvent* new_trace_event);
gpr_mu tracer_mu_; gpr_mu tracer_mu_;
intptr_t channel_uuid_;
uint64_t num_events_logged_; uint64_t num_events_logged_;
size_t list_size_; size_t list_size_;
size_t max_list_size_; size_t max_list_size_;
@ -128,6 +123,7 @@ class ChannelTrace : public RefCounted<ChannelTrace> {
gpr_timespec time_created_; gpr_timespec time_created_;
}; };
} // namespace channelz
} // namespace grpc_core } // namespace grpc_core
#endif /* GRPC_CORE_LIB_CHANNEL_CHANNEL_TRACE_H */ #endif /* GRPC_CORE_LIB_CHANNEL_CHANNEL_TRACE_H */

@ -0,0 +1,185 @@
/*
*
* 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 <grpc/impl/codegen/port_platform.h>
#include "src/core/lib/channel/channelz.h"
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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"
namespace grpc_core {
namespace channelz {
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
//
// "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,
int64_t num) {
char* num_str;
gpr_asprintf(&num_str, "%" PRId64, num);
return grpc_json_create_child(it, parent, name, num_str, GRPC_JSON_STRING,
true);
}
} // namespace
ChannelNode::ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes)
: channel_(channel), target_(nullptr), channel_uuid_(-1) {
trace_.Init(channel_tracer_max_nodes);
target_ = UniquePtr<char>(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();
ChannelzRegistry::Unregister(channel_uuid_);
}
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 ChannelNode::GetConnectivityState() {
if (channel_ == nullptr) {
return GRPC_CHANNEL_SHUTDOWN;
} else {
return grpc_channel_check_connectivity_state(channel_, false);
}
}
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;
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,
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_.get(), GRPC_JSON_STRING, false);
// fill in the channel trace if applicable
grpc_json* trace = trace_->RenderJSON();
if (trace != nullptr) {
// 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_);
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 =
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);
return json_str;
}
} // namespace channelz
} // namespace grpc_core

@ -0,0 +1,85 @@
/*
*
* 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 <grpc/impl/codegen/port_platform.h>
#include <grpc/grpc.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"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/json/json.h"
namespace grpc_core {
namespace channelz {
namespace testing {
class ChannelNodePeer;
}
class ChannelNode : public RefCounted<ChannelNode> {
public:
ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes);
~ChannelNode();
void RecordCallStarted();
void RecordCallFailed() {
gpr_atm_no_barrier_fetch_add(&calls_failed_, (gpr_atm(1)));
}
void RecordCallSucceeded() {
gpr_atm_no_barrier_fetch_add(&calls_succeeded_, (gpr_atm(1)));
}
char* RenderJSON();
ChannelTrace* trace() { return trace_.get(); }
void set_channel_destroyed() {
GPR_ASSERT(channel_ != nullptr);
channel_ = nullptr;
}
intptr_t channel_uuid() { return channel_uuid_; }
private:
// testing peer friend.
friend class testing::ChannelNodePeer;
// helper for getting connectivity state.
grpc_connectivity_state GetConnectivityState();
grpc_channel* channel_ = nullptr;
UniquePtr<char> target_;
gpr_atm calls_started_ = 0;
gpr_atm calls_succeeded_ = 0;
gpr_atm calls_failed_ = 0;
gpr_atm last_call_started_millis_ = 0;
intptr_t channel_uuid_;
ManualConstructor<ChannelTrace> trace_;
};
} // namespace channelz
} // namespace grpc_core
#endif /* GRPC_CORE_LIB_CHANNEL_CHANNELZ_H */

@ -23,12 +23,21 @@
#include <stddef.h> #include <stddef.h>
// 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 */ /* A wrapper for htons on POSIX and Windows */
uint16_t grpc_htons(uint16_t hostshort); uint16_t grpc_htons(uint16_t hostshort);
/* A wrapper for ntohs on POSIX and WINDOWS */ /* A wrapper for ntohs on POSIX and WINDOWS */
uint16_t grpc_ntohs(uint16_t netshort); 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 */ /* A wrapper for inet_pton on POSIX and WINDOWS */
int grpc_inet_pton(int af, const char* src, void* dst); int grpc_inet_pton(int af, const char* src, void* dst);

@ -339,6 +339,10 @@ uint16_t grpc_htons(uint16_t hostshort) { return htons(hostshort); }
uint16_t grpc_ntohs(uint16_t netshort) { return ntohs(netshort); } 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) { int grpc_inet_pton(int af, const char* src, void* dst) {
return inet_pton(af, src, dst); return inet_pton(af, src, dst);
} }

@ -33,6 +33,10 @@ uint16_t grpc_htons(uint16_t hostshort) { return htons(hostshort); }
uint16_t grpc_ntohs(uint16_t netshort) { return ntohs(netshort); } 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) { int grpc_inet_pton(int af, const char* src, void* dst) {
return inet_pton(af, src, dst); return inet_pton(af, src, dst);
} }

@ -31,6 +31,10 @@ uint16_t grpc_htons(uint16_t hostshort) { return htons(hostshort); }
uint16_t grpc_ntohs(uint16_t netshort) { return ntohs(netshort); } 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) { int grpc_inet_pton(int af, const char* src, void* dst) {
return inet_pton(af, src, dst); return inet_pton(af, src, dst);
} }

@ -489,6 +489,12 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args,
&call->pollent); &call->pollent);
} }
grpc_core::channelz::ChannelNode* channelz_channel =
grpc_channel_get_channelz_node(call->channel);
if (channelz_channel != nullptr) {
channelz_channel->RecordCallStarted();
}
grpc_slice_unref_internal(path); grpc_slice_unref_internal(path);
return error; return error;
@ -531,7 +537,6 @@ static void release_call(void* call, grpc_error* error) {
GRPC_CHANNEL_INTERNAL_UNREF(channel, "call"); 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) { static void destroy_call(void* call, grpc_error* error) {
GPR_TIMER_SCOPE("destroy_call", 0); GPR_TIMER_SCOPE("destroy_call", 0);
size_t i; size_t i;
@ -1087,13 +1092,12 @@ static void recv_trailing_filter(void* args, grpc_metadata_batch* b) {
if (b->idx.named.grpc_status != nullptr) { if (b->idx.named.grpc_status != nullptr) {
grpc_status_code status_code = grpc_status_code status_code =
grpc_get_status_code_from_metadata(b->idx.named.grpc_status->md); grpc_get_status_code_from_metadata(b->idx.named.grpc_status->md);
grpc_error* error = grpc_error* error = GRPC_ERROR_NONE;
status_code == GRPC_STATUS_OK if (status_code != GRPC_STATUS_OK) {
? GRPC_ERROR_NONE error = grpc_error_set_int(
: grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING( GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error received from peer"),
"Error received from peer"), GRPC_ERROR_INT_GRPC_STATUS, static_cast<intptr_t>(status_code));
GRPC_ERROR_INT_GRPC_STATUS, }
static_cast<intptr_t>(status_code));
if (b->idx.named.grpc_message != nullptr) { if (b->idx.named.grpc_message != nullptr) {
error = grpc_error_set_str( error = grpc_error_set_str(
error, GRPC_ERROR_STR_GRPC_MESSAGE, error, GRPC_ERROR_STR_GRPC_MESSAGE,
@ -1260,6 +1264,15 @@ static void post_batch_completion(batch_control* bctl) {
get_final_status(call, set_cancelled_value, get_final_status(call, set_cancelled_value,
call->final_op.server.cancelled, nullptr, nullptr); call->final_op.server.cancelled, nullptr, nullptr);
} }
grpc_core::channelz::ChannelNode* channelz_channel =
grpc_channel_get_channelz_node(call->channel);
if (channelz_channel != nullptr) {
if (*call->final_op.client.status != GRPC_STATUS_OK) {
channelz_channel->RecordCallFailed();
} else {
channelz_channel->RecordCallSucceeded();
}
}
GRPC_ERROR_UNREF(error); GRPC_ERROR_UNREF(error);
error = GRPC_ERROR_NONE; error = GRPC_ERROR_NONE;
} }

@ -32,6 +32,7 @@
#include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/channel_trace.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/debug/stats.h"
#include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/manual_constructor.h" #include "src/core/lib/gprpp/manual_constructor.h"
@ -66,7 +67,7 @@ struct grpc_channel {
gpr_mu registered_call_mu; gpr_mu registered_call_mu;
registered_call* registered_calls; registered_call* registered_calls;
grpc_core::RefCountedPtr<grpc_core::ChannelTrace> tracer; grpc_core::RefCountedPtr<grpc_core::channelz::ChannelNode> channelz_channel;
char* target; char* target;
}; };
@ -103,6 +104,7 @@ grpc_channel* grpc_channel_create_with_builder(
channel->target = target; channel->target = target;
channel->is_client = grpc_channel_stack_type_is_client(channel_stack_type); channel->is_client = grpc_channel_stack_type_is_client(channel_stack_type);
size_t channel_tracer_max_nodes = 0; // default to off size_t channel_tracer_max_nodes = 0; // default to off
bool channelz_enabled = false;
gpr_mu_init(&channel->registered_call_mu); gpr_mu_init(&channel->registered_call_mu);
channel->registered_calls = nullptr; channel->registered_calls = nullptr;
@ -141,15 +143,20 @@ grpc_channel* grpc_channel_create_with_builder(
const grpc_integer_options options = {0, 0, INT_MAX}; const grpc_integer_options options = {0, 0, INT_MAX};
channel_tracer_max_nodes = channel_tracer_max_nodes =
(size_t)grpc_channel_arg_get_integer(&args->args[i], options); (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); grpc_channel_args_destroy(args);
channel->tracer = grpc_core::MakeRefCounted<grpc_core::ChannelTrace>( if (channelz_enabled) {
channel_tracer_max_nodes); channel->channelz_channel =
channel->tracer->AddTraceEvent( grpc_core::MakeRefCounted<grpc_core::channelz::ChannelNode>(
grpc_core::ChannelTrace::Severity::Info, channel, channel_tracer_max_nodes);
grpc_slice_from_static_string("Channel created")); channel->channelz_channel->trace()->AddTraceEvent(
grpc_core::channelz::ChannelTrace::Severity::Info,
grpc_slice_from_static_string("Channel created"));
}
return channel; return channel;
} }
@ -184,12 +191,9 @@ static grpc_channel_args* build_channel_args(
return grpc_channel_args_copy_and_add(input_args, new_args, num_new_args); return grpc_channel_args_copy_and_add(input_args, new_args, num_new_args);
} }
char* grpc_channel_get_trace(grpc_channel* channel) { grpc_core::channelz::ChannelNode* grpc_channel_get_channelz_node(
return channel->tracer->RenderTrace(); grpc_channel* channel) {
} return channel->channelz_channel.get();
intptr_t grpc_channel_get_uuid(grpc_channel* channel) {
return channel->tracer->GetUuid();
} }
grpc_channel* grpc_channel_create(const char* target, grpc_channel* grpc_channel_create(const char* target,
@ -395,6 +399,10 @@ void grpc_channel_internal_unref(grpc_channel* c REF_ARG) {
static void destroy_channel(void* arg, grpc_error* error) { static void destroy_channel(void* arg, grpc_error* error) {
grpc_channel* channel = static_cast<grpc_channel*>(arg); grpc_channel* channel = static_cast<grpc_channel*>(arg);
if (channel->channelz_channel != nullptr) {
channel->channelz_channel->set_channel_destroyed();
channel->channelz_channel.reset();
}
grpc_channel_stack_destroy(CHANNEL_STACK_FROM_CHANNEL(channel)); grpc_channel_stack_destroy(CHANNEL_STACK_FROM_CHANNEL(channel));
while (channel->registered_calls) { while (channel->registered_calls) {
registered_call* rc = channel->registered_calls; registered_call* rc = channel->registered_calls;
@ -403,7 +411,6 @@ static void destroy_channel(void* arg, grpc_error* error) {
GRPC_MDELEM_UNREF(rc->authority); GRPC_MDELEM_UNREF(rc->authority);
gpr_free(rc); gpr_free(rc);
} }
channel->tracer.reset();
gpr_mu_destroy(&channel->registered_call_mu); gpr_mu_destroy(&channel->registered_call_mu);
gpr_free(channel->target); gpr_free(channel->target);
gpr_free(channel); gpr_free(channel);

@ -23,6 +23,7 @@
#include "src/core/lib/channel/channel_stack.h" #include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/channel/channel_stack_builder.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" #include "src/core/lib/surface/channel_stack_type.h"
grpc_channel* grpc_channel_create(const char* target, grpc_channel* grpc_channel_create(const char* target,
@ -50,6 +51,9 @@ grpc_call* grpc_channel_create_pollset_set_call(
/** Get a (borrowed) pointer to this channels underlying channel stack */ /** Get a (borrowed) pointer to this channels underlying channel stack */
grpc_channel_stack* grpc_channel_get_channel_stack(grpc_channel* channel); grpc_channel_stack* grpc_channel_get_channel_stack(grpc_channel* channel);
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 /** Get a grpc_mdelem of grpc-status: X where X is the numeric value of
status_code. status_code.

@ -1,13 +1,62 @@
# Overview # 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 # To start using gRPC C++
[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`.
# 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 You can find out how to build and run our simplest gRPC C++ example in our
[C++ quick start](../../examples/cpp). [C++ quick start](../../examples/cpp).
@ -25,7 +74,6 @@ documentation site at [grpc.io](https://grpc.io), specifically:
APIs. APIs.
# Examples # To start developing gRPC C++
Code examples for gRPC C++ live in this repository's For instructions on how to build gRPC C++ from source, follow the [Building gRPC C++](../../BUILDING.md) instructions.
[examples/cpp](../../examples/cpp) directory.

@ -119,8 +119,10 @@ void CensusClientCallData::StartTransportStreamOpBatch(
} }
if (op->recv_trailing_metadata() != nullptr) { if (op->recv_trailing_metadata() != nullptr) {
recv_trailing_metadata_ = op->recv_trailing_metadata()->batch(); recv_trailing_metadata_ = op->recv_trailing_metadata()->batch();
initial_on_done_recv_trailing_metadata_ = op->on_complete(); initial_on_done_recv_trailing_metadata_ =
op->set_on_complete(&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. // Call next op.
grpc_call_next_op(elem, op->op()); grpc_call_next_op(elem, op->op());

@ -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) - [dotnet SDK](https://www.microsoft.com/net/core)
- [Mono 4+](https://www.mono-project.com/) (only needed for Linux and MacOS) - [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. to be able to compile the native code.
**Windows, Linux or Mac OS X** **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. 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 [Helloworld Example]: ../../examples/csharp/helloworld
[RouteGuide Tutorial]: https://grpc.io/docs/tutorials/basic/csharp.html [RouteGuide Tutorial]: https://grpc.io/docs/tutorials/basic/csharp.html

@ -1,4 +1,4 @@
// Copyright 2018 gRPC authors. // Copyright 2018 The gRPC Authors
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with 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 // See the License for the specific language governing permissions and
// limitations under the License. // 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"; syntax = "proto3";
package grpc.channelz; package grpc.channelz.v1;
import "google/protobuf/any.proto"; import "google/protobuf/any.proto";
import "google/protobuf/duration.proto"; import "google/protobuf/duration.proto";
import "google/protobuf/timestamp.proto"; import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.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. // Channel is a logical grouping of channels, subchannels, and sockets.
message Channel { message Channel {
// The identifier for this channel. // The identifier for this channel. This should bet set.
ChannelRef ref = 1; ChannelRef ref = 1;
// Data specific to this channel. // Data specific to this channel.
ChannelData data = 2; ChannelData data = 2;
@ -43,7 +53,7 @@ message Channel {
repeated SubchannelRef subchannel_ref = 4; repeated SubchannelRef subchannel_ref = 4;
// There are no ordering guarantees on the order of sockets. // 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. // Subchannel is a logical grouping of channels, subchannels, and sockets.
@ -67,7 +77,7 @@ message Subchannel {
repeated SubchannelRef subchannel_ref = 4; repeated SubchannelRef subchannel_ref = 4;
// There are no ordering guarantees on the order of sockets. // 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: // These come from the specified states in this document:
@ -84,20 +94,23 @@ message ChannelConnectivityState {
State state = 1; State state = 1;
} }
// Channel data is data related to a specific Channel or Subchannel.
message ChannelData { message ChannelData {
// The connectivity state of the channel or subchannel. Implementations
// should always set this.
ChannelConnectivityState state = 1; ChannelConnectivityState state = 1;
// The target this channel originally tried to connect to. May be absent // The target this channel originally tried to connect to. May be absent
string target = 2; string target = 2;
// A trace of recent events on the channel. May be absent.
ChannelTrace trace = 3; ChannelTrace trace = 3;
// The number of calls started on the channel // The number of calls started on the channel
int64 calls_started = 4; int64 calls_started = 4;
// The number of calls that have completed with an OK status // The number of calls that have completed with an OK status
int64 calls_succeeded = 5; 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; int64 calls_failed = 6;
// The last time a call was started on the channel. // 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 { message ChannelTrace {
// Number of events ever logged in this tracing object. This can differ from // Number of events ever logged in this tracing object. This can differ from
// events.size() because events can be overwritten or garbage collected by // events.size() because events can be overwritten or garbage collected by
// implementations. // implementations.
int64 num_events_logged = 1; int64 num_events_logged = 1;
// Time that this channel was created. // 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. // List of events that have occurred on this channel.
repeated ChannelTraceEvent events = 3; repeated ChannelTraceEvent events = 3;
} }
// ChannelRef is a reference to a Channel.
message ChannelRef { message ChannelRef {
// The globally unique id for this channel. Must be a positive number. // The globally unique id for this channel. Must be a positive number.
int64 channel_id = 1; int64 channel_id = 1;
// An optional name associated with the channel. // An optional name associated with the channel.
string name = 2; string name = 2;
// Intentionally don't use field numbers from other refs. // 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 { message SubchannelRef {
// The globally unique id for this subchannel. Must be a positive number. // The globally unique id for this subchannel. Must be a positive number.
int64 subchannel_id = 7; int64 subchannel_id = 7;
@ -159,6 +175,7 @@ message SubchannelRef {
reserved 1, 2, 3, 4, 5, 6; reserved 1, 2, 3, 4, 5, 6;
} }
// SocketRef is a reference to a Socket.
message SocketRef { message SocketRef {
int64 socket_id = 3; int64 socket_id = 3;
// An optional name associated with the socket. // An optional name associated with the socket.
@ -167,8 +184,9 @@ message SocketRef {
reserved 1, 2, 5, 6, 7, 8; reserved 1, 2, 5, 6, 7, 8;
} }
// ServerRef is a reference to a Server.
message ServerRef { 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; int64 server_id = 5;
// An optional name associated with the server. // An optional name associated with the server.
string name = 6; string name = 6;
@ -176,16 +194,22 @@ message ServerRef {
reserved 1, 2, 3, 4, 7, 8; reserved 1, 2, 3, 4, 7, 8;
} }
// Server represents a single server. There may be multiple servers in a single
// program.
message Server { message Server {
// The identifier for a Server. This should be set.
ServerRef ref = 1; ServerRef ref = 1;
// The associated data of the Server.
ServerData data = 2; ServerData data = 2;
// The sockets that the server is listening on. There are no ordering // The sockets that the server is listening on. There are no ordering
// guarantees. // guarantees. This may be absent.
repeated SocketRef listen_socket = 3; repeated SocketRef listen_socket = 3;
} }
// ServerData is data for a specific Server.
message ServerData { message ServerData {
// A trace of recent events on the server. May be absent.
ChannelTrace trace = 1; ChannelTrace trace = 1;
// The number of incoming calls started on the server // The number of incoming calls started on the server
@ -201,13 +225,17 @@ message ServerData {
// Information about an actual connection. Pronounced "sock-ay". // Information about an actual connection. Pronounced "sock-ay".
message Socket { message Socket {
// The identifier for the Socket.
SocketRef ref = 1; SocketRef ref = 1;
// Data specific to this Socket.
SocketData data = 2; SocketData data = 2;
// The locally bound address. // The locally bound address.
Address local = 3; Address local = 3;
// The remote bound address. May be absent. // The remote bound address. May be absent.
Address remote = 4; 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; Security security = 5;
// Optional, represents the name of the remote endpoint, if different than // Optional, represents the name of the remote endpoint, if different than
@ -215,17 +243,23 @@ message Socket {
string remote_name = 6; 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 { message SocketData {
// The number of streams that have been started. // The number of streams that have been started.
int64 streams_started = 1; int64 streams_started = 1;
// The number of streams that have ended successfully with the EoS bit set for // The number of streams that have ended successfully:
// both end points // On client side, received frame with eos bit set;
// On server side, sent frame with eos bit set.
int64 streams_succeeded = 2; 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; int64 streams_failed = 3;
// The number of grpc messages successfully sent on this socket.
// The number of messages successfully sent on this socket.
int64 messages_sent = 4; int64 messages_sent = 4;
// The number of grpc messages received on this socket.
int64 messages_received = 5; int64 messages_received = 5;
// The number of keep alives sent. This is typically implemented with HTTP/2 // 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. // include stream level or TCP level flow control info.
google.protobuf.Int64Value remote_flow_control_window = 12; google.protobuf.Int64Value remote_flow_control_window = 12;
// Socket options set on this socket. May be absent.
repeated SocketOption option = 13; repeated SocketOption option = 13;
} }
// Address represents the address used to create the socket.
message Address { message Address {
message TcpIpAddress { 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 in length.
bytes ip_address = 1; bytes ip_address = 1;
// 0-64k, or -1 if not appropriate. // 0-64k, or -1 if not appropriate.
@ -271,7 +307,7 @@ message Address {
} }
// An address type not included above. // An address type not included above.
message OtherAddress { message OtherAddress {
// The human readable version of the value. // The human readable version of the value. This value should be set.
string name = 1; string name = 1;
// The actual address message. // The actual address message.
google.protobuf.Any value = 2; google.protobuf.Any value = 2;
@ -284,12 +320,17 @@ message Address {
} }
} }
// Security represents details about how secure the socket is.
message Security { message Security {
message Tls { message Tls {
// The key exchange used. e.g. X25519 oneof cipher_suite {
string key_exchange = 1; // The cipher suite name in the RFC 4346 format:
// The cipher used. e.g. AES_128_GCM. // https://tools.ietf.org/html/rfc4346#appendix-C
string cipher = 2; 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. // the certificate used by this endpoint.
bytes local_certificate = 3; bytes local_certificate = 3;
// the certificate used by the remote endpoint. // 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 { message SocketOption {
// The full name of the socket option. Typically this will be the upper case
// name, such as "SO_REUSEPORT".
string name = 1; string name = 1;
// The human readable value of this socket option. At least one of value or // The human readable value of this socket option. At least one of value or
// additional will be set. // additional will be set.
@ -323,12 +368,17 @@ message SocketOptionTimeout {
google.protobuf.Duration duration = 1; google.protobuf.Duration duration = 1;
} }
// For use with SocketOption's additional field. This is primarily used for
// SO_LINGER.
message SocketOptionLinger { message SocketOptionLinger {
// active maps to `struct linger.l_onoff`
bool active = 1; bool active = 1;
// duration maps to `struct linger.l_linger`
google.protobuf.Duration duration = 2; 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 { message SocketOptionTcpInfo {
uint32 tcpi_state = 1; uint32 tcpi_state = 1;
@ -366,8 +416,10 @@ message SocketOptionTcpInfo {
uint32 tcpi_reordering = 29; uint32 tcpi_reordering = 29;
} }
// Channelz is a service exposed by gRPC servers that provides detailed debug
// information.
service Channelz { 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. // created). This does not include subchannels nor non-top level channels.
rpc GetTopChannels(GetTopChannelsRequest) returns (GetTopChannelsResponse); rpc GetTopChannels(GetTopChannelsRequest) returns (GetTopChannelsResponse);
// Gets all servers that exist in the process. // Gets all servers that exist in the process.
@ -382,6 +434,22 @@ service Channelz {
rpc GetSocket(GetSocketRequest) returns (GetSocketResponse); 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 { message GetServersRequest {
// start_server_id indicates that only servers at or above this id should be // start_server_id indicates that only servers at or above this id should be
// included in the results. // included in the results.
@ -415,42 +483,35 @@ message GetServerSocketsResponse {
bool end = 2; 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 { message GetChannelRequest {
// channel_id is the identifier of the specific channel to get.
int64 channel_id = 1; int64 channel_id = 1;
} }
message GetChannelResponse { message GetChannelResponse {
// The Channel that corresponds to the requested channel_id. This field
// should be set.
Channel channel = 1; Channel channel = 1;
} }
message GetSubchannelRequest { message GetSubchannelRequest {
// subchannel_id is the identifier of the specific subchannel to get.
int64 subchannel_id = 1; int64 subchannel_id = 1;
} }
message GetSubchannelResponse { message GetSubchannelResponse {
// The Subchannel that corresponds to the requested subchannel_id. This
// field should be set.
Subchannel subchannel = 1; Subchannel subchannel = 1;
} }
message GetSocketRequest { message GetSocketRequest {
// socket_id is the identifier of the specific socket to get.
int64 socket_id = 1; int64 socket_id = 1;
} }
message GetSocketResponse { message GetSocketResponse {
// The Socket that corresponds to the requested socket_id. This field
// should be set.
Socket socket = 1; Socket socket = 1;
} }

@ -64,6 +64,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/channel/channel_stack.cc', 'src/core/lib/channel/channel_stack.cc',
'src/core/lib/channel/channel_stack_builder.cc', 'src/core/lib/channel/channel_stack_builder.cc',
'src/core/lib/channel/channel_trace.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/channelz_registry.cc',
'src/core/lib/channel/connected_channel.cc', 'src/core/lib/channel/connected_channel.cc',
'src/core/lib/channel/handshaker.cc', 'src/core/lib/channel/handshaker.cc',

@ -0,0 +1,3 @@
include grpc_version.py
recursive-include grpc_testing *.py
global-exclude *.pyc

@ -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`.

@ -58,10 +58,6 @@ def main
run_multiple_killed_watches(10, 0.1) run_multiple_killed_watches(10, 0.1)
STDERR.puts '1000 iterations, sleep 0.001 before killing thread' STDERR.puts '1000 iterations, sleep 0.001 before killing thread'
run_multiple_killed_watches(1000, 0.001) 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)
end end
main main

@ -68,8 +68,6 @@ grpc_channel_get_info_type grpc_channel_get_info_import;
grpc_insecure_channel_create_type grpc_insecure_channel_create_import; grpc_insecure_channel_create_type grpc_insecure_channel_create_import;
grpc_lame_client_channel_create_type grpc_lame_client_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_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_type grpc_call_cancel_import;
grpc_call_cancel_with_status_type grpc_call_cancel_with_status_import; grpc_call_cancel_with_status_type grpc_call_cancel_with_status_import;
grpc_call_ref_type grpc_call_ref_import; grpc_call_ref_type grpc_call_ref_import;
@ -316,8 +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_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_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_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_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_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"); grpc_call_ref_import = (grpc_call_ref_type) GetProcAddress(library, "grpc_call_ref");

@ -179,12 +179,6 @@ extern grpc_lame_client_channel_create_type grpc_lame_client_channel_create_impo
typedef void(*grpc_channel_destroy_type)(grpc_channel* channel); typedef void(*grpc_channel_destroy_type)(grpc_channel* channel);
extern grpc_channel_destroy_type grpc_channel_destroy_import; extern grpc_channel_destroy_type grpc_channel_destroy_import;
#define grpc_channel_destroy 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
typedef grpc_call_error(*grpc_call_cancel_type)(grpc_call* call, void* reserved); typedef grpc_call_error(*grpc_call_cancel_type)(grpc_call* call, void* reserved);
extern grpc_call_cancel_type grpc_call_cancel_import; extern grpc_call_cancel_type grpc_call_cancel_import;
#define grpc_call_cancel grpc_call_cancel_import #define grpc_call_cancel grpc_call_cancel_import

@ -120,7 +120,7 @@ module GRPC
@send_initial_md_mutex.synchronize do @send_initial_md_mutex.synchronize do
return if @metadata_sent return if @metadata_sent
@metadata_to_send.merge!(new_metadata) @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 @metadata_sent = true
end end
end end

@ -87,6 +87,7 @@
# Options # Options
option(gRPC_BUILD_TESTS "Build tests" OFF) option(gRPC_BUILD_TESTS "Build tests" OFF)
option(gRPC_BUILD_CODEGEN "Build codegen" ON) option(gRPC_BUILD_CODEGEN "Build codegen" ON)
option(gRPC_BUILD_CSHARP_EXT "Build C# extensions" ON)
set(gRPC_INSTALL_default ON) set(gRPC_INSTALL_default ON)
if (NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) if (NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
@ -298,6 +299,11 @@
if (gRPC_BUILD_TESTS) if (gRPC_BUILD_TESTS)
${cc_library(lib)} ${cc_library(lib)}
endif (gRPC_BUILD_TESTS) 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: % else:
${cc_library(lib)} ${cc_library(lib)}
% if not lib.build in ["tool"]: % if not lib.build in ["tool"]:

@ -11,11 +11,12 @@
PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/src/php/ext/grpc) 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/boringssl/include)
PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/address_sorting/include) PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/address_sorting/include)
PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/nanopb)
LIBS="-lpthread $LIBS" LIBS="-lpthread $LIBS"
CFLAGS="-Wall -Werror -Wno-parentheses-equality -Wno-unused-value -std=c11 -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_16BIT=1" CXXFLAGS="-std=c++11 -fno-exceptions -fno-rtti -g -O2 -D PB_FIELD_32BIT=1"
GRPC_SHARED_LIBADD="-lpthread $GRPC_SHARED_LIBADD" GRPC_SHARED_LIBADD="-lpthread $GRPC_SHARED_LIBADD"
PHP_REQUIRE_CXX() PHP_REQUIRE_CXX()
PHP_ADD_LIBRARY(pthread) PHP_ADD_LIBRARY(pthread)

@ -23,13 +23,14 @@
EXTENSION("grpc", grpc_source, null, EXTENSION("grpc", grpc_source, null,
"/DOPENSSL_NO_ASM /D_GNU_SOURCE /DWIN32_LEAN_AND_MEAN "+ "/DOPENSSL_NO_ASM /D_GNU_SOURCE /DWIN32_LEAN_AND_MEAN "+
"/D_HAS_EXCEPTIONS=0 /DNOMINMAX /DGRPC_ARES=0 /D_WIN32_WINNT=0x600 "+ "/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+" "+
"/I"+configure_module_dirname+"\\include "+ "/I"+configure_module_dirname+"\\include "+
"/I"+configure_module_dirname+"\\src\\php\\ext\\grpc "+ "/I"+configure_module_dirname+"\\src\\php\\ext\\grpc "+
"/I"+configure_module_dirname+"\\third_party\\boringssl\\include "+ "/I"+configure_module_dirname+"\\third_party\\boringssl\\include "+
"/I"+configure_module_dirname+"\\third_party\\zlib "+ "/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 = {} dirs = {}
for lib in libs: for lib in libs:

@ -83,6 +83,23 @@ grpc_cc_test(
], ],
) )
grpc_cc_test(
name = "channelz_test",
srcs = ["channelz_test.cc"],
language = "C++",
deps = [
"//:gpr",
"//:grpc",
"//:grpc++",
"//test/core/util:gpr_test_util",
"//test/core/util:grpc_test_util",
"//test/cpp/util:channel_trace_proto_helper",
],
external_deps = [
"gtest",
],
)
grpc_cc_test( grpc_cc_test(
name = "channelz_registry_test", name = "channelz_registry_test",
srcs = ["channelz_registry_test.cc"], srcs = ["channelz_registry_test.cc"],

@ -25,6 +25,7 @@
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include "src/core/lib/channel/channel_trace.h" #include "src/core/lib/channel/channel_trace.h"
#include "src/core/lib/channel/channelz.h"
#include "src/core/lib/channel/channelz_registry.h" #include "src/core/lib/channel/channelz_registry.h"
#include "src/core/lib/gpr/useful.h" #include "src/core/lib/gpr/useful.h"
#include "src/core/lib/iomgr/exec_ctx.h" #include "src/core/lib/iomgr/exec_ctx.h"
@ -39,6 +40,7 @@
#include <string.h> #include <string.h>
namespace grpc_core { namespace grpc_core {
namespace channelz {
namespace testing { namespace testing {
namespace { namespace {
@ -69,7 +71,7 @@ void ValidateChannelTraceData(grpc_json* json,
ASSERT_NE(json, nullptr); ASSERT_NE(json, nullptr);
grpc_json* num_events_logged_json = GetJsonChild(json, "numEventsLogged"); grpc_json* num_events_logged_json = GetJsonChild(json, "numEventsLogged");
ASSERT_NE(num_events_logged_json, nullptr); 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); ASSERT_NE(start_time, nullptr);
size_t num_events_logged = size_t num_events_logged =
(size_t)strtol(num_events_logged_json->value, nullptr, 0); (size_t)strtol(num_events_logged_json->value, nullptr, 0);
@ -77,35 +79,47 @@ void ValidateChannelTraceData(grpc_json* json,
ValidateJsonArraySize(json, "events", actual_num_events_expected); ValidateJsonArraySize(json, "events", actual_num_events_expected);
} }
void AddSimpleTrace(const RefCountedPtr<ChannelTrace>& tracer) { void AddSimpleTrace(ChannelTrace* tracer) {
tracer->AddTraceEvent(ChannelTrace::Severity::Info, tracer->AddTraceEvent(ChannelTrace::Severity::Info,
grpc_slice_from_static_string("simple trace")); grpc_slice_from_static_string("simple trace"));
} }
// checks for the existence of all the required members of the tracer. // checks for the existence of all the required members of the tracer.
void ValidateChannelTrace(const RefCountedPtr<ChannelTrace>& tracer, void ValidateChannelTrace(ChannelTrace* tracer,
size_t expected_num_event_logged, size_t max_nodes) { size_t expected_num_event_logged, size_t max_nodes) {
if (!max_nodes) return; 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::testing::ValidateChannelTraceProtoJsonTranslation(json_str);
grpc_json* json = grpc_json_parse_string(json_str); grpc_json* parsed_json = grpc_json_parse_string(json_str);
ValidateChannelTraceData(json, expected_num_event_logged, ValidateChannelTraceData(parsed_json, expected_num_event_logged,
GPR_MIN(expected_num_event_logged, max_nodes)); GPR_MIN(expected_num_event_logged, max_nodes));
grpc_json_destroy(json); grpc_json_destroy(parsed_json);
gpr_free(json_str); gpr_free(json_str);
} }
void ValidateTraceDataMatchedUuidLookup( class ChannelFixture {
const RefCountedPtr<ChannelTrace>& tracer) { public:
intptr_t uuid = tracer->GetUuid(); ChannelFixture(int max_trace_nodes) {
if (uuid == -1) return; // Doesn't make sense to lookup if tracing disabled grpc_arg client_a;
char* tracer_json_str = tracer->RenderTrace(); client_a.type = GRPC_ARG_INTEGER;
ChannelTrace* uuid_lookup = ChannelzRegistry::Get<ChannelTrace>(uuid); client_a.key =
char* uuid_lookup_json_str = uuid_lookup->RenderTrace(); const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE);
EXPECT_EQ(strcmp(tracer_json_str, uuid_lookup_json_str), 0); client_a.value.integer = max_trace_nodes;
gpr_free(tracer_json_str); grpc_channel_args client_args = {1, &client_a};
gpr_free(uuid_lookup_json_str); 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 } // anonymous namespace
@ -115,25 +129,22 @@ class ChannelTracerTest : public ::testing::TestWithParam<size_t> {};
// lookups by uuid. // lookups by uuid.
TEST_P(ChannelTracerTest, BasicTest) { TEST_P(ChannelTracerTest, BasicTest) {
grpc_core::ExecCtx exec_ctx; grpc_core::ExecCtx exec_ctx;
RefCountedPtr<ChannelTrace> tracer = MakeRefCounted<ChannelTrace>(GetParam()); ChannelTrace tracer(GetParam());
AddSimpleTrace(tracer); AddSimpleTrace(&tracer);
AddSimpleTrace(tracer); AddSimpleTrace(&tracer);
ValidateTraceDataMatchedUuidLookup(tracer); tracer.AddTraceEvent(ChannelTrace::Severity::Info,
tracer->AddTraceEvent(ChannelTrace::Severity::Info, grpc_slice_from_static_string("trace three"));
grpc_slice_from_static_string("trace three")); tracer.AddTraceEvent(ChannelTrace::Severity::Error,
tracer->AddTraceEvent(ChannelTrace::Severity::Error, grpc_slice_from_static_string("trace four error"));
grpc_slice_from_static_string("trace four error")); ValidateChannelTrace(&tracer, 4, GetParam());
ValidateChannelTrace(tracer, 4, GetParam()); AddSimpleTrace(&tracer);
AddSimpleTrace(tracer); AddSimpleTrace(&tracer);
AddSimpleTrace(tracer); ValidateChannelTrace(&tracer, 6, GetParam());
ValidateChannelTrace(tracer, 6, GetParam()); AddSimpleTrace(&tracer);
AddSimpleTrace(tracer); AddSimpleTrace(&tracer);
AddSimpleTrace(tracer); AddSimpleTrace(&tracer);
AddSimpleTrace(tracer); AddSimpleTrace(&tracer);
AddSimpleTrace(tracer); ValidateChannelTrace(&tracer, 10, GetParam());
ValidateChannelTrace(tracer, 10, GetParam());
ValidateTraceDataMatchedUuidLookup(tracer);
tracer.reset(nullptr);
} }
// Tests more complex functionality, like a parent channel tracking // Tests more complex functionality, like a parent channel tracking
@ -141,42 +152,43 @@ TEST_P(ChannelTracerTest, BasicTest) {
// and this function will both hold refs to the subchannel. // and this function will both hold refs to the subchannel.
TEST_P(ChannelTracerTest, ComplexTest) { TEST_P(ChannelTracerTest, ComplexTest) {
grpc_core::ExecCtx exec_ctx; grpc_core::ExecCtx exec_ctx;
RefCountedPtr<ChannelTrace> tracer = MakeRefCounted<ChannelTrace>(GetParam()); ChannelTrace tracer(GetParam());
AddSimpleTrace(tracer); AddSimpleTrace(&tracer);
AddSimpleTrace(tracer); AddSimpleTrace(&tracer);
RefCountedPtr<ChannelTrace> sc1 = MakeRefCounted<ChannelTrace>(GetParam()); ChannelFixture channel1(GetParam());
tracer->AddTraceEventReferencingSubchannel( RefCountedPtr<ChannelNode> sc1 =
MakeRefCounted<ChannelNode>(channel1.channel(), GetParam());
tracer.AddTraceEventReferencingSubchannel(
ChannelTrace::Severity::Info, ChannelTrace::Severity::Info,
grpc_slice_from_static_string("subchannel one created"), sc1); grpc_slice_from_static_string("subchannel one created"), sc1);
ValidateChannelTrace(tracer, 3, GetParam()); ValidateChannelTrace(&tracer, 3, GetParam());
AddSimpleTrace(sc1); AddSimpleTrace(sc1->trace());
AddSimpleTrace(sc1); AddSimpleTrace(sc1->trace());
AddSimpleTrace(sc1); AddSimpleTrace(sc1->trace());
ValidateChannelTrace(sc1, 3, GetParam()); ValidateChannelTrace(sc1->trace(), 3, GetParam());
AddSimpleTrace(sc1); AddSimpleTrace(sc1->trace());
AddSimpleTrace(sc1); AddSimpleTrace(sc1->trace());
AddSimpleTrace(sc1); AddSimpleTrace(sc1->trace());
ValidateChannelTrace(sc1, 6, GetParam()); ValidateChannelTrace(sc1->trace(), 6, GetParam());
AddSimpleTrace(tracer); AddSimpleTrace(&tracer);
AddSimpleTrace(tracer); AddSimpleTrace(&tracer);
ValidateChannelTrace(tracer, 5, GetParam()); ValidateChannelTrace(&tracer, 5, GetParam());
ValidateTraceDataMatchedUuidLookup(tracer); ChannelFixture channel2(GetParam());
RefCountedPtr<ChannelTrace> sc2 = MakeRefCounted<ChannelTrace>(GetParam()); RefCountedPtr<ChannelNode> sc2 =
tracer->AddTraceEventReferencingChannel( MakeRefCounted<ChannelNode>(channel2.channel(), GetParam());
tracer.AddTraceEventReferencingChannel(
ChannelTrace::Severity::Info, ChannelTrace::Severity::Info,
grpc_slice_from_static_string("LB channel two created"), sc2); grpc_slice_from_static_string("LB channel two created"), sc2);
tracer->AddTraceEventReferencingSubchannel( tracer.AddTraceEventReferencingSubchannel(
ChannelTrace::Severity::Warning, ChannelTrace::Severity::Warning,
grpc_slice_from_static_string("subchannel one inactive"), sc1); grpc_slice_from_static_string("subchannel one inactive"), sc1);
ValidateChannelTrace(tracer, 7, GetParam()); ValidateChannelTrace(&tracer, 7, GetParam());
AddSimpleTrace(tracer); AddSimpleTrace(&tracer);
AddSimpleTrace(tracer); AddSimpleTrace(&tracer);
AddSimpleTrace(tracer); AddSimpleTrace(&tracer);
AddSimpleTrace(tracer); AddSimpleTrace(&tracer);
AddSimpleTrace(tracer); AddSimpleTrace(&tracer);
AddSimpleTrace(tracer); AddSimpleTrace(&tracer);
ValidateTraceDataMatchedUuidLookup(tracer);
tracer.reset(nullptr);
sc1.reset(nullptr); sc1.reset(nullptr);
sc2.reset(nullptr); sc2.reset(nullptr);
} }
@ -186,39 +198,44 @@ TEST_P(ChannelTracerTest, ComplexTest) {
// gets deleted. // gets deleted.
TEST_P(ChannelTracerTest, TestNesting) { TEST_P(ChannelTracerTest, TestNesting) {
grpc_core::ExecCtx exec_ctx; grpc_core::ExecCtx exec_ctx;
RefCountedPtr<ChannelTrace> tracer = MakeRefCounted<ChannelTrace>(GetParam()); ChannelTrace tracer(GetParam());
AddSimpleTrace(tracer); AddSimpleTrace(&tracer);
AddSimpleTrace(tracer); AddSimpleTrace(&tracer);
ValidateChannelTrace(tracer, 2, GetParam()); ValidateChannelTrace(&tracer, 2, GetParam());
RefCountedPtr<ChannelTrace> sc1 = MakeRefCounted<ChannelTrace>(GetParam()); ChannelFixture channel1(GetParam());
tracer->AddTraceEventReferencingChannel( RefCountedPtr<ChannelNode> sc1 =
MakeRefCounted<ChannelNode>(channel1.channel(), GetParam());
tracer.AddTraceEventReferencingChannel(
ChannelTrace::Severity::Info, ChannelTrace::Severity::Info,
grpc_slice_from_static_string("subchannel one created"), sc1); grpc_slice_from_static_string("subchannel one created"), sc1);
ValidateChannelTrace(tracer, 3, GetParam()); ValidateChannelTrace(&tracer, 3, GetParam());
AddSimpleTrace(sc1); AddSimpleTrace(sc1->trace());
RefCountedPtr<ChannelTrace> conn1 = MakeRefCounted<ChannelTrace>(GetParam()); ChannelFixture channel2(GetParam());
RefCountedPtr<ChannelNode> conn1 =
MakeRefCounted<ChannelNode>(channel2.channel(), GetParam());
// nesting one level deeper. // nesting one level deeper.
sc1->AddTraceEventReferencingSubchannel( sc1->trace()->AddTraceEventReferencingSubchannel(
ChannelTrace::Severity::Info, ChannelTrace::Severity::Info,
grpc_slice_from_static_string("connection one created"), conn1); grpc_slice_from_static_string("connection one created"), conn1);
ValidateChannelTrace(tracer, 3, GetParam()); ValidateChannelTrace(&tracer, 3, GetParam());
AddSimpleTrace(conn1); AddSimpleTrace(conn1->trace());
AddSimpleTrace(tracer); AddSimpleTrace(&tracer);
AddSimpleTrace(tracer); AddSimpleTrace(&tracer);
ValidateChannelTrace(tracer, 5, GetParam()); ValidateChannelTrace(&tracer, 5, GetParam());
ValidateChannelTrace(conn1, 1, GetParam()); ValidateChannelTrace(conn1->trace(), 1, GetParam());
RefCountedPtr<ChannelTrace> sc2 = MakeRefCounted<ChannelTrace>(GetParam()); ChannelFixture channel3(GetParam());
tracer->AddTraceEventReferencingSubchannel( RefCountedPtr<ChannelNode> sc2 =
MakeRefCounted<ChannelNode>(channel3.channel(), GetParam());
tracer.AddTraceEventReferencingSubchannel(
ChannelTrace::Severity::Info, ChannelTrace::Severity::Info,
grpc_slice_from_static_string("subchannel two created"), sc2); grpc_slice_from_static_string("subchannel two created"), sc2);
// this trace should not get added to the parents children since it is already // this trace should not get added to the parents children since it is already
// present in the tracer. // present in the tracer.
tracer->AddTraceEventReferencingChannel( tracer.AddTraceEventReferencingChannel(
ChannelTrace::Severity::Warning, ChannelTrace::Severity::Warning,
grpc_slice_from_static_string("subchannel one inactive"), sc1); grpc_slice_from_static_string("subchannel one inactive"), sc1);
AddSimpleTrace(tracer); AddSimpleTrace(&tracer);
ValidateChannelTrace(tracer, 8, GetParam()); ValidateChannelTrace(&tracer, 8, GetParam());
tracer.reset(nullptr);
sc1.reset(nullptr); sc1.reset(nullptr);
sc2.reset(nullptr); sc2.reset(nullptr);
conn1.reset(nullptr); conn1.reset(nullptr);
@ -228,6 +245,7 @@ INSTANTIATE_TEST_CASE_P(ChannelTracerTestSweep, ChannelTracerTest,
::testing::Values(0, 1, 2, 6, 10, 15)); ::testing::Values(0, 1, 2, 6, 10, 15));
} // namespace testing } // namespace testing
} // namespace channelz
} // namespace grpc_core } // namespace grpc_core
int main(int argc, char** argv) { int main(int argc, char** argv) {

@ -0,0 +1,216 @@
/*
*
* 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 <stdlib.h>
#include <string.h>
#include <gtest/gtest.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/lib/channel/channel_trace.h"
#include "src/core/lib/channel/channelz.h"
#include "src/core/lib/channel/channelz_registry.h"
#include "src/core/lib/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"
#include <grpc/support/string_util.h>
#include <stdlib.h>
#include <string.h>
namespace grpc_core {
namespace channelz {
namespace testing {
// testing peer to access channel internals
class ChannelNodePeer {
public:
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:
ChannelNode* channel_;
};
namespace {
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[2];
client_a[0].type = GRPC_ARG_INTEGER;
client_a[0].key =
const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENTS_PER_NODE);
client_a[0].value.integer = max_trace_nodes;
client_a[1].type = GRPC_ARG_INTEGER;
client_a[1].key = const_cast<char*>(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);
}
~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);
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);
ASSERT_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);
}
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(ChannelNode* channel) {
ChannelNodePeer peer(channel);
return peer.last_call_started_millis();
}
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<size_t> {};
TEST_P(ChannelzChannelTest, BasicChannel) {
grpc_core::ExecCtx exec_ctx;
ChannelFixture channel(GetParam());
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);
}
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);
ASSERT_EQ(channelz_channel, nullptr);
grpc_channel_destroy(channel);
}
TEST_P(ChannelzChannelTest, BasicChannelAPIFunctionality) {
grpc_core::ExecCtx exec_ctx;
ChannelFixture channel(GetParam());
ChannelNode* channelz_channel =
grpc_channel_get_channelz_node(channel.channel());
channelz_channel->RecordCallStarted();
channelz_channel->RecordCallFailed();
channelz_channel->RecordCallSucceeded();
ValidateChannel(channelz_channel, {1, 1, 1});
channelz_channel->RecordCallStarted();
channelz_channel->RecordCallFailed();
channelz_channel->RecordCallSucceeded();
channelz_channel->RecordCallStarted();
channelz_channel->RecordCallFailed();
channelz_channel->RecordCallSucceeded();
ValidateChannel(channelz_channel, {3, 3, 3});
}
TEST_P(ChannelzChannelTest, LastCallStartedMillis) {
grpc_core::ExecCtx exec_ctx;
ChannelFixture channel(GetParam());
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);
// 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);
channelz_channel->RecordCallStarted();
grpc_millis millis4 = GetLastCallStartedMillis(channelz_channel);
EXPECT_NE(millis1, millis4);
}
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) {
grpc_test_init(argc, argv);
grpc_init();
::testing::InitGoogleTest(&argc, argv);
int ret = RUN_ALL_TESTS();
grpc_shutdown();
return ret;
}

@ -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_in_a_vacuum_pre_init(void);
extern void cancel_with_status(grpc_end2end_test_config config); extern void cancel_with_status(grpc_end2end_test_config config);
extern void cancel_with_status_pre_init(void); 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(grpc_end2end_test_config config);
extern void compressed_payload_pre_init(void); extern void compressed_payload_pre_init(void);
extern void connectivity(grpc_end2end_test_config config); extern void connectivity(grpc_end2end_test_config config);
@ -201,6 +203,7 @@ void grpc_end2end_tests_pre_init(void) {
cancel_before_invoke_pre_init(); cancel_before_invoke_pre_init();
cancel_in_a_vacuum_pre_init(); cancel_in_a_vacuum_pre_init();
cancel_with_status_pre_init(); cancel_with_status_pre_init();
channelz_pre_init();
compressed_payload_pre_init(); compressed_payload_pre_init();
connectivity_pre_init(); connectivity_pre_init();
default_host_pre_init(); default_host_pre_init();
@ -287,6 +290,7 @@ void grpc_end2end_tests(int argc, char **argv,
cancel_before_invoke(config); cancel_before_invoke(config);
cancel_in_a_vacuum(config); cancel_in_a_vacuum(config);
cancel_with_status(config); cancel_with_status(config);
channelz(config);
compressed_payload(config); compressed_payload(config);
connectivity(config); connectivity(config);
default_host(config); default_host(config);
@ -404,6 +408,10 @@ void grpc_end2end_tests(int argc, char **argv,
cancel_with_status(config); cancel_with_status(config);
continue; continue;
} }
if (0 == strcmp("channelz", argv[i])) {
channelz(config);
continue;
}
if (0 == strcmp("compressed_payload", argv[i])) { if (0 == strcmp("compressed_payload", argv[i])) {
compressed_payload(config); compressed_payload(config);
continue; continue;

@ -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_in_a_vacuum_pre_init(void);
extern void cancel_with_status(grpc_end2end_test_config config); extern void cancel_with_status(grpc_end2end_test_config config);
extern void cancel_with_status_pre_init(void); 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(grpc_end2end_test_config config);
extern void compressed_payload_pre_init(void); extern void compressed_payload_pre_init(void);
extern void connectivity(grpc_end2end_test_config config); extern void connectivity(grpc_end2end_test_config config);
@ -204,6 +206,7 @@ void grpc_end2end_tests_pre_init(void) {
cancel_before_invoke_pre_init(); cancel_before_invoke_pre_init();
cancel_in_a_vacuum_pre_init(); cancel_in_a_vacuum_pre_init();
cancel_with_status_pre_init(); cancel_with_status_pre_init();
channelz_pre_init();
compressed_payload_pre_init(); compressed_payload_pre_init();
connectivity_pre_init(); connectivity_pre_init();
default_host_pre_init(); default_host_pre_init();
@ -291,6 +294,7 @@ void grpc_end2end_tests(int argc, char **argv,
cancel_before_invoke(config); cancel_before_invoke(config);
cancel_in_a_vacuum(config); cancel_in_a_vacuum(config);
cancel_with_status(config); cancel_with_status(config);
channelz(config);
compressed_payload(config); compressed_payload(config);
connectivity(config); connectivity(config);
default_host(config); default_host(config);
@ -412,6 +416,10 @@ void grpc_end2end_tests(int argc, char **argv,
cancel_with_status(config); cancel_with_status(config);
continue; continue;
} }
if (0 == strcmp("channelz", argv[i])) {
channelz(config);
continue;
}
if (0 == strcmp("compressed_payload", argv[i])) { if (0 == strcmp("compressed_payload", argv[i])) {
compressed_payload(config); compressed_payload(config);
continue; continue;

@ -1046,6 +1046,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
op->reserved = nullptr; op->reserved = nullptr;
op->flags = grpc_fuzzer_get_next_uint32(&inp); op->flags = grpc_fuzzer_get_next_uint32(&inp);
} }
if (g_channel == nullptr) ok = false;
if (ok) { if (ok) {
validator* v = make_finished_batch_validator(g_active_call, has_ops); validator* v = make_finished_batch_validator(g_active_call, has_ops);
g_active_call->pending_ops++; g_active_call->pending_ops++;

@ -106,6 +106,7 @@ END2END_TESTS = {
needs_compression=True), needs_compression=True),
'connectivity': connectivity_test_options._replace(needs_names=True, 'connectivity': connectivity_test_options._replace(needs_names=True,
proxyable=False, cpu_cost=LOWCPU, exclude_iomgrs=['uv']), proxyable=False, cpu_cost=LOWCPU, exclude_iomgrs=['uv']),
'channelz': default_test_options,
'default_host': default_test_options._replace( 'default_host': default_test_options._replace(
needs_fullstack=True, needs_dns=True, needs_names=True), needs_fullstack=True, needs_dns=True, needs_names=True),
'call_host_override': default_test_options._replace( 'call_host_override': default_test_options._replace(

@ -113,6 +113,7 @@ END2END_TESTS = {
'compressed_payload': test_options(proxyable=False, exclude_inproc=True), 'compressed_payload': test_options(proxyable=False, exclude_inproc=True),
'connectivity': test_options(needs_fullstack=True, needs_names=True, 'connectivity': test_options(needs_fullstack=True, needs_names=True,
proxyable=False), proxyable=False),
'channelz': test_options(),
'default_host': test_options(needs_fullstack=True, needs_dns=True, 'default_host': test_options(needs_fullstack=True, needs_dns=True,
needs_names=True), needs_names=True),
'disappearing_server': test_options(needs_fullstack=True,needs_names=True), 'disappearing_server': test_options(needs_fullstack=True,needs_names=True),

@ -0,0 +1,299 @@
/*
*
* 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 <stdio.h>
#include <string.h>
#include "src/core/lib/surface/channel.h"
#include <grpc/byte_buffer.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/time.h>
#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<size_t>(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<size_t>(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;
grpc_arg client_a;
client_a.type = GRPC_ARG_INTEGER;
client_a.key = const_cast<char*>(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);
GPR_ASSERT(channelz_channel != nullptr);
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\""));
gpr_free(json);
// one successful request
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\""));
gpr_free(json);
// one failed request
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);
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[2];
client_a[0].type = GRPC_ARG_INTEGER;
client_a[0].key =
const_cast<char*>(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<char*>(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);
grpc_core::channelz::ChannelNode* channelz_channel =
grpc_channel_get_channelz_node(f.client);
GPR_ASSERT(channelz_channel != nullptr);
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\""));
GPR_ASSERT(nullptr != strstr(json, "\"severity\":\"CT_INFO\""));
gpr_free(json);
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);
GPR_ASSERT(channelz_channel == nullptr);
// one successful request
run_one_request(config, f, true);
GPR_ASSERT(channelz_channel == nullptr);
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);
}
void channelz_pre_init(void) {}

@ -106,8 +106,6 @@ int main(int argc, char **argv) {
printf("%lx", (unsigned long) grpc_insecure_channel_create); printf("%lx", (unsigned long) grpc_insecure_channel_create);
printf("%lx", (unsigned long) grpc_lame_client_channel_create); printf("%lx", (unsigned long) grpc_lame_client_channel_create);
printf("%lx", (unsigned long) grpc_channel_destroy); 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);
printf("%lx", (unsigned long) grpc_call_cancel_with_status); printf("%lx", (unsigned long) grpc_call_cancel_with_status);
printf("%lx", (unsigned long) grpc_call_ref); printf("%lx", (unsigned long) grpc_call_ref);

@ -30,26 +30,47 @@
namespace grpc { namespace grpc {
namespace testing { namespace testing {
void ValidateChannelTraceProtoJsonTranslation(char* tracer_json_c_str) { namespace {
std::string tracer_json_str(tracer_json_c_str);
grpc::channelz::ChannelTrace channel_trace; // 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 <typename Message>
void VaidateProtoJsonTranslation(char* json_c_str) {
std::string json_str(json_c_str);
Message msg;
google::protobuf::util::JsonParseOptions parse_options; google::protobuf::util::JsonParseOptions parse_options;
// If the following line is failing, then uncomment the last line of the // 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 // comment, and uncomment the lines that print the two strings. You can
// then compare the output, and determine what fields are missing. // 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( EXPECT_EQ(google::protobuf::util::JsonStringToMessage(json_str, &msg,
tracer_json_str, &channel_trace, parse_options), parse_options),
google::protobuf::util::Status::OK); google::protobuf::util::Status::OK);
std::string proto_json_str; std::string proto_json_str;
ASSERT_EQ(google::protobuf::util::MessageToJsonString(channel_trace, google::protobuf::util::JsonPrintOptions print_options;
&proto_json_str), // 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); google::protobuf::util::Status::OK);
// uncomment these to compare the the json strings. // 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()); // gpr_log(GPR_ERROR, "proto json: %s", proto_json_str.c_str());
ASSERT_EQ(tracer_json_str, proto_json_str); EXPECT_EQ(json_str, proto_json_str);
}
} // namespace
void ValidateChannelTraceProtoJsonTranslation(char* tracer_json_c_str) {
VaidateProtoJsonTranslation<grpc::channelz::v1::ChannelTrace>(
tracer_json_c_str);
}
void ValidateChannelProtoJsonTranslation(char* channel_json_c_str) {
VaidateProtoJsonTranslation<grpc::channelz::v1::Channel>(channel_json_c_str);
} }
} // namespace testing } // namespace testing

@ -23,6 +23,7 @@ namespace grpc {
namespace testing { namespace testing {
void ValidateChannelTraceProtoJsonTranslation(char* tracer_json_c_str); void ValidateChannelTraceProtoJsonTranslation(char* tracer_json_c_str);
void ValidateChannelProtoJsonTranslation(char* channel_json_c_str);
} // namespace testing } // namespace testing
} // namespace grpc } // namespace grpc

@ -28,10 +28,12 @@ else
echo "Testing Python source distribution" echo "Testing Python source distribution"
ARCHIVES=("$EXTERNAL_GIT_ROOT"/input_artifacts/grpcio-[0-9]*.tar.gz) ARCHIVES=("$EXTERNAL_GIT_ROOT"/input_artifacts/grpcio-[0-9]*.tar.gz)
TOOLS_ARCHIVES=("$EXTERNAL_GIT_ROOT"/input_artifacts/grpcio-tools-[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 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) VIRTUAL_ENV=$(mktemp -d)
virtualenv "$VIRTUAL_ENV" virtualenv "$VIRTUAL_ENV"
PYTHON=$VIRTUAL_ENV/bin/python PYTHON=$VIRTUAL_ENV/bin/python
@ -53,13 +55,9 @@ function at_least_one_installs() {
at_least_one_installs "${ARCHIVES[@]}" at_least_one_installs "${ARCHIVES[@]}"
at_least_one_installs "${TOOLS_ARCHIVES[@]}" at_least_one_installs "${TOOLS_ARCHIVES[@]}"
at_least_one_installs "${HEALTH_ARCHIVES[@]}"
if [[ "$1" == "source" ]] at_least_one_installs "${REFLECTION_ARCHIVES[@]}"
then at_least_one_installs "${TESTING_ARCHIVES[@]}"
echo "Testing Python health and reflection packages"
at_least_one_installs "${HEALTH_ARCHIVES[@]}"
at_least_one_installs "${REFLECTION_ARCHIVES[@]}"
fi
# #

@ -1012,6 +1012,7 @@ src/core/lib/channel/channel_args.h \
src/core/lib/channel/channel_stack.h \ src/core/lib/channel/channel_stack.h \
src/core/lib/channel/channel_stack_builder.h \ src/core/lib/channel/channel_stack_builder.h \
src/core/lib/channel/channel_trace.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/channelz_registry.h \
src/core/lib/channel/connected_channel.h \ src/core/lib/channel/connected_channel.h \
src/core/lib/channel/context.h \ src/core/lib/channel/context.h \

@ -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_stack_builder.h \
src/core/lib/channel/channel_trace.cc \ src/core/lib/channel/channel_trace.cc \
src/core/lib/channel/channel_trace.h \ 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.cc \
src/core/lib/channel/channelz_registry.h \ src/core/lib/channel/channelz_registry.h \
src/core/lib/channel/connected_channel.cc \ src/core/lib/channel/connected_channel.cc \

@ -99,12 +99,16 @@ then
"${PIP}" install grpcio --no-index --find-links "file://$ARTIFACT_DIR/" "${PIP}" install grpcio --no-index --find-links "file://$ARTIFACT_DIR/"
"${PIP}" install grpcio-tools --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 \ ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_health_checking/setup.py \
preprocess build_package_protos sdist preprocess build_package_protos sdist
cp -r src/python/grpcio_health_checking/dist/* "$ARTIFACT_DIR" 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 \ ${SETARCH_CMD} "${PYTHON}" src/python/grpcio_reflection/setup.py \
preprocess build_package_protos sdist preprocess build_package_protos sdist
cp -r src/python/grpcio_reflection/dist/* "$ARTIFACT_DIR" cp -r src/python/grpcio_reflection/dist/* "$ARTIFACT_DIR"

@ -3137,6 +3137,27 @@
"third_party": false, "third_party": false,
"type": "target" "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": [ "deps": [
"gpr", "gpr",
@ -8777,6 +8798,7 @@
"test/core/end2end/tests/cancel_in_a_vacuum.cc", "test/core/end2end/tests/cancel_in_a_vacuum.cc",
"test/core/end2end/tests/cancel_test_helpers.h", "test/core/end2end/tests/cancel_test_helpers.h",
"test/core/end2end/tests/cancel_with_status.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/compressed_payload.cc",
"test/core/end2end/tests/connectivity.cc", "test/core/end2end/tests/connectivity.cc",
"test/core/end2end/tests/default_host.cc", "test/core/end2end/tests/default_host.cc",
@ -8877,6 +8899,7 @@
"test/core/end2end/tests/cancel_in_a_vacuum.cc", "test/core/end2end/tests/cancel_in_a_vacuum.cc",
"test/core/end2end/tests/cancel_test_helpers.h", "test/core/end2end/tests/cancel_test_helpers.h",
"test/core/end2end/tests/cancel_with_status.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/compressed_payload.cc",
"test/core/end2end/tests/connectivity.cc", "test/core/end2end/tests/connectivity.cc",
"test/core/end2end/tests/default_host.cc", "test/core/end2end/tests/default_host.cc",
@ -9349,6 +9372,7 @@
"src/core/lib/channel/channel_stack.cc", "src/core/lib/channel/channel_stack.cc",
"src/core/lib/channel/channel_stack_builder.cc", "src/core/lib/channel/channel_stack_builder.cc",
"src/core/lib/channel/channel_trace.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/channelz_registry.cc",
"src/core/lib/channel/connected_channel.cc", "src/core/lib/channel/connected_channel.cc",
"src/core/lib/channel/handshaker.cc", "src/core/lib/channel/handshaker.cc",
@ -9520,6 +9544,7 @@
"src/core/lib/channel/channel_stack.h", "src/core/lib/channel/channel_stack.h",
"src/core/lib/channel/channel_stack_builder.h", "src/core/lib/channel/channel_stack_builder.h",
"src/core/lib/channel/channel_trace.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/channelz_registry.h",
"src/core/lib/channel/connected_channel.h", "src/core/lib/channel/connected_channel.h",
"src/core/lib/channel/context.h", "src/core/lib/channel/context.h",
@ -9669,6 +9694,7 @@
"src/core/lib/channel/channel_stack.h", "src/core/lib/channel/channel_stack.h",
"src/core/lib/channel/channel_stack_builder.h", "src/core/lib/channel/channel_stack_builder.h",
"src/core/lib/channel/channel_trace.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/channelz_registry.h",
"src/core/lib/channel/connected_channel.h", "src/core/lib/channel/connected_channel.h",
"src/core/lib/channel/context.h", "src/core/lib/channel/context.h",

File diff suppressed because it is too large Load Diff

@ -19,15 +19,15 @@ set -ex
cd "$(dirname "$0")/../../.." cd "$(dirname "$0")/../../.."
EXIT_CODE=0 EXIT_CODE=0
ruby src/ruby/end2end/sig_handling_driver.rb || EXIT_CODE=1 time ruby src/ruby/end2end/sig_handling_driver.rb || EXIT_CODE=1
ruby src/ruby/end2end/channel_state_driver.rb || EXIT_CODE=1 time ruby src/ruby/end2end/channel_state_driver.rb || EXIT_CODE=1
ruby src/ruby/end2end/channel_closing_driver.rb || EXIT_CODE=1 time 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 time 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 time ruby src/ruby/end2end/killed_client_thread_driver.rb || EXIT_CODE=1
ruby src/ruby/end2end/forking_client_driver.rb || EXIT_CODE=1 time ruby src/ruby/end2end/forking_client_driver.rb || EXIT_CODE=1
ruby src/ruby/end2end/grpc_class_init_driver.rb || EXIT_CODE=1 time 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 time 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 time 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/client_memory_usage_driver.rb || EXIT_CODE=1
ruby src/ruby/end2end/package_with_underscore_checker.rb || EXIT_CODE=1 time ruby src/ruby/end2end/package_with_underscore_checker.rb || EXIT_CODE=1
exit $EXIT_CODE exit $EXIT_CODE

@ -96,7 +96,7 @@ _WHITELIST_DICT = {
'gRPC\-Core\.podspec$': [_OBJC_TEST_SUITE], 'gRPC\-Core\.podspec$': [_OBJC_TEST_SUITE],
'gRPC\-ProtoRPC\.podspec$': [_OBJC_TEST_SUITE], 'gRPC\-ProtoRPC\.podspec$': [_OBJC_TEST_SUITE],
'gRPC\-RxLibrary\.podspec$': [_OBJC_TEST_SUITE], 'gRPC\-RxLibrary\.podspec$': [_OBJC_TEST_SUITE],
'INSTALL\.md$': [], 'BUILDING\.md$': [],
'LICENSE$': [], 'LICENSE$': [],
'MANIFEST\.md$': [], 'MANIFEST\.md$': [],
'package\.json$': [_PHP_TEST_SUITE], 'package\.json$': [_PHP_TEST_SUITE],

@ -161,7 +161,7 @@ if __name__ == "__main__":
test_cases = action['testAction']['testSuite']['tests'][0][ test_cases = action['testAction']['testSuite']['tests'][0][
'testSuite']['tests'] 'testSuite']['tests']
for test_case in test_cases: 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' result = 'FAILED'
elif 'timedOut' in test_case['testCase']: elif 'timedOut' in test_case['testCase']:
result = 'TIMEOUT' result = 'TIMEOUT'

@ -883,7 +883,7 @@ class RubyLanguage(object):
tests.append( tests.append(
self.config.job_spec( self.config.job_spec(
['tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh'], ['tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh'],
timeout_seconds=10 * 60, timeout_seconds=20 * 60,
environ=_FORCE_ENVIRON_FOR_WRAPPERS)) environ=_FORCE_ENVIRON_FOR_WRAPPERS))
return tests return tests

@ -1,12 +0,0 @@
Debug
Debug-DLL
Release
Release-DLL
*.suo
*.user
test_bin
*.opensdf
*.sdf
third_party/*.user
/packages
/IntDir

@ -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.
Loading…
Cancel
Save