Merge remote-tracking branch 'upstream/master' into libuv_em_basic

pull/21216/head
Guantao Liu 5 years ago
commit 6b4b891eb2
  1. 2
      .github/ISSUE_TEMPLATE/bug_report.md
  2. 2
      .github/ISSUE_TEMPLATE/cleanup_request.md
  3. 2
      .github/ISSUE_TEMPLATE/feature_request.md
  4. 2
      .github/pull_request_template.md
  5. 6
      BUILD
  6. 100
      BUILDING.md
  7. 6
      CMakeLists.txt
  8. 4
      Makefile
  9. 20
      bazel/grpc_deps.bzl
  10. 4
      build.yaml
  11. 3
      doc/g_stands_for.md
  12. 2
      gRPC-C++.podspec
  13. 2
      gRPC-Core.podspec
  14. 2
      gRPC-ProtoRPC.podspec
  15. 2
      gRPC-RxLibrary.podspec
  16. 2
      gRPC.podspec
  17. 8
      include/grpcpp/generic/generic_stub_impl.h
  18. 15
      include/grpcpp/impl/codegen/async_generic_service.h
  19. 45
      include/grpcpp/impl/codegen/client_callback.h
  20. 50
      include/grpcpp/impl/codegen/client_callback_impl.h
  21. 6
      include/grpcpp/impl/codegen/client_context_impl.h
  22. 4
      include/grpcpp/impl/codegen/completion_queue_impl.h
  23. 20
      include/grpcpp/impl/codegen/message_allocator.h
  24. 3
      include/grpcpp/impl/codegen/method_handler_impl.h
  25. 7
      include/grpcpp/impl/codegen/rpc_service_method.h
  26. 26
      include/grpcpp/impl/codegen/server_callback.h
  27. 132
      include/grpcpp/impl/codegen/server_callback_handlers.h
  28. 14
      include/grpcpp/impl/codegen/server_callback_impl.h
  29. 10
      include/grpcpp/impl/codegen/server_context.h
  30. 86
      include/grpcpp/impl/codegen/server_context_impl.h
  31. 12
      include/grpcpp/impl/codegen/server_interceptor.h
  32. 18
      include/grpcpp/impl/codegen/server_interface.h
  33. 24
      include/grpcpp/server_builder_impl.h
  34. 16
      include/grpcpp/server_impl.h
  35. 6
      package.xml
  36. 13
      src/compiler/cpp_generator.cc
  37. 8
      src/core/ext/filters/client_channel/http_proxy.cc
  38. 27
      src/core/ext/transport/chttp2/client/chttp2_connector.cc
  39. 10
      src/core/lib/gprpp/optional.h
  40. 24
      src/core/lib/gprpp/string_view.h
  41. 5
      src/core/lib/security/security_connector/ssl_utils.cc
  42. 2
      src/core/lib/surface/version.cc
  43. 26
      src/cpp/README.md
  44. 5
      src/cpp/client/client_context.cc
  45. 3
      src/cpp/client/generic_stub.cc
  46. 2
      src/cpp/common/version_cc.cc
  47. 21
      src/cpp/ext/filters/census/client_filter.cc
  48. 17
      src/cpp/ext/filters/census/context.cc
  49. 28
      src/cpp/ext/filters/census/context.h
  50. 15
      src/cpp/server/server_builder.cc
  51. 39
      src/cpp/server/server_cc.cc
  52. 2
      src/cpp/server/server_context.cc
  53. 4
      src/csharp/Grpc.Core.Api/VersionInfo.cs
  54. 10
      src/csharp/Grpc.Core/Internal/AsyncCall.cs
  55. 4
      src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
  56. 2
      src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
  57. 167
      src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs
  58. 54
      src/csharp/Grpc.HealthCheck.Tests/TestResponseStreamWriter.cs
  59. 57
      src/csharp/Grpc.HealthCheck.Tests/TestServerCallContext.cs
  60. 12
      src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
  61. 201
      src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs
  62. 12
      src/csharp/Grpc.HealthCheck/Properties/AssemblyInfo.cs
  63. 100
      src/csharp/Grpc.IntegrationTesting/UnobservedTaskExceptionTest.cs
  64. 9
      src/csharp/Grpc.sln
  65. 2
      src/csharp/build/dependencies.props
  66. 2
      src/csharp/build_unitypackage.bat
  67. 3
      src/csharp/tests.json
  68. 2
      src/objective-c/!ProtoCompiler-gRPCCppPlugin.podspec
  69. 2
      src/objective-c/!ProtoCompiler-gRPCPlugin.podspec
  70. 2
      src/objective-c/GRPCClient/version.h
  71. 2
      src/objective-c/tests/version.h
  72. 2
      src/php/composer.json
  73. 30
      src/php/ext/grpc/byte_buffer.c
  74. 4
      src/php/ext/grpc/byte_buffer.h
  75. 23
      src/php/ext/grpc/call.c
  76. 2
      src/php/ext/grpc/version.h
  77. 2
      src/python/grpcio/grpc/_grpcio_metadata.py
  78. 2
      src/python/grpcio/grpc_version.py
  79. 2
      src/python/grpcio_channelz/grpc_version.py
  80. 2
      src/python/grpcio_health_checking/grpc_version.py
  81. 2
      src/python/grpcio_reflection/grpc_version.py
  82. 2
      src/python/grpcio_status/grpc_version.py
  83. 2
      src/python/grpcio_testing/grpc_version.py
  84. 2
      src/python/grpcio_tests/grpc_version.py
  85. 2
      src/ruby/lib/grpc/version.rb
  86. 2
      src/ruby/tools/version.rb
  87. 18
      test/core/gprpp/string_view_test.cc
  88. 4
      test/core/security/credentials_test.cc
  89. 1
      test/core/tsi/alts/handshaker/alts_concurrent_connectivity_test.cc
  90. 14
      test/cpp/codegen/compiler_test_golden
  91. 27
      test/cpp/end2end/hybrid_end2end_test.cc
  92. 1
      test/cpp/end2end/time_change_test.cc
  93. 2
      test/cpp/ext/filters/census/BUILD
  94. 67
      test/cpp/ext/filters/census/stats_plugin_end2end_test.cc
  95. 2
      tools/distrib/python/grpcio_tools/grpc_version.py
  96. 2
      tools/doxygen/Doxyfile.c++
  97. 2
      tools/doxygen/Doxyfile.c++.internal
  98. 2
      tools/doxygen/Doxyfile.objc
  99. 2
      tools/doxygen/Doxyfile.objc.internal
  100. 94
      tools/internal_ci/helper_scripts/install_python38.ps1
  101. Some files were not shown because too many files have changed in this diff Show More

@ -2,7 +2,7 @@
name: Report a bug
about: Create a report to help us improve
labels: kind/bug, priority/P2
assignees: nicolasnoble
assignees: karthikravis
---

@ -2,7 +2,7 @@
name: Request a cleanup
about: Suggest a cleanup in our repository
labels: kind/internal cleanup, priority/P2
assignees: nicolasnoble
assignees: karthikravis
---

@ -2,7 +2,7 @@
name: Request a feature
about: Suggest an idea for this project
labels: kind/enhancement, priority/P2
assignees: nicolasnoble
assignees: karthikravis
---

@ -8,4 +8,4 @@ If you know who should review your pull request, please remove the mentioning be
-->
@nicolasnoble
@karthikravis

@ -77,11 +77,11 @@ config_setting(
python_config_settings()
# This should be updated along with build.yaml
g_stands_for = "gon"
g_stands_for = "guantao"
core_version = "9.0.0"
version = "1.26.0-dev"
version = "1.27.0-dev"
GPR_PUBLIC_HDRS = [
"include/grpc/support/alloc.h",
@ -2303,7 +2303,9 @@ grpc_cc_library(
"absl-base",
"absl-time",
"opencensus-trace",
"opencensus-trace-context_util",
"opencensus-stats",
"opencensus-context",
],
language = "c++",
deps = [

@ -1,6 +1,9 @@
gRPC C++ - Building from source
===========================
This document has detailed instructions on how to build gRPC C++ from source. Note that it only covers the build of gRPC itself and is mostly meant for gRPC C++ contributors and/or power users.
Other should follow the user instructions. See the [How to use](https://github.com/grpc/grpc/tree/master/src/cpp#to-start-using-grpc-c) instructions for guidance on how to add gRPC as a dependency to a C++ application (there are several ways and system wide installation is often not the best choice).
# Pre-requisites
## Linux
@ -14,7 +17,6 @@ If you plan to build from source and run tests, install the following as well:
$ [sudo] apt-get install libgflags-dev libgtest-dev
$ [sudo] apt-get install clang-5.0 libc++-dev
```
Lastly, see the Protoc section below if you do not yet have the protoc compiler installed.
## MacOS
@ -47,7 +49,6 @@ installed by `brew` is being used:
```sh
$ LIBTOOL=glibtool LIBTOOLIZE=glibtoolize make
```
Lastly, see the Protoc section below if you do not yet have the protoc compiler.
## Windows
@ -57,26 +58,9 @@ To prepare for cmake + Microsoft Visual C++ compiler build
- 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*
- Install [nasm](https://www.nasm.us/) and add it to `PATH` (`choco install nasm`) - *required by boringssl*
- (Optional) Install [Ninja](https://ninja-build.org/) (`choco install ninja`)
## Protoc
By default gRPC uses [protocol buffers](https://github.com/google/protobuf),
you will need the `protoc` compiler to generate stub server and client code.
If you compile gRPC from source, as described below, the Makefile will
automatically try compiling the `protoc` in third_party if you cloned the
repository recursively and it detects that you do not already have 'protoc' compiler
installed.
If 'protoc' compiler has not been installed, following commands can be used for installation.
```sh
$ cd grpc/third_party/protobuf
$ sudo make install # 'make' should have been run by core grpc
```
# Clone the repository (including submodules)
Before building, you need to clone the gRPC github repository and download submodules containing source code
@ -100,37 +84,52 @@ repository at the latest stable version.
> @rem To update submodules at later time, run "git submodule update --init"
```
NOTE: The `bazel` build tool uses a different model for dependencies. You only need to worry about downloading submodules if you're building
with something else than `bazel` (e.g. `cmake`).
# 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.
Therefore, gRPC supports several major build systems, which should satisfy most users. Depending on your needs
we recommend building using `bazel` or `cmake`.
Note that this section only covers the build of gRPC itself, not the installation. See the [How to use](https://github.com/grpc/grpc/tree/master/src/cpp#to-start-using-grpc-c) instructions
for guidance on how to add gRPC as a dependency to a C++ application (there are several ways and system wide installation is often not the best choice).
## Building with bazel (recommended)
## make (on UNIX systems)
Bazel is the primary build system for gRPC C++ and if you're comfortable with using bazel, we can certainly recommend it.
Using bazel will give you the best developer experience as well as faster and cleaner builds.
You'll need `bazel` version `1.0.0` or higher to build gRPC.
See [Installing Bazel](https://docs.bazel.build/versions/master/install.html) for instructions how to install bazel on your system.
We support building with `bazel` on Linux, MacOS and Windows.
From the grpc repository root
```sh
$ make
```
NOTE: if you get an error on linux such as 'aclocal-1.15: command not found', which can happen if you ran 'make' before installing the pre-reqs, try the following:
```sh
$ git clean -f -d -x && git submodule foreach --recursive git clean -f -d -x
$ [sudo] apt-get install build-essential autoconf libtool pkg-config
$ make
# Build gRPC C++
$ bazel build :all
```
## bazel
```
# Run all the C/C++ tests
$ bazel test --config=dbg //test/...
```
See [Installing Bazel](https://docs.bazel.build/versions/master/install.html) for instructions how to install bazel on your system.
NOTE: If you are gRPC maintainer and you have access to our test cluster, you should use the our [gRPC's Remote Execution environment](tools/remote_build/README.md)
to get significant improvement to the build and test speed (and a bunch of other very useful features).
From the grpc repository root
## CMake: Linux/Unix, Using Make
Run from grpc directory after cloning the repo with --recursive or updating submodules.
```
$ bazel build :all
$ mkdir -p cmake/build
$ cd cmake/build
$ cmake ../..
$ make
```
## cmake: Windows, Using Visual Studio 2015 or 2017 (can only build with OPENSSL_NO_ASM).
If you want to build shared libraries (`.so` files), run `cmake` with `-DBUILD_SHARED_LIBS=ON`.
## Building with CMake: Windows, Using Visual Studio 2015 or 2017 (can only build with OPENSSL_NO_ASM).
When using the "Visual Studio" generator,
cmake will generate a solution (`grpc.sln`) that contains a VS project for
every target defined in `CMakeLists.txt` (+ few extra convenience projects
@ -144,7 +143,8 @@ you will be able to browse and build the code.
> cmake --build . --config Release
```
## cmake: Windows, Using Ninja (faster build, supports boringssl's assembly optimizations).
## Building with CMake: Windows, Using Ninja (faster build, supports boringssl's assembly optimizations).
Please note that when using Ninja, you will still need Visual C++ (part of Visual Studio)
installed to be able to compile the C/C++ sources.
```
@ -155,3 +155,29 @@ installed to be able to compile the C/C++ sources.
> cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release
> cmake --build .
```
## Building with make (on UNIX systems)
NOTE: `make` used to be gRPC's default build system, but we're no longer recommending it. You should use `bazel` or `cmake` instead. The `Makefile` is only intended for internal usage and is not meant for public consumption.
From the grpc repository root
```sh
$ make
```
NOTE: if you get an error on linux such as 'aclocal-1.15: command not found', which can happen if you ran 'make' before installing the pre-reqs, try the following:
```sh
$ git clean -f -d -x && git submodule foreach --recursive git clean -f -d -x
$ [sudo] apt-get install build-essential autoconf libtool pkg-config
$ make
```
### A note on `protoc`
By default gRPC uses [protocol buffers](https://github.com/google/protobuf),
you will need the `protoc` compiler to generate stub server and client code.
If you compile gRPC from source, as described below, the Makefile will
automatically try compiling the `protoc` in third_party if you cloned the
repository recursively and it detects that you do not already have 'protoc' compiler
installed.

@ -25,12 +25,12 @@
cmake_minimum_required(VERSION 3.5.1)
set(PACKAGE_NAME "grpc")
set(PACKAGE_VERSION "1.26.0-dev")
set(PACKAGE_VERSION "1.27.0-dev")
set(gRPC_CORE_VERSION "9.0.0")
set(gRPC_CORE_SOVERSION "9")
set(gRPC_CPP_VERSION "1.26.0-dev")
set(gRPC_CPP_VERSION "1.27.0-dev")
set(gRPC_CPP_SOVERSION "1")
set(gRPC_CSHARP_VERSION "2.26.0-dev")
set(gRPC_CSHARP_VERSION "2.27.0-dev")
set(gRPC_CSHARP_SOVERSION "2")
set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
set(PACKAGE_TARNAME "${PACKAGE_NAME}-${PACKAGE_VERSION}")

@ -470,8 +470,8 @@ Q = @
endif
CORE_VERSION = 9.0.0
CPP_VERSION = 1.26.0-dev
CSHARP_VERSION = 2.26.0-dev
CPP_VERSION = 1.27.0-dev
CSHARP_VERSION = 2.27.0-dev
CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)

@ -86,11 +86,21 @@ def grpc_deps():
actual = "@com_github_grpc_grpc//:grpc++_codegen_proto",
)
native.bind(
name = "opencensus-context",
actual = "@io_opencensus_cpp//opencensus/context:context",
)
native.bind(
name = "opencensus-trace",
actual = "@io_opencensus_cpp//opencensus/trace:trace",
)
native.bind(
name = "opencensus-trace-context_util",
actual = "@io_opencensus_cpp//opencensus/trace:context_util",
)
native.bind(
name = "opencensus-stats",
actual = "@io_opencensus_cpp//opencensus/stats:stats",
@ -101,6 +111,16 @@ def grpc_deps():
actual = "@io_opencensus_cpp//opencensus/stats:test_utils",
)
native.bind(
name = "opencensus-with-tag-map",
actual = "@io_opencensus_cpp//opencensus/tags:with_tag_map",
)
native.bind(
name = "opencensus-tags",
actual = "@io_opencensus_cpp//opencensus/tags:tags",
)
if "boringssl" not in native.existing_rules():
http_archive(
name = "boringssl",

@ -14,8 +14,8 @@ settings:
'#10': See the expand_version.py for all the quirks here
core_version: 9.0.0
csharp_major_version: 2
g_stands_for: gon
version: 1.26.0-dev
g_stands_for: guantao
version: 1.27.0-dev
filegroups:
- name: alts_tsi
headers:

@ -25,4 +25,5 @@
- 1.23 'g' stands for ['gangnam'](https://github.com/grpc/grpc/tree/v1.23.x)
- 1.24 'g' stands for ['ganges'](https://github.com/grpc/grpc/tree/v1.24.x)
- 1.25 'g' stands for ['game'](https://github.com/grpc/grpc/tree/v1.25.x)
- 1.26 'g' stands for ['gon'](https://github.com/grpc/grpc/tree/master)
- 1.26 'g' stands for ['gon'](https://github.com/grpc/grpc/tree/v1.26.x)
- 1.27 'g' stands for ['guantao'](https://github.com/grpc/grpc/tree/master)

@ -23,7 +23,7 @@
Pod::Spec.new do |s|
s.name = 'gRPC-C++'
# TODO (mxyan): use version that match gRPC version when pod is stabilized
version = '1.26.0-dev'
version = '1.27.0-dev'
s.version = version
s.summary = 'gRPC C++ library'
s.homepage = 'https://grpc.io'

@ -22,7 +22,7 @@
Pod::Spec.new do |s|
s.name = 'gRPC-Core'
version = '1.26.0-dev'
version = '1.27.0-dev'
s.version = version
s.summary = 'Core cross-platform gRPC library, written in C'
s.homepage = 'https://grpc.io'

@ -21,7 +21,7 @@
Pod::Spec.new do |s|
s.name = 'gRPC-ProtoRPC'
version = '1.26.0-dev'
version = '1.27.0-dev'
s.version = version
s.summary = 'RPC library for Protocol Buffers, based on gRPC'
s.homepage = 'https://grpc.io'

@ -21,7 +21,7 @@
Pod::Spec.new do |s|
s.name = 'gRPC-RxLibrary'
version = '1.26.0-dev'
version = '1.27.0-dev'
s.version = version
s.summary = 'Reactive Extensions library for iOS/OSX.'
s.homepage = 'https://grpc.io'

@ -20,7 +20,7 @@
Pod::Spec.new do |s|
s.name = 'gRPC'
version = '1.26.0-dev'
version = '1.27.0-dev'
s.version = version
s.summary = 'gRPC client library for iOS/OSX'
s.homepage = 'https://grpc.io'

@ -28,8 +28,6 @@
#include <grpcpp/support/client_callback_impl.h>
#include <grpcpp/support/status.h>
#include <functional>
namespace grpc {
typedef ::grpc_impl::ClientAsyncReaderWriter<ByteBuffer, ByteBuffer>
@ -92,15 +90,15 @@ class GenericStub final {
void UnaryCall(grpc_impl::ClientContext* context,
const grpc::string& method, const grpc::ByteBuffer* request,
grpc::ByteBuffer* response,
grpc_impl::experimental::ClientUnaryReactor* reactor);
grpc_impl::ClientUnaryReactor* reactor);
/// Setup a call to a named method \a method using \a context and tied to
/// \a reactor . Like any other bidi streaming RPC, it will not be activated
/// until StartCall is invoked on its reactor.
void PrepareBidiStreamingCall(
grpc_impl::ClientContext* context, const grpc::string& method,
grpc_impl::experimental::ClientBidiReactor<grpc::ByteBuffer,
grpc::ByteBuffer>* reactor);
grpc_impl::ClientBidiReactor<grpc::ByteBuffer, grpc::ByteBuffer>*
reactor);
private:
GenericStub* stub_;

@ -19,6 +19,8 @@
#ifndef GRPCPP_IMPL_CODEGEN_ASYNC_GENERIC_SERVICE_H
#define GRPCPP_IMPL_CODEGEN_ASYNC_GENERIC_SERVICE_H
#include <grpc/impl/codegen/port_platform.h>
#include <grpcpp/impl/codegen/async_stream_impl.h>
#include <grpcpp/impl/codegen/byte_buffer.h>
#include <grpcpp/impl/codegen/server_callback_handlers.h>
@ -87,16 +89,18 @@ class AsyncGenericService final {
grpc_impl::Server* server_;
};
#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
namespace experimental {
#endif
/// \a ServerGenericBidiReactor is the reactor class for bidi streaming RPCs
/// invoked on a CallbackGenericService. It is just a ServerBidi reactor with
/// ByteBuffer arguments.
using ServerGenericBidiReactor =
::grpc_impl::experimental::ServerBidiReactor<ByteBuffer, ByteBuffer>;
::grpc_impl::ServerBidiReactor<ByteBuffer, ByteBuffer>;
class GenericCallbackServerContext final
: public ::grpc_impl::experimental::CallbackServerContext {
: public ::grpc_impl::CallbackServerContext {
public:
const grpc::string& method() const { return method_; }
const grpc::string& host() const { return host_; }
@ -108,7 +112,7 @@ class GenericCallbackServerContext final
void Clear() {
method_.clear();
host_.clear();
::grpc_impl::experimental::CallbackServerContext::Clear();
::grpc_impl::CallbackServerContext::Clear();
}
grpc::string method_;
@ -143,14 +147,17 @@ class CallbackGenericService {
Handler() {
return new ::grpc_impl::internal::CallbackBidiHandler<ByteBuffer,
ByteBuffer>(
[this](::grpc_impl::experimental::CallbackServerContext* ctx) {
[this](::grpc_impl::CallbackServerContext* ctx) {
return CreateReactor(static_cast<GenericCallbackServerContext*>(ctx));
});
}
grpc_impl::Server* server_{nullptr};
};
#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
} // namespace experimental
#endif
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_ASYNC_GENERIC_SERVICE_H

@ -22,33 +22,54 @@
#include <grpcpp/impl/codegen/client_callback_impl.h>
namespace grpc {
#ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
template <class Response>
using ClientCallbackReader = ::grpc_impl::ClientCallbackReader<Response>;
template <class Request>
using ClientCallbackWriter = ::grpc_impl::ClientCallbackWriter<Request>;
template <class Request, class Response>
using ClientCallbackReaderWriter =
::grpc_impl::ClientCallbackReaderWriter<Request, Response>;
template <class Response>
using ClientReadReactor = ::grpc_impl::ClientReadReactor<Response>;
template <class Request>
using ClientWriteReactor = ::grpc_impl::ClientWriteReactor<Request>;
template <class Request, class Response>
using ClientBidiReactor = ::grpc_impl::ClientBidiReactor<Request, Response>;
typedef ::grpc_impl::ClientUnaryReactor ClientUnaryReactor;
#endif
// TODO(vjpai): Remove namespace experimental when de-experimentalized fully.
namespace experimental {
template <class Response>
using ClientCallbackReader =
::grpc_impl::experimental::ClientCallbackReader<Response>;
using ClientCallbackReader = ::grpc_impl::ClientCallbackReader<Response>;
template <class Request>
using ClientCallbackWriter =
::grpc_impl::experimental::ClientCallbackWriter<Request>;
using ClientCallbackWriter = ::grpc_impl::ClientCallbackWriter<Request>;
template <class Request, class Response>
using ClientCallbackReaderWriter =
::grpc_impl::experimental::ClientCallbackReaderWriter<Request, Response>;
::grpc_impl::ClientCallbackReaderWriter<Request, Response>;
template <class Response>
using ClientReadReactor =
::grpc_impl::experimental::ClientReadReactor<Response>;
using ClientReadReactor = ::grpc_impl::ClientReadReactor<Response>;
template <class Request>
using ClientWriteReactor =
::grpc_impl::experimental::ClientWriteReactor<Request>;
using ClientWriteReactor = ::grpc_impl::ClientWriteReactor<Request>;
template <class Request, class Response>
using ClientBidiReactor =
::grpc_impl::experimental::ClientBidiReactor<Request, Response>;
using ClientBidiReactor = ::grpc_impl::ClientBidiReactor<Request, Response>;
typedef ::grpc_impl::ClientUnaryReactor ClientUnaryReactor;
typedef ::grpc_impl::experimental::ClientUnaryReactor ClientUnaryReactor;
} // namespace experimental
} // namespace grpc

@ -103,8 +103,6 @@ class CallbackUnaryCallImpl {
};
} // namespace internal
namespace experimental {
// Forward declarations
template <class Request, class Response>
class ClientBidiReactor;
@ -404,8 +402,6 @@ inline void ClientCallbackUnary::BindReactor(ClientUnaryReactor* reactor) {
reactor->BindCall(this);
}
} // namespace experimental
namespace internal {
// Forward declare factory classes for friendship
@ -418,7 +414,7 @@ class ClientCallbackWriterFactory;
template <class Request, class Response>
class ClientCallbackReaderWriterImpl
: public experimental::ClientCallbackReaderWriter<Request, Response> {
: public ClientCallbackReaderWriter<Request, Response> {
public:
// always allocated against a call arena, no memory free required
static void operator delete(void* /*ptr*/, std::size_t size) {
@ -562,9 +558,9 @@ class ClientCallbackReaderWriterImpl
private:
friend class ClientCallbackReaderWriterFactory<Request, Response>;
ClientCallbackReaderWriterImpl(
grpc::internal::Call call, ::grpc_impl::ClientContext* context,
experimental::ClientBidiReactor<Request, Response>* reactor)
ClientCallbackReaderWriterImpl(grpc::internal::Call call,
::grpc_impl::ClientContext* context,
ClientBidiReactor<Request, Response>* reactor)
: context_(context),
call_(call),
reactor_(reactor),
@ -574,7 +570,7 @@ class ClientCallbackReaderWriterImpl
::grpc_impl::ClientContext* const context_;
grpc::internal::Call call_;
experimental::ClientBidiReactor<Request, Response>* const reactor_;
ClientBidiReactor<Request, Response>* const reactor_;
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
grpc::internal::CallOpRecvInitialMetadata>
@ -612,11 +608,10 @@ class ClientCallbackReaderWriterImpl
template <class Request, class Response>
class ClientCallbackReaderWriterFactory {
public:
static void Create(
::grpc::ChannelInterface* channel,
const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context,
experimental::ClientBidiReactor<Request, Response>* reactor) {
static void Create(::grpc::ChannelInterface* channel,
const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context,
ClientBidiReactor<Request, Response>* reactor) {
grpc::internal::Call call =
channel->CreateCall(method, context, channel->CallbackCQ());
@ -629,8 +624,7 @@ class ClientCallbackReaderWriterFactory {
};
template <class Response>
class ClientCallbackReaderImpl
: public experimental::ClientCallbackReader<Response> {
class ClientCallbackReaderImpl : public ClientCallbackReader<Response> {
public:
// always allocated against a call arena, no memory free required
static void operator delete(void* /*ptr*/, std::size_t size) {
@ -716,7 +710,7 @@ class ClientCallbackReaderImpl
ClientCallbackReaderImpl(::grpc::internal::Call call,
::grpc_impl::ClientContext* context,
Request* request,
experimental::ClientReadReactor<Response>* reactor)
ClientReadReactor<Response>* reactor)
: context_(context), call_(call), reactor_(reactor) {
this->BindReactor(reactor);
// TODO(vjpai): don't assert
@ -726,7 +720,7 @@ class ClientCallbackReaderImpl
::grpc_impl::ClientContext* const context_;
grpc::internal::Call call_;
experimental::ClientReadReactor<Response>* const reactor_;
ClientReadReactor<Response>* const reactor_;
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
grpc::internal::CallOpSendMessage,
@ -757,7 +751,7 @@ class ClientCallbackReaderFactory {
const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context,
const Request* request,
experimental::ClientReadReactor<Response>* reactor) {
ClientReadReactor<Response>* reactor) {
grpc::internal::Call call =
channel->CreateCall(method, context, channel->CallbackCQ());
@ -769,8 +763,7 @@ class ClientCallbackReaderFactory {
};
template <class Request>
class ClientCallbackWriterImpl
: public experimental::ClientCallbackWriter<Request> {
class ClientCallbackWriterImpl : public ClientCallbackWriter<Request> {
public:
// always allocated against a call arena, no memory free required
static void operator delete(void* /*ptr*/, std::size_t size) {
@ -896,7 +889,7 @@ class ClientCallbackWriterImpl
ClientCallbackWriterImpl(::grpc::internal::Call call,
::grpc_impl::ClientContext* context,
Response* response,
experimental::ClientWriteReactor<Request>* reactor)
ClientWriteReactor<Request>* reactor)
: context_(context),
call_(call),
reactor_(reactor),
@ -908,7 +901,7 @@ class ClientCallbackWriterImpl
::grpc_impl::ClientContext* const context_;
grpc::internal::Call call_;
experimental::ClientWriteReactor<Request>* const reactor_;
ClientWriteReactor<Request>* const reactor_;
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
grpc::internal::CallOpRecvInitialMetadata>
@ -947,7 +940,7 @@ class ClientCallbackWriterFactory {
static void Create(::grpc::ChannelInterface* channel,
const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context, Response* response,
experimental::ClientWriteReactor<Request>* reactor) {
ClientWriteReactor<Request>* reactor) {
grpc::internal::Call call =
channel->CreateCall(method, context, channel->CallbackCQ());
@ -958,7 +951,7 @@ class ClientCallbackWriterFactory {
}
};
class ClientCallbackUnaryImpl final : public experimental::ClientCallbackUnary {
class ClientCallbackUnaryImpl final : public ClientCallbackUnary {
public:
// always allocated against a call arena, no memory free required
static void operator delete(void* /*ptr*/, std::size_t size) {
@ -1015,8 +1008,7 @@ class ClientCallbackUnaryImpl final : public experimental::ClientCallbackUnary {
template <class Request, class Response>
ClientCallbackUnaryImpl(::grpc::internal::Call call,
::grpc_impl::ClientContext* context, Request* request,
Response* response,
experimental::ClientUnaryReactor* reactor)
Response* response, ClientUnaryReactor* reactor)
: context_(context), call_(call), reactor_(reactor) {
this->BindReactor(reactor);
// TODO(vjpai): don't assert
@ -1028,7 +1020,7 @@ class ClientCallbackUnaryImpl final : public experimental::ClientCallbackUnary {
::grpc_impl::ClientContext* const context_;
grpc::internal::Call call_;
experimental::ClientUnaryReactor* const reactor_;
ClientUnaryReactor* const reactor_;
grpc::internal::CallOpSet<grpc::internal::CallOpSendInitialMetadata,
grpc::internal::CallOpSendMessage,
@ -1055,7 +1047,7 @@ class ClientCallbackUnaryFactory {
const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context,
const Request* request, Response* response,
experimental::ClientUnaryReactor* reactor) {
ClientUnaryReactor* reactor) {
grpc::internal::Call call =
channel->CreateCall(method, context, channel->CallbackCQ());

@ -107,10 +107,8 @@ class ClientAsyncReaderWriter;
template <class R>
class ClientAsyncResponseReader;
namespace experimental {
class ServerContextBase;
class CallbackServerContext;
} // namespace experimental
/// Options for \a ClientContext::FromServerContext specifying which traits from
/// the \a ServerContext to propagate (copy) from it into a new \a
@ -202,7 +200,7 @@ class ClientContext {
const grpc_impl::ServerContext& server_context,
PropagationOptions options = PropagationOptions());
static std::unique_ptr<ClientContext> FromCallbackServerContext(
const grpc_impl::experimental::CallbackServerContext& server_context,
const grpc_impl::CallbackServerContext& server_context,
PropagationOptions options = PropagationOptions());
/// Add the (\a meta_key, \a meta_value) pair to the metadata associated with
@ -484,7 +482,7 @@ class ClientContext {
void SendCancelToInterceptors();
static std::unique_ptr<ClientContext> FromInternalServerContext(
const grpc_impl::experimental::ServerContextBase& server_context,
const grpc_impl::ServerContextBase& server_context,
PropagationOptions options);
bool initial_metadata_received_;

@ -56,9 +56,7 @@ template <class R>
class ServerReader;
template <class W>
class ServerWriter;
namespace experimental {
class ServerContextBase;
} // namespace experimental
namespace internal {
template <class W, class R>
class ServerReaderWriterBody;
@ -277,7 +275,7 @@ class CompletionQueue : private ::grpc::GrpcLibraryCodegen {
template <::grpc::StatusCode code>
friend class ::grpc_impl::internal::ErrorMethodHandler;
friend class ::grpc_impl::Server;
friend class ::grpc_impl::experimental::ServerContextBase;
friend class ::grpc_impl::ServerContextBase;
friend class ::grpc::ServerInterface;
template <class InputMessage, class OutputMessage>
friend class ::grpc::internal::BlockingUnaryCallImpl;

@ -20,7 +20,9 @@
#define GRPCPP_IMPL_CODEGEN_MESSAGE_ALLOCATOR_H
namespace grpc {
#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
namespace experimental {
#endif
// NOTE: This is an API for advanced users who need custom allocators.
// Per rpc struct for the allocator. This is the interface to return to user.
@ -67,7 +69,25 @@ class MessageAllocator {
virtual MessageHolder<RequestT, ResponseT>* AllocateMessages() = 0;
};
#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
} // namespace experimental
#endif
// TODO(vjpai): Remove namespace experimental when de-experimentalized fully.
#ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
namespace experimental {
using ::grpc::RpcAllocatorState;
template <typename RequestT, typename ResponseT>
using MessageHolder = ::grpc::MessageHolder<RequestT, ResponseT>;
template <typename RequestT, typename ResponseT>
using MessageAllocator = ::grpc::MessageAllocator<RequestT, ResponseT>;
} // namespace experimental
#endif
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_MESSAGE_ALLOCATOR_H

@ -345,8 +345,7 @@ template <::grpc::StatusCode code>
class ErrorMethodHandler : public ::grpc::internal::MethodHandler {
public:
template <class T>
static void FillOps(::grpc_impl::experimental::ServerContextBase* context,
T* ops) {
static void FillOps(::grpc_impl::ServerContextBase* context, T* ops) {
::grpc::Status status(code, "");
if (!context->sent_initial_metadata_) {
ops->SendInitialMetadata(&context->initial_metadata_,

@ -32,9 +32,7 @@
#include <grpcpp/impl/codegen/status.h>
namespace grpc_impl {
namespace experimental {
class ServerContextBase;
}
} // namespace grpc_impl
namespace grpc {
@ -54,8 +52,7 @@ class MethodHandler {
/// \param requester : used only by the callback API. It is a function
/// called by the RPC Controller to request another RPC (and also
/// to set up the state required to make that request possible)
HandlerParameter(Call* c,
::grpc_impl::experimental::ServerContextBase* context,
HandlerParameter(Call* c, ::grpc_impl::ServerContextBase* context,
void* req, Status req_status, void* handler_data,
std::function<void()> requester)
: call(c),
@ -66,7 +63,7 @@ class MethodHandler {
call_requester(std::move(requester)) {}
~HandlerParameter() {}
Call* const call;
::grpc_impl::experimental::ServerContextBase* const server_context;
::grpc_impl::ServerContextBase* const server_context;
void* const request;
const Status status;
void* const internal_data;

@ -22,19 +22,33 @@
#include <grpcpp/impl/codegen/server_callback_impl.h>
namespace grpc {
#ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
template <class Request>
using ServerReadReactor = ::grpc_impl::ServerReadReactor<Request>;
template <class Response>
using ServerWriteReactor = ::grpc_impl::ServerWriteReactor<Response>;
template <class Request, class Response>
using ServerBidiReactor = ::grpc_impl::ServerBidiReactor<Request, Response>;
using ServerUnaryReactor = ::grpc_impl::ServerUnaryReactor;
#endif
// TODO(vjpai): Remove namespace experimental when de-experimentalized fully.
namespace experimental {
template <class Request>
using ServerReadReactor = ::grpc_impl::experimental::ServerReadReactor<Request>;
using ServerReadReactor = ::grpc_impl::ServerReadReactor<Request>;
template <class Response>
using ServerWriteReactor =
::grpc_impl::experimental::ServerWriteReactor<Response>;
using ServerWriteReactor = ::grpc_impl::ServerWriteReactor<Response>;
template <class Request, class Response>
using ServerBidiReactor =
::grpc_impl::experimental::ServerBidiReactor<Request, Response>;
using ServerBidiReactor = ::grpc_impl::ServerBidiReactor<Request, Response>;
using ServerUnaryReactor = ::grpc_impl::experimental::ServerUnaryReactor;
using ServerUnaryReactor = ::grpc_impl::ServerUnaryReactor;
} // namespace experimental
} // namespace grpc

@ -31,9 +31,8 @@ template <class RequestType, class ResponseType>
class CallbackUnaryHandler : public ::grpc::internal::MethodHandler {
public:
explicit CallbackUnaryHandler(
std::function<experimental::ServerUnaryReactor*(
::grpc_impl::experimental::CallbackServerContext*, const RequestType*,
ResponseType*)>
std::function<ServerUnaryReactor*(::grpc_impl::CallbackServerContext*,
const RequestType*, ResponseType*)>
get_reactor)
: get_reactor_(std::move(get_reactor)) {}
@ -53,18 +52,17 @@ class CallbackUnaryHandler : public ::grpc::internal::MethodHandler {
auto* call = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(
param.call->call(), sizeof(ServerCallbackUnaryImpl)))
ServerCallbackUnaryImpl(
static_cast<::grpc_impl::experimental::CallbackServerContext*>(
static_cast<::grpc_impl::CallbackServerContext*>(
param.server_context),
param.call, allocator_state, std::move(param.call_requester));
param.server_context->BeginCompletionOp(
param.call, [call](bool) { call->MaybeDone(); }, call);
experimental::ServerUnaryReactor* reactor = nullptr;
ServerUnaryReactor* reactor = nullptr;
if (param.status.ok()) {
reactor = ::grpc::internal::CatchingReactorGetter<
experimental::ServerUnaryReactor>(
reactor = ::grpc::internal::CatchingReactorGetter<ServerUnaryReactor>(
get_reactor_,
static_cast<::grpc_impl::experimental::CallbackServerContext*>(
static_cast<::grpc_impl::CallbackServerContext*>(
param.server_context),
call->request(), call->response());
}
@ -110,14 +108,13 @@ class CallbackUnaryHandler : public ::grpc::internal::MethodHandler {
}
private:
std::function<experimental::ServerUnaryReactor*(
::grpc_impl::experimental::CallbackServerContext*, const RequestType*,
ResponseType*)>
std::function<ServerUnaryReactor*(::grpc_impl::CallbackServerContext*,
const RequestType*, ResponseType*)>
get_reactor_;
::grpc::experimental::MessageAllocator<RequestType, ResponseType>*
allocator_ = nullptr;
class ServerCallbackUnaryImpl : public experimental::ServerCallbackUnary {
class ServerCallbackUnaryImpl : public ServerCallbackUnary {
public:
void Finish(::grpc::Status s) override {
finish_tag_.Set(
@ -168,8 +165,7 @@ class CallbackUnaryHandler : public ::grpc::internal::MethodHandler {
friend class CallbackUnaryHandler<RequestType, ResponseType>;
ServerCallbackUnaryImpl(
::grpc_impl::experimental::CallbackServerContext* ctx,
::grpc::internal::Call* call,
::grpc_impl::CallbackServerContext* ctx, ::grpc::internal::Call* call,
::grpc::experimental::MessageHolder<RequestType, ResponseType>*
allocator_state,
std::function<void()> call_requester)
@ -184,7 +180,7 @@ class CallbackUnaryHandler : public ::grpc::internal::MethodHandler {
/// operations), maybe calls OnCancel if possible/needed, and maybe marks
/// the completion of the RPC. This should be the last component of the
/// handler.
void SetupReactor(experimental::ServerUnaryReactor* reactor) {
void SetupReactor(ServerUnaryReactor* reactor) {
reactor_.store(reactor, std::memory_order_relaxed);
this->BindReactor(reactor);
this->MaybeCallOnCancel(reactor);
@ -219,7 +215,7 @@ class CallbackUnaryHandler : public ::grpc::internal::MethodHandler {
finish_ops_;
::grpc::internal::CallbackWithSuccessTag finish_tag_;
::grpc_impl::experimental::CallbackServerContext* const ctx_;
::grpc_impl::CallbackServerContext* const ctx_;
::grpc::internal::Call call_;
::grpc::experimental::MessageHolder<RequestType, ResponseType>* const
allocator_state_;
@ -234,7 +230,7 @@ class CallbackUnaryHandler : public ::grpc::internal::MethodHandler {
// change after that and it only gets used by actions caused, directly or
// indirectly, by that setup. This comment also applies to the reactor_
// variables of the other streaming objects in this file.
std::atomic<experimental::ServerUnaryReactor*> reactor_;
std::atomic<ServerUnaryReactor*> reactor_;
// callbacks_outstanding_ follows a refcount pattern
std::atomic<intptr_t> callbacks_outstanding_{
3}; // reserve for start, Finish, and CompletionOp
@ -245,8 +241,8 @@ template <class RequestType, class ResponseType>
class CallbackClientStreamingHandler : public ::grpc::internal::MethodHandler {
public:
explicit CallbackClientStreamingHandler(
std::function<experimental::ServerReadReactor<RequestType>*(
::grpc_impl::experimental::CallbackServerContext*, ResponseType*)>
std::function<ServerReadReactor<RequestType>*(
::grpc_impl::CallbackServerContext*, ResponseType*)>
get_reactor)
: get_reactor_(std::move(get_reactor)) {}
void RunHandler(const HandlerParameter& param) final {
@ -256,18 +252,18 @@ class CallbackClientStreamingHandler : public ::grpc::internal::MethodHandler {
auto* reader = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(
param.call->call(), sizeof(ServerCallbackReaderImpl)))
ServerCallbackReaderImpl(
static_cast<::grpc_impl::experimental::CallbackServerContext*>(
static_cast<::grpc_impl::CallbackServerContext*>(
param.server_context),
param.call, std::move(param.call_requester));
param.server_context->BeginCompletionOp(
param.call, [reader](bool) { reader->MaybeDone(); }, reader);
experimental::ServerReadReactor<RequestType>* reactor = nullptr;
ServerReadReactor<RequestType>* reactor = nullptr;
if (param.status.ok()) {
reactor = ::grpc::internal::CatchingReactorGetter<
experimental::ServerReadReactor<RequestType>>(
ServerReadReactor<RequestType>>(
get_reactor_,
static_cast<::grpc_impl::experimental::CallbackServerContext*>(
static_cast<::grpc_impl::CallbackServerContext*>(
param.server_context),
reader->response());
}
@ -284,12 +280,11 @@ class CallbackClientStreamingHandler : public ::grpc::internal::MethodHandler {
}
private:
std::function<experimental::ServerReadReactor<RequestType>*(
::grpc_impl::experimental::CallbackServerContext*, ResponseType*)>
std::function<ServerReadReactor<RequestType>*(
::grpc_impl::CallbackServerContext*, ResponseType*)>
get_reactor_;
class ServerCallbackReaderImpl
: public experimental::ServerCallbackReader<RequestType> {
class ServerCallbackReaderImpl : public ServerCallbackReader<RequestType> {
public:
void Finish(::grpc::Status s) override {
finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); }, &finish_ops_,
@ -342,12 +337,12 @@ class CallbackClientStreamingHandler : public ::grpc::internal::MethodHandler {
private:
friend class CallbackClientStreamingHandler<RequestType, ResponseType>;
ServerCallbackReaderImpl(
::grpc_impl::experimental::CallbackServerContext* ctx,
::grpc::internal::Call* call, std::function<void()> call_requester)
ServerCallbackReaderImpl(::grpc_impl::CallbackServerContext* ctx,
::grpc::internal::Call* call,
std::function<void()> call_requester)
: ctx_(ctx), call_(*call), call_requester_(std::move(call_requester)) {}
void SetupReactor(experimental::ServerReadReactor<RequestType>* reactor) {
void SetupReactor(ServerReadReactor<RequestType>* reactor) {
reactor_.store(reactor, std::memory_order_relaxed);
read_tag_.Set(call_.call(),
[this](bool ok) {
@ -393,12 +388,12 @@ class CallbackClientStreamingHandler : public ::grpc::internal::MethodHandler {
read_ops_;
::grpc::internal::CallbackWithSuccessTag read_tag_;
::grpc_impl::experimental::CallbackServerContext* const ctx_;
::grpc_impl::CallbackServerContext* const ctx_;
::grpc::internal::Call call_;
ResponseType resp_;
std::function<void()> call_requester_;
// The memory ordering of reactor_ follows ServerCallbackUnaryImpl.
std::atomic<experimental::ServerReadReactor<RequestType>*> reactor_;
std::atomic<ServerReadReactor<RequestType>*> reactor_;
// callbacks_outstanding_ follows a refcount pattern
std::atomic<intptr_t> callbacks_outstanding_{
3}; // reserve for OnStarted, Finish, and CompletionOp
@ -409,9 +404,8 @@ template <class RequestType, class ResponseType>
class CallbackServerStreamingHandler : public ::grpc::internal::MethodHandler {
public:
explicit CallbackServerStreamingHandler(
std::function<experimental::ServerWriteReactor<ResponseType>*(
::grpc_impl::experimental::CallbackServerContext*,
const RequestType*)>
std::function<ServerWriteReactor<ResponseType>*(
::grpc_impl::CallbackServerContext*, const RequestType*)>
get_reactor)
: get_reactor_(std::move(get_reactor)) {}
void RunHandler(const HandlerParameter& param) final {
@ -421,19 +415,19 @@ class CallbackServerStreamingHandler : public ::grpc::internal::MethodHandler {
auto* writer = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(
param.call->call(), sizeof(ServerCallbackWriterImpl)))
ServerCallbackWriterImpl(
static_cast<::grpc_impl::experimental::CallbackServerContext*>(
static_cast<::grpc_impl::CallbackServerContext*>(
param.server_context),
param.call, static_cast<RequestType*>(param.request),
std::move(param.call_requester));
param.server_context->BeginCompletionOp(
param.call, [writer](bool) { writer->MaybeDone(); }, writer);
experimental::ServerWriteReactor<ResponseType>* reactor = nullptr;
ServerWriteReactor<ResponseType>* reactor = nullptr;
if (param.status.ok()) {
reactor = ::grpc::internal::CatchingReactorGetter<
experimental::ServerWriteReactor<ResponseType>>(
ServerWriteReactor<ResponseType>>(
get_reactor_,
static_cast<::grpc_impl::experimental::CallbackServerContext*>(
static_cast<::grpc_impl::CallbackServerContext*>(
param.server_context),
writer->request());
}
@ -466,12 +460,11 @@ class CallbackServerStreamingHandler : public ::grpc::internal::MethodHandler {
}
private:
std::function<experimental::ServerWriteReactor<ResponseType>*(
::grpc_impl::experimental::CallbackServerContext*, const RequestType*)>
std::function<ServerWriteReactor<ResponseType>*(
::grpc_impl::CallbackServerContext*, const RequestType*)>
get_reactor_;
class ServerCallbackWriterImpl
: public experimental::ServerCallbackWriter<ResponseType> {
class ServerCallbackWriterImpl : public ServerCallbackWriter<ResponseType> {
public:
void Finish(::grpc::Status s) override {
finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); }, &finish_ops_,
@ -543,16 +536,16 @@ class CallbackServerStreamingHandler : public ::grpc::internal::MethodHandler {
private:
friend class CallbackServerStreamingHandler<RequestType, ResponseType>;
ServerCallbackWriterImpl(
::grpc_impl::experimental::CallbackServerContext* ctx,
::grpc::internal::Call* call, const RequestType* req,
std::function<void()> call_requester)
ServerCallbackWriterImpl(::grpc_impl::CallbackServerContext* ctx,
::grpc::internal::Call* call,
const RequestType* req,
std::function<void()> call_requester)
: ctx_(ctx),
call_(*call),
req_(req),
call_requester_(std::move(call_requester)) {}
void SetupReactor(experimental::ServerWriteReactor<ResponseType>* reactor) {
void SetupReactor(ServerWriteReactor<ResponseType>* reactor) {
reactor_.store(reactor, std::memory_order_relaxed);
write_tag_.Set(
call_.call(),
@ -598,12 +591,12 @@ class CallbackServerStreamingHandler : public ::grpc::internal::MethodHandler {
write_ops_;
::grpc::internal::CallbackWithSuccessTag write_tag_;
::grpc_impl::experimental::CallbackServerContext* const ctx_;
::grpc_impl::CallbackServerContext* const ctx_;
::grpc::internal::Call call_;
const RequestType* req_;
std::function<void()> call_requester_;
// The memory ordering of reactor_ follows ServerCallbackUnaryImpl.
std::atomic<experimental::ServerWriteReactor<ResponseType>*> reactor_;
std::atomic<ServerWriteReactor<ResponseType>*> reactor_;
// callbacks_outstanding_ follows a refcount pattern
std::atomic<intptr_t> callbacks_outstanding_{
3}; // reserve for OnStarted, Finish, and CompletionOp
@ -614,8 +607,8 @@ template <class RequestType, class ResponseType>
class CallbackBidiHandler : public ::grpc::internal::MethodHandler {
public:
explicit CallbackBidiHandler(
std::function<experimental::ServerBidiReactor<RequestType, ResponseType>*(
::grpc_impl::experimental::CallbackServerContext*)>
std::function<ServerBidiReactor<RequestType, ResponseType>*(
::grpc_impl::CallbackServerContext*)>
get_reactor)
: get_reactor_(std::move(get_reactor)) {}
void RunHandler(const HandlerParameter& param) final {
@ -624,20 +617,18 @@ class CallbackBidiHandler : public ::grpc::internal::MethodHandler {
auto* stream = new (::grpc::g_core_codegen_interface->grpc_call_arena_alloc(
param.call->call(), sizeof(ServerCallbackReaderWriterImpl)))
ServerCallbackReaderWriterImpl(
static_cast<::grpc_impl::experimental::CallbackServerContext*>(
static_cast<::grpc_impl::CallbackServerContext*>(
param.server_context),
param.call, std::move(param.call_requester));
param.server_context->BeginCompletionOp(
param.call, [stream](bool) { stream->MaybeDone(); }, stream);
experimental::ServerBidiReactor<RequestType, ResponseType>* reactor =
nullptr;
ServerBidiReactor<RequestType, ResponseType>* reactor = nullptr;
if (param.status.ok()) {
reactor = ::grpc::internal::CatchingReactorGetter<
experimental::ServerBidiReactor<RequestType, ResponseType>>(
get_reactor_,
static_cast<::grpc_impl::experimental::CallbackServerContext*>(
param.server_context));
ServerBidiReactor<RequestType, ResponseType>>(
get_reactor_, static_cast<::grpc_impl::CallbackServerContext*>(
param.server_context));
}
if (reactor == nullptr) {
@ -653,13 +644,12 @@ class CallbackBidiHandler : public ::grpc::internal::MethodHandler {
}
private:
std::function<experimental::ServerBidiReactor<RequestType, ResponseType>*(
::grpc_impl::experimental::CallbackServerContext*)>
std::function<ServerBidiReactor<RequestType, ResponseType>*(
::grpc_impl::CallbackServerContext*)>
get_reactor_;
class ServerCallbackReaderWriterImpl
: public experimental::ServerCallbackReaderWriter<RequestType,
ResponseType> {
: public ServerCallbackReaderWriter<RequestType, ResponseType> {
public:
void Finish(::grpc::Status s) override {
finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); }, &finish_ops_,
@ -736,13 +726,12 @@ class CallbackBidiHandler : public ::grpc::internal::MethodHandler {
private:
friend class CallbackBidiHandler<RequestType, ResponseType>;
ServerCallbackReaderWriterImpl(
::grpc_impl::experimental::CallbackServerContext* ctx,
::grpc::internal::Call* call, std::function<void()> call_requester)
ServerCallbackReaderWriterImpl(::grpc_impl::CallbackServerContext* ctx,
::grpc::internal::Call* call,
std::function<void()> call_requester)
: ctx_(ctx), call_(*call), call_requester_(std::move(call_requester)) {}
void SetupReactor(
experimental::ServerBidiReactor<RequestType, ResponseType>* reactor) {
void SetupReactor(ServerBidiReactor<RequestType, ResponseType>* reactor) {
reactor_.store(reactor, std::memory_order_relaxed);
write_tag_.Set(
call_.call(),
@ -796,12 +785,11 @@ class CallbackBidiHandler : public ::grpc::internal::MethodHandler {
read_ops_;
::grpc::internal::CallbackWithSuccessTag read_tag_;
::grpc_impl::experimental::CallbackServerContext* const ctx_;
::grpc_impl::CallbackServerContext* const ctx_;
::grpc::internal::Call call_;
std::function<void()> call_requester_;
// The memory ordering of reactor_ follows ServerCallbackUnaryImpl.
std::atomic<experimental::ServerBidiReactor<RequestType, ResponseType>*>
reactor_;
std::atomic<ServerBidiReactor<RequestType, ResponseType>*> reactor_;
// callbacks_outstanding_ follows a refcount pattern
std::atomic<intptr_t> callbacks_outstanding_{
3}; // reserve for OnStarted, Finish, and CompletionOp

@ -136,8 +136,6 @@ class DefaultMessageHolder
} // namespace internal
namespace experimental {
// Forward declarations
class ServerUnaryReactor;
template <class Request>
@ -723,8 +721,6 @@ class ServerUnaryReactor : public internal::ServerReactor {
::grpc::Status status_wanted_ /* GUARDED_BY(writer_mu_) */;
};
} // namespace experimental
namespace internal {
template <class Base>
@ -734,17 +730,15 @@ class FinishOnlyReactor : public Base {
void OnDone() override { this->~FinishOnlyReactor(); }
};
using UnimplementedUnaryReactor =
FinishOnlyReactor<experimental::ServerUnaryReactor>;
using UnimplementedUnaryReactor = FinishOnlyReactor<ServerUnaryReactor>;
template <class Request>
using UnimplementedReadReactor =
FinishOnlyReactor<experimental::ServerReadReactor<Request>>;
using UnimplementedReadReactor = FinishOnlyReactor<ServerReadReactor<Request>>;
template <class Response>
using UnimplementedWriteReactor =
FinishOnlyReactor<experimental::ServerWriteReactor<Response>>;
FinishOnlyReactor<ServerWriteReactor<Response>>;
template <class Request, class Response>
using UnimplementedBidiReactor =
FinishOnlyReactor<experimental::ServerBidiReactor<Request, Response>>;
FinishOnlyReactor<ServerBidiReactor<Request, Response>>;
} // namespace internal
} // namespace grpc_impl

@ -25,10 +25,16 @@ namespace grpc {
typedef ::grpc_impl::ServerContext ServerContext;
#ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
typedef ::grpc_impl::ServerContextBase ServerContextBase;
typedef ::grpc_impl::CallbackServerContext CallbackServerContext;
#endif
// TODO(vjpai): Remove namespace experimental when de-experimentalized fully.
namespace experimental {
typedef ::grpc_impl::experimental::ServerContextBase ServerContextBase;
typedef ::grpc_impl::experimental::CallbackServerContext CallbackServerContext;
typedef ::grpc_impl::ServerContextBase ServerContextBase;
typedef ::grpc_impl::CallbackServerContext CallbackServerContext;
} // namespace experimental
} // namespace grpc

@ -24,8 +24,9 @@
#include <memory>
#include <vector>
#include <grpc/impl/codegen/compression_types.h>
#include <grpc/impl/codegen/port_platform.h>
#include <grpc/impl/codegen/compression_types.h>
#include <grpcpp/impl/codegen/call.h>
#include <grpcpp/impl/codegen/call_op_set.h>
#include <grpcpp/impl/codegen/callback_common.h>
@ -95,10 +96,13 @@ namespace grpc {
class GenericServerContext;
class ServerInterface;
#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
namespace experimental {
#endif
class GenericCallbackServerContext;
#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
} // namespace experimental
#endif
namespace internal {
class Call;
} // namespace internal
@ -112,7 +116,6 @@ class DefaultReactorTestPeer;
} // namespace grpc
namespace grpc_impl {
namespace experimental {
/// Base class of ServerContext. Experimental until callback API is final.
class ServerContextBase {
@ -297,7 +300,7 @@ class ServerContextBase {
/// from the method handler.
///
/// WARNING: This is experimental API and could be changed or removed.
::grpc_impl::experimental::ServerUnaryReactor* DefaultReactor() {
::grpc_impl::ServerUnaryReactor* DefaultReactor() {
auto reactor = &default_reactor_;
default_reactor_used_.store(true, std::memory_order_relaxed);
return reactor;
@ -349,7 +352,11 @@ class ServerContextBase {
friend class ::grpc_impl::internal::FinishOnlyReactor;
friend class ::grpc_impl::ClientContext;
friend class ::grpc::GenericServerContext;
#ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
friend class ::grpc::GenericCallbackServerContext;
#else
friend class ::grpc::experimental::GenericCallbackServerContext;
#endif
/// Prevent copying.
ServerContextBase(const ServerContextBase&);
@ -415,7 +422,7 @@ class ServerContextBase {
::grpc::experimental::ServerRpcInfo* rpc_info_;
::grpc::experimental::RpcAllocatorState* message_allocator_state_ = nullptr;
class Reactor : public experimental::ServerUnaryReactor {
class Reactor : public ServerUnaryReactor {
public:
void OnCancel() override {}
void OnDone() override {}
@ -434,8 +441,7 @@ class ServerContextBase {
}
::grpc::Status test_status() const { return test_unary_->status(); }
class TestServerCallbackUnary
: public ::grpc_impl::experimental::ServerCallbackUnary {
class TestServerCallbackUnary : public ::grpc_impl::ServerCallbackUnary {
public:
TestServerCallbackUnary(ServerContextBase* ctx,
std::function<void(::grpc::Status)> func)
@ -460,7 +466,7 @@ class ServerContextBase {
return reactor_;
}
::grpc_impl::experimental::ServerUnaryReactor* const reactor_;
::grpc_impl::ServerUnaryReactor* const reactor_;
std::atomic_bool status_set_{false};
::grpc::Status status_;
const std::function<void(::grpc::Status s)> func_;
@ -471,8 +477,6 @@ class ServerContextBase {
std::unique_ptr<TestServerCallbackUnary> test_unary_;
};
} // namespace experimental
/// A ServerContext or CallbackServerContext allows the code implementing a
/// service handler to:
///
@ -489,48 +493,46 @@ class ServerContextBase {
/// to a \a grpc::ServerBuilder, via \a ServerBuilder::AddChannelArgument.
///
/// \warning ServerContext instances should \em not be reused across rpcs.
class ServerContext : public experimental::ServerContextBase {
class ServerContext : public ServerContextBase {
public:
ServerContext() {} // for async calls
using experimental::ServerContextBase::AddInitialMetadata;
using experimental::ServerContextBase::AddTrailingMetadata;
using experimental::ServerContextBase::IsCancelled;
using experimental::ServerContextBase::SetLoadReportingCosts;
using experimental::ServerContextBase::TryCancel;
using experimental::ServerContextBase::auth_context;
using experimental::ServerContextBase::c_call;
using experimental::ServerContextBase::census_context;
using experimental::ServerContextBase::client_metadata;
using experimental::ServerContextBase::compression_algorithm;
using experimental::ServerContextBase::compression_level;
using experimental::ServerContextBase::compression_level_set;
using experimental::ServerContextBase::deadline;
using experimental::ServerContextBase::peer;
using experimental::ServerContextBase::raw_deadline;
using experimental::ServerContextBase::set_compression_algorithm;
using experimental::ServerContextBase::set_compression_level;
using ServerContextBase::AddInitialMetadata;
using ServerContextBase::AddTrailingMetadata;
using ServerContextBase::IsCancelled;
using ServerContextBase::SetLoadReportingCosts;
using ServerContextBase::TryCancel;
using ServerContextBase::auth_context;
using ServerContextBase::c_call;
using ServerContextBase::census_context;
using ServerContextBase::client_metadata;
using ServerContextBase::compression_algorithm;
using ServerContextBase::compression_level;
using ServerContextBase::compression_level_set;
using ServerContextBase::deadline;
using ServerContextBase::peer;
using ServerContextBase::raw_deadline;
using ServerContextBase::set_compression_algorithm;
using ServerContextBase::set_compression_level;
// Sync/CQ-based Async ServerContext only
using experimental::ServerContextBase::AsyncNotifyWhenDone;
using ServerContextBase::AsyncNotifyWhenDone;
private:
// Constructor for internal use by server only
friend class ::grpc_impl::Server;
ServerContext(gpr_timespec deadline, grpc_metadata_array* arr)
: experimental::ServerContextBase(deadline, arr) {}
: ServerContextBase(deadline, arr) {}
// CallbackServerContext only
using experimental::ServerContextBase::DefaultReactor;
using experimental::ServerContextBase::GetRpcAllocatorState;
using ServerContextBase::DefaultReactor;
using ServerContextBase::GetRpcAllocatorState;
/// Prevent copying.
ServerContext(const ServerContext&) = delete;
ServerContext& operator=(const ServerContext&) = delete;
};
namespace experimental {
class CallbackServerContext : public ServerContextBase {
public:
/// Public constructors are for direct use only by mocking tests. In practice,
@ -568,21 +570,19 @@ class CallbackServerContext : public ServerContextBase {
CallbackServerContext& operator=(const CallbackServerContext&) = delete;
};
} // namespace experimental
} // namespace grpc_impl
static_assert(std::is_base_of<::grpc_impl::experimental::ServerContextBase,
static_assert(std::is_base_of<::grpc_impl::ServerContextBase,
::grpc_impl::ServerContext>::value,
"improper base class");
static_assert(
std::is_base_of<::grpc_impl::experimental::ServerContextBase,
::grpc_impl::experimental::CallbackServerContext>::value,
"improper base class");
static_assert(sizeof(::grpc_impl::experimental::ServerContextBase) ==
static_assert(std::is_base_of<::grpc_impl::ServerContextBase,
::grpc_impl::CallbackServerContext>::value,
"improper base class");
static_assert(sizeof(::grpc_impl::ServerContextBase) ==
sizeof(::grpc_impl::ServerContext),
"wrong size");
static_assert(sizeof(::grpc_impl::experimental::ServerContextBase) ==
sizeof(::grpc_impl::experimental::CallbackServerContext),
static_assert(sizeof(::grpc_impl::ServerContextBase) ==
sizeof(::grpc_impl::CallbackServerContext),
"wrong size");
#endif // GRPCPP_IMPL_CODEGEN_SERVER_CONTEXT_IMPL_H

@ -27,9 +27,7 @@
#include <grpcpp/impl/codegen/string_ref.h>
namespace grpc_impl {
namespace experimental {
class ServerContextBase;
}
} // namespace grpc_impl
namespace grpc {
@ -82,7 +80,7 @@ class ServerRpcInfo {
/// Return a pointer to the underlying ServerContext structure associated
/// with the RPC to support features that apply to it
grpc_impl::experimental::ServerContextBase* server_context() { return ctx_; }
grpc_impl::ServerContextBase* server_context() { return ctx_; }
private:
static_assert(Type::UNARY ==
@ -98,8 +96,8 @@ class ServerRpcInfo {
static_cast<Type>(internal::RpcMethod::BIDI_STREAMING),
"violated expectation about Type enum");
ServerRpcInfo(grpc_impl::experimental::ServerContextBase* ctx,
const char* method, internal::RpcMethod::RpcType type)
ServerRpcInfo(grpc_impl::ServerContextBase* ctx, const char* method,
internal::RpcMethod::RpcType type)
: ctx_(ctx), method_(method), type_(static_cast<Type>(type)) {}
// Runs interceptor at pos \a pos.
@ -129,14 +127,14 @@ class ServerRpcInfo {
}
}
grpc_impl::experimental::ServerContextBase* ctx_ = nullptr;
grpc_impl::ServerContextBase* ctx_ = nullptr;
const char* method_ = nullptr;
const Type type_;
std::atomic<intptr_t> ref_{1};
std::vector<std::unique_ptr<experimental::Interceptor>> interceptors_;
friend class internal::InterceptorBatchMethodsImpl;
friend class grpc_impl::experimental::ServerContextBase;
friend class grpc_impl::ServerContextBase;
};
} // namespace experimental

@ -19,6 +19,8 @@
#ifndef GRPCPP_IMPL_CODEGEN_SERVER_INTERFACE_H
#define GRPCPP_IMPL_CODEGEN_SERVER_INTERFACE_H
#include <grpc/impl/codegen/port_platform.h>
#include <grpc/impl/codegen/grpc_types.h>
#include <grpcpp/impl/codegen/byte_buffer.h>
#include <grpcpp/impl/codegen/call.h>
@ -51,8 +53,15 @@ namespace internal {
class ServerAsyncStreamingInterface;
} // namespace internal
#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
namespace experimental {
#endif
class CallbackGenericService;
#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
} // namespace experimental
#endif
namespace experimental {
class ServerInterceptorFactoryInterface;
} // namespace experimental
@ -124,6 +133,14 @@ class ServerInterface : public internal::CallHook {
/// service. The service must exist for the lifetime of the Server instance.
virtual void RegisterAsyncGenericService(AsyncGenericService* service) = 0;
#ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
/// Register a callback generic service. This call does not take ownership of
/// the service. The service must exist for the lifetime of the Server
/// instance. May not be abstract since this is a post-1.0 API addition.
virtual void RegisterCallbackGenericService(CallbackGenericService*
/*service*/) {}
#else
/// NOTE: class experimental_registration_interface is not part of the public
/// API of this class
/// TODO(vjpai): Move these contents to public API when no longer experimental
@ -142,6 +159,7 @@ class ServerInterface : public internal::CallHook {
virtual experimental_registration_interface* experimental_registration() {
return nullptr;
}
#endif
/// Tries to bind \a server to the given \a addr.
///

@ -24,6 +24,8 @@
#include <memory>
#include <vector>
#include <grpc/impl/codegen/port_platform.h>
#include <grpc/compression.h>
#include <grpc/support/cpu.h>
#include <grpc/support/workaround_list.h>
@ -57,9 +59,15 @@ namespace internal {
class ExternalConnectionAcceptorImpl;
} // namespace internal
#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
namespace experimental {
#endif
class CallbackGenericService;
#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
} // namespace experimental
#endif
namespace experimental {
// EXPERIMENTAL API:
// Interface for a grpc server to build transports with connections created out
// of band.
@ -265,12 +273,14 @@ class ServerBuilder {
builder_->interceptor_creators_ = std::move(interceptor_creators);
}
#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
/// Register a generic service that uses the callback API.
/// Matches requests with any :authority
/// This is mostly useful for writing generic gRPC Proxies where the exact
/// serialization format is unknown
ServerBuilder& RegisterCallbackGenericService(
grpc::experimental::CallbackGenericService* service);
#endif
enum class ExternalConnectionType {
FROM_FD = 0 // in the form of a file descriptor
@ -288,6 +298,15 @@ class ServerBuilder {
ServerBuilder* builder_;
};
#ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
/// Register a generic service that uses the callback API.
/// Matches requests with any :authority
/// This is mostly useful for writing generic gRPC Proxies where the exact
/// serialization format is unknown
ServerBuilder& RegisterCallbackGenericService(
grpc::CallbackGenericService* service);
#endif
/// NOTE: The function experimental() is not stable public API. It is a view
/// to the experimental components of this class. It may be changed or removed
/// at any time.
@ -369,8 +388,13 @@ class ServerBuilder {
std::vector<std::unique_ptr<grpc::ServerBuilderPlugin>> plugins_;
grpc_resource_quota* resource_quota_;
grpc::AsyncGenericService* generic_service_{nullptr};
#ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
grpc::CallbackGenericService* callback_generic_service_{nullptr};
#else
grpc::experimental::CallbackGenericService* callback_generic_service_{
nullptr};
#endif
struct {
bool is_set;
grpc_compression_level level;

@ -23,6 +23,8 @@
#include <memory>
#include <vector>
#include <grpc/impl/codegen/port_platform.h>
#include <grpc/compression.h>
#include <grpc/support/atm.h>
#include <grpcpp/channel_impl.h>
@ -243,6 +245,13 @@ class Server : public grpc::ServerInterface, private grpc::GrpcLibraryCodegen {
/// service. The service must exist for the lifetime of the Server instance.
void RegisterAsyncGenericService(grpc::AsyncGenericService* service) override;
#ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
/// Register a callback-based generic service. This call does not take
/// ownership of theservice. The service must exist for the lifetime of the
/// Server instance.
void RegisterCallbackGenericService(
grpc::CallbackGenericService* service) override;
#else
/// NOTE: class experimental_registration_type is not part of the public API
/// of this class
/// TODO(vjpai): Move these contents to the public API of Server when
@ -270,6 +279,7 @@ class Server : public grpc::ServerInterface, private grpc::GrpcLibraryCodegen {
experimental_registration_interface* experimental_registration() override {
return &experimental_registration_;
}
#endif
void PerformOpsOnCall(grpc::internal::CallOpSetInterface* ops,
grpc::internal::Call* call) override;
@ -318,9 +328,11 @@ class Server : public grpc::ServerInterface, private grpc::GrpcLibraryCodegen {
// List of callback requests to start when server actually starts.
std::list<CallbackRequestBase*> callback_reqs_to_start_;
#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
// For registering experimental callback generic service; remove when that
// method longer experimental
experimental_registration_type experimental_registration_{this};
#endif
// Server status
grpc::internal::Mutex mu_;
@ -357,8 +369,12 @@ class Server : public grpc::ServerInterface, private grpc::GrpcLibraryCodegen {
// When appropriate, use a default callback generic service to handle
// unimplemented methods
#ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
std::unique_ptr<grpc::CallbackGenericService> unimplemented_service_;
#else
std::unique_ptr<grpc::experimental::CallbackGenericService>
unimplemented_service_;
#endif
// A special handler for resource exhausted in sync case
std::unique_ptr<grpc::internal::MethodHandler> resource_exhausted_handler_;

@ -13,8 +13,8 @@
<date>2019-09-24</date>
<time>16:06:07</time>
<version>
<release>1.26.0dev</release>
<api>1.26.0dev</api>
<release>1.27.0dev</release>
<api>1.27.0dev</api>
</version>
<stability>
<release>beta</release>
@ -22,7 +22,7 @@
</stability>
<license>Apache 2.0</license>
<notes>
- gRPC Core 1.26.0 update
- gRPC Core 1.27.0 update
</notes>
<contents>
<dir baseinstalldir="/" name="/">

@ -144,6 +144,7 @@ grpc::string GetHeaderIncludes(grpc_generator::File* file,
"grpcpp/impl/codegen/client_callback.h",
"grpcpp/impl/codegen/client_context.h",
"grpcpp/impl/codegen/completion_queue.h",
"grpcpp/impl/codegen/message_allocator.h",
"grpcpp/impl/codegen/method_handler.h",
"grpcpp/impl/codegen/proto_utils.h",
"grpcpp/impl/codegen/rpc_method.h",
@ -159,17 +160,6 @@ grpc::string GetHeaderIncludes(grpc_generator::File* file,
PrintIncludes(printer.get(), headers, params.use_system_headers,
params.grpc_search_path);
printer->Print(vars, "\n");
printer->Print(vars, "namespace grpc_impl {\n");
printer->Print(vars, "class CompletionQueue;\n");
printer->Print(vars, "class ServerCompletionQueue;\n");
printer->Print(vars, "class ServerContext;\n");
printer->Print(vars, "} // namespace grpc_impl\n\n");
printer->Print(vars, "namespace grpc {\n");
printer->Print(vars, "namespace experimental {\n");
printer->Print(vars, "template <typename RequestT, typename ResponseT>\n");
printer->Print(vars, "class MessageAllocator;\n");
printer->Print(vars, "} // namespace experimental\n");
printer->Print(vars, "} // namespace grpc\n\n");
vars["message_header_ext"] = params.message_header_extension.empty()
? kCppGeneratorMessageHeaderExt
@ -1662,6 +1652,7 @@ grpc::string GetSourceIncludes(grpc_generator::File* file,
"grpcpp/impl/codegen/channel_interface.h",
"grpcpp/impl/codegen/client_unary_call.h",
"grpcpp/impl/codegen/client_callback.h",
"grpcpp/impl/codegen/message_allocator.h",
"grpcpp/impl/codegen/method_handler.h",
"grpcpp/impl/codegen/rpc_service_method.h",
"grpcpp/impl/codegen/server_callback.h",

@ -187,10 +187,10 @@ class HttpProxyMapper : public ProxyMapperInterface {
return false;
}
bool MapAddress(const grpc_resolved_address& address,
const grpc_channel_args* args,
grpc_resolved_address** new_address,
grpc_channel_args** new_args) override {
bool MapAddress(const grpc_resolved_address& /*address*/,
const grpc_channel_args* /*args*/,
grpc_resolved_address** /*new_address*/,
grpc_channel_args** /*new_args*/) override {
return false;
}
};

@ -139,20 +139,22 @@ void Chttp2Connector::OnHandshakeDone(void* arg, grpc_error* error) {
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("connector shutdown");
// We were shut down after handshaking completed successfully, so
// destroy the endpoint here.
// TODO(ctiller): It is currently necessary to shutdown endpoints
// before destroying them, even if we know that there are no
// pending read/write callbacks. This should be fixed, at which
// point this can be removed.
grpc_endpoint_shutdown(args->endpoint, GRPC_ERROR_REF(error));
grpc_endpoint_destroy(args->endpoint);
grpc_channel_args_destroy(args->args);
grpc_slice_buffer_destroy_internal(args->read_buffer);
gpr_free(args->read_buffer);
if (args->endpoint != nullptr) {
// TODO(ctiller): It is currently necessary to shutdown endpoints
// before destroying them, even if we know that there are no
// pending read/write callbacks. This should be fixed, at which
// point this can be removed.
grpc_endpoint_shutdown(args->endpoint, GRPC_ERROR_REF(error));
grpc_endpoint_destroy(args->endpoint);
grpc_channel_args_destroy(args->args);
grpc_slice_buffer_destroy_internal(args->read_buffer);
gpr_free(args->read_buffer);
}
} else {
error = GRPC_ERROR_REF(error);
}
self->result_->Reset();
} else {
} else if (args->endpoint != nullptr) {
grpc_endpoint_delete_from_pollset_set(args->endpoint,
self->args_.interested_parties);
self->result_->transport =
@ -187,6 +189,11 @@ void Chttp2Connector::OnHandshakeDone(void* arg, grpc_error* error) {
grpc_chttp2_transport_start_reading(self->result_->transport,
args->read_buffer, nullptr);
self->result_->channel_args = args->args;
} else {
// If the handshaking succeeded but there is no endpoint, then the
// handshaker may have handed off the connection to some external
// code. Just verify that exit_early flag is set.
GPR_DEBUG_ASSERT(args->exit_early);
}
grpc_closure* notify = self->notify_;
self->notify_ = nullptr;

@ -19,6 +19,10 @@
#ifndef GRPC_CORE_LIB_GPRPP_OPTIONAL_H
#define GRPC_CORE_LIB_GPRPP_OPTIONAL_H
#include <grpc/support/port_platform.h>
#include <utility>
namespace grpc_core {
/* A make-shift alternative for absl::Optional. This can be removed in favor of
@ -27,11 +31,17 @@ template <typename T>
class Optional {
public:
Optional() : value_() {}
void set(const T& val) {
value_ = val;
set_ = true;
}
void set(T&& val) {
value_ = std::move(val);
set_ = true;
}
bool has_value() const { return set_; }
void reset() { set_ = false; }

@ -121,6 +121,16 @@ class StringView final {
size());
}
// Compares with other.
inline int compare(StringView other) {
const size_t len = GPR_MIN(size(), other.size());
const int ret = strncmp(data(), other.data(), len);
if (ret != 0) return ret;
if (size() == other.size()) return 0;
if (size() < other.size()) return -1;
return 1;
}
private:
const char* ptr_;
size_t size_;
@ -133,6 +143,10 @@ inline bool operator==(StringView lhs, StringView rhs) {
inline bool operator!=(StringView lhs, StringView rhs) { return !(lhs == rhs); }
inline bool operator<(StringView lhs, StringView rhs) {
return lhs.compare(rhs) < 0;
}
#endif // GRPC_USE_ABSL
// Converts grpc_slice to StringView.
@ -150,16 +164,6 @@ inline grpc_core::UniquePtr<char> StringViewToCString(const StringView sv) {
return grpc_core::UniquePtr<char>(str);
}
// Compares lhs and rhs.
inline int StringViewCmp(const StringView lhs, const StringView rhs) {
const size_t len = GPR_MIN(lhs.size(), rhs.size());
const int ret = strncmp(lhs.data(), rhs.data(), len);
if (ret != 0) return ret;
if (lhs.size() == rhs.size()) return 0;
if (lhs.size() < rhs.size()) return -1;
return 1;
}
} // namespace grpc_core
#endif /* GRPC_CORE_LIB_GPRPP_STRING_VIEW_H */

@ -189,10 +189,9 @@ int grpc_ssl_cmp_target_name(
grpc_core::StringView target_name, grpc_core::StringView other_target_name,
grpc_core::StringView overridden_target_name,
grpc_core::StringView other_overridden_target_name) {
int c = grpc_core::StringViewCmp(target_name, other_target_name);
int c = target_name.compare(other_target_name);
if (c != 0) return c;
return grpc_core::StringViewCmp(overridden_target_name,
other_overridden_target_name);
return overridden_target_name.compare(other_overridden_target_name);
}
grpc_core::RefCountedPtr<grpc_auth_context> grpc_ssl_peer_to_auth_context(

@ -25,4 +25,4 @@
const char* grpc_version_string(void) { return "9.0.0"; }
const char* grpc_g_stands_for(void) { return "gon"; }
const char* grpc_g_stands_for(void) { return "guantao"; }

@ -30,11 +30,23 @@ To add gRPC as a dependency in bazel:
grpc_deps()
```
NOTE: currently bazel is only supported for building gRPC on Linux.
## cmake
`cmake` is your best option if you cannot use bazel. It supports building on Linux, MacOS and Windows (official support) but also has a good chance of working on other platforms (no promises!). `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 (preferably as a git submodule) and add it to your CMake project with `add_subdirectory`. [Example](../../examples/cpp/helloworld/CMakeLists.txt)
If your project is not using CMake (e.g. you're using `make` directly), you can first install gRPC C++ using CMake,
and have your non-CMake project rely on the `pkgconfig` files which are provided by gRPC installation. [Example](../../test/distrib/cpp/run_distrib_test_cmake_pkgconfig.sh)
## make
Currently the default choice for building on UNIX based systems is `make`.
The default choice for building on UNIX based systems used to be `make`, but we are no longer recommending it.
You should use `bazel` or `cmake` instead.
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`.
@ -44,16 +56,6 @@ 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 (preferably as a git submodule) and add it to your cmake project with `add_subdirectory`. [Example](../../examples/cpp/helloworld/CMakeLists.txt)
## Packaging systems
We do not officially support any packaging system for C++, but there are some community-maintained packages that are kept up-to-date

@ -89,8 +89,7 @@ void ClientContext::set_credentials(
}
std::unique_ptr<ClientContext> ClientContext::FromInternalServerContext(
const grpc_impl::experimental::ServerContextBase& context,
PropagationOptions options) {
const grpc_impl::ServerContextBase& context, PropagationOptions options) {
std::unique_ptr<ClientContext> ctx(new ClientContext);
ctx->propagate_from_call_ = context.call_;
ctx->propagation_options_ = options;
@ -104,7 +103,7 @@ std::unique_ptr<ClientContext> ClientContext::FromServerContext(
}
std::unique_ptr<ClientContext> ClientContext::FromCallbackServerContext(
const grpc_impl::experimental::CallbackServerContext& server_context,
const grpc_impl::CallbackServerContext& server_context,
PropagationOptions options) {
return FromInternalServerContext(server_context, options);
}

@ -80,8 +80,7 @@ void GenericStub::experimental_type::UnaryCall(
void GenericStub::experimental_type::PrepareBidiStreamingCall(
grpc::ClientContext* context, const grpc::string& method,
experimental::ClientBidiReactor<grpc::ByteBuffer, grpc::ByteBuffer>*
reactor) {
ClientBidiReactor<grpc::ByteBuffer, grpc::ByteBuffer>* reactor) {
internal::ClientCallbackReaderWriterFactory<
grpc::ByteBuffer,
grpc::ByteBuffer>::Create(stub_->channel_.get(),

@ -22,5 +22,5 @@
#include <grpcpp/grpcpp.h>
namespace grpc {
grpc::string Version() { return "1.26.0-dev"; }
grpc::string Version() { return "1.27.0-dev"; }
} // namespace grpc

@ -18,11 +18,17 @@
#include <grpc/support/port_platform.h>
#include <string>
#include <utility>
#include <vector>
#include "src/cpp/ext/filters/census/client_filter.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "opencensus/stats/stats.h"
#include "opencensus/tags/tag_key.h"
#include "opencensus/tags/tag_map.h"
#include "src/core/lib/surface/call.h"
#include "src/cpp/ext/filters/census/grpc_plugin.h"
#include "src/cpp/ext/filters/census/measures.h"
@ -152,6 +158,13 @@ void CensusClientCallData::Destroy(grpc_call_element* elem,
const uint64_t request_size = GetOutgoingDataSize(final_info);
const uint64_t response_size = GetIncomingDataSize(final_info);
double latency_ms = absl::ToDoubleMilliseconds(absl::Now() - start_time_);
std::vector<std::pair<opencensus::tags::TagKey, std::string>> tags =
context_.tags().tags();
std::string method = absl::StrCat(method_);
tags.emplace_back(ClientMethodTagKey(), method);
std::string final_status =
absl::StrCat(StatusCodeToString(final_info->final_status));
tags.emplace_back(ClientStatusTagKey(), final_status);
::opencensus::stats::Record(
{{RpcClientSentBytesPerRpc(), static_cast<double>(request_size)},
{RpcClientReceivedBytesPerRpc(), static_cast<double>(response_size)},
@ -160,9 +173,13 @@ void CensusClientCallData::Destroy(grpc_call_element* elem,
ToDoubleMilliseconds(absl::Nanoseconds(elapsed_time_))},
{RpcClientSentMessagesPerRpc(), sent_message_count_},
{RpcClientReceivedMessagesPerRpc(), recv_message_count_}},
{{ClientMethodTagKey(), method_},
{ClientStatusTagKey(), StatusCodeToString(final_info->final_status)}});
tags);
grpc_slice_unref_internal(path_);
if (final_info->final_status != GRPC_STATUS_OK) {
// TODO: Map grpc_status_code to trace::StatusCode.
context_.Span().SetStatus(opencensus::trace::StatusCode::UNKNOWN,
StatusCodeToString(final_info->final_status));
}
context_.EndSpan();
}

@ -18,10 +18,13 @@
#include <grpc/support/port_platform.h>
#include "opencensus/tags/context_util.h"
#include "opencensus/trace/context_util.h"
#include "src/cpp/ext/filters/census/context.h"
namespace grpc {
using ::opencensus::tags::TagMap;
using ::opencensus::trace::Span;
using ::opencensus::trace::SpanContext;
@ -40,7 +43,7 @@ void GenerateServerContext(absl::string_view tracing, absl::string_view stats,
return;
}
}
new (context) CensusContext(method);
new (context) CensusContext(method, TagMap{});
}
void GenerateClientContext(absl::string_view method, CensusContext* ctxt,
@ -52,11 +55,19 @@ void GenerateClientContext(absl::string_view method, CensusContext* ctxt,
SpanContext span_ctxt = parent_ctxt->Context();
Span span = parent_ctxt->Span();
if (span_ctxt.IsValid()) {
new (ctxt) CensusContext(method, &span);
new (ctxt) CensusContext(method, &span, TagMap{});
return;
}
}
new (ctxt) CensusContext(method);
const Span& span = opencensus::trace::GetCurrentSpan();
const TagMap& tags = opencensus::tags::GetCurrentTagMap();
if (span.context().IsValid()) {
// Create span with parent.
new (ctxt) CensusContext(method, &span, tags);
return;
}
// Create span without parent.
new (ctxt) CensusContext(method, tags);
}
size_t TraceContextSerialize(const ::opencensus::trace::SpanContext& context,

@ -25,6 +25,9 @@
#include "absl/memory/memory.h"
#include "absl/strings/string_view.h"
#include "absl/strings/strip.h"
#include "opencensus/context/context.h"
#include "opencensus/tags/tag_map.h"
#include "opencensus/trace/context_util.h"
#include "opencensus/trace/span.h"
#include "opencensus/trace/span_context.h"
#include "opencensus/trace/trace_params.h"
@ -41,25 +44,32 @@ namespace grpc {
// Thread compatible.
class CensusContext {
public:
CensusContext() : span_(::opencensus::trace::Span::BlankSpan()) {}
CensusContext() : span_(::opencensus::trace::Span::BlankSpan()), tags_({}) {}
explicit CensusContext(absl::string_view name)
: span_(::opencensus::trace::Span::StartSpan(name)) {}
explicit CensusContext(absl::string_view name,
const ::opencensus::tags::TagMap& tags)
: span_(::opencensus::trace::Span::StartSpan(name)), tags_(tags) {}
CensusContext(absl::string_view name, const ::opencensus::trace::Span* parent)
: span_(::opencensus::trace::Span::StartSpan(name, parent)) {}
CensusContext(absl::string_view name, const ::opencensus::trace::Span* parent,
const ::opencensus::tags::TagMap& tags)
: span_(::opencensus::trace::Span::StartSpan(name, parent)),
tags_(tags) {}
CensusContext(absl::string_view name,
const ::opencensus::trace::SpanContext& parent_ctxt)
: span_(::opencensus::trace::Span::StartSpanWithRemoteParent(
name, parent_ctxt)) {}
name, parent_ctxt)),
tags_({}) {}
::opencensus::trace::SpanContext Context() const { return span_.context(); }
::opencensus::trace::Span Span() const { return span_; }
void EndSpan() { span_.End(); }
const ::opencensus::trace::Span& Span() const { return span_; }
const ::opencensus::tags::TagMap& tags() const { return tags_; }
::opencensus::trace::SpanContext Context() const { return Span().context(); }
void EndSpan() { Span().End(); }
private:
::opencensus::trace::Span span_;
::opencensus::tags::TagMap tags_;
};
// Serializes the outgoing trace context. Field IDs are 1 byte followed by

@ -101,6 +101,20 @@ ServerBuilder& ServerBuilder::RegisterAsyncGenericService(
return *this;
}
#ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
ServerBuilder& ServerBuilder::RegisterCallbackGenericService(
grpc::CallbackGenericService* service) {
if (generic_service_ || callback_generic_service_) {
gpr_log(GPR_ERROR,
"Adding multiple generic services is unsupported for now. "
"Dropping the service %p",
(void*)service);
} else {
callback_generic_service_ = service;
}
return *this;
}
#else
ServerBuilder& ServerBuilder::experimental_type::RegisterCallbackGenericService(
grpc::experimental::CallbackGenericService* service) {
if (builder_->generic_service_ || builder_->callback_generic_service_) {
@ -113,6 +127,7 @@ ServerBuilder& ServerBuilder::experimental_type::RegisterCallbackGenericService(
}
return *builder_;
}
#endif
std::unique_ptr<grpc::experimental::ExternalConnectionAcceptor>
ServerBuilder::experimental_type::AddExternalConnectionAcceptor(

@ -106,6 +106,15 @@ class UnimplementedAsyncRequestContext {
GenericServerAsyncReaderWriter generic_stream_;
};
// TODO(vjpai): Just for this file, use some contents of the experimental
// namespace here to make the code easier to read below. Remove this when
// de-experimentalized fully.
#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
using ::grpc::experimental::CallbackGenericService;
using ::grpc::experimental::CallbackServerContext;
using ::grpc::experimental::GenericCallbackServerContext;
#endif
} // namespace
ServerInterface::BaseAsyncRequest::BaseAsyncRequest(
@ -543,9 +552,9 @@ class Server::CallbackRequestBase : public grpc::internal::CompletionQueueTag {
template <class ServerContextType>
class Server::CallbackRequest final : public Server::CallbackRequestBase {
public:
static_assert(std::is_base_of<grpc::experimental::CallbackServerContext,
ServerContextType>::value,
"ServerContextType must be derived from CallbackServerContext");
static_assert(
std::is_base_of<grpc::CallbackServerContext, ServerContextType>::value,
"ServerContextType must be derived from CallbackServerContext");
// The constructor needs to know the server for this callback request and its
// index in the server's request count array to allow for proper dynamic
@ -799,14 +808,15 @@ class Server::CallbackRequest final : public Server::CallbackRequestBase {
};
template <>
bool Server::CallbackRequest<grpc::experimental::CallbackServerContext>::
FinalizeResult(void** /*tag*/, bool* /*status*/) {
bool Server::CallbackRequest<grpc::CallbackServerContext>::FinalizeResult(
void** /*tag*/, bool* /*status*/) {
return false;
}
template <>
bool Server::CallbackRequest<grpc::experimental::GenericCallbackServerContext>::
FinalizeResult(void** /*tag*/, bool* status) {
bool Server::CallbackRequest<
grpc::GenericCallbackServerContext>::FinalizeResult(void** /*tag*/,
bool* status) {
if (*status) {
// TODO(yangg) remove the copy here
ctx_.method_ = grpc::StringFromCopiedSlice(call_details_->method);
@ -818,14 +828,14 @@ bool Server::CallbackRequest<grpc::experimental::GenericCallbackServerContext>::
}
template <>
const char* Server::CallbackRequest<
grpc::experimental::CallbackServerContext>::method_name() const {
const char* Server::CallbackRequest<grpc::CallbackServerContext>::method_name()
const {
return method_->name();
}
template <>
const char* Server::CallbackRequest<
grpc::experimental::GenericCallbackServerContext>::method_name() const {
grpc::GenericCallbackServerContext>::method_name() const {
return ctx_.method().c_str();
}
@ -1131,7 +1141,7 @@ bool Server::RegisterService(const grpc::string* host, grpc::Service* service) {
// TODO(vjpai): Register these dynamically based on need
for (int i = 0; i < DEFAULT_CALLBACK_REQS_PER_METHOD; i++) {
callback_reqs_to_start_.push_back(
new CallbackRequest<grpc::experimental::CallbackServerContext>(
new CallbackRequest<grpc::CallbackServerContext>(
this, method_index, method.get(), method_registration_tag));
}
// Enqueue it so that it will be Request'ed later after all request
@ -1161,7 +1171,7 @@ void Server::RegisterAsyncGenericService(grpc::AsyncGenericService* service) {
}
void Server::RegisterCallbackGenericService(
grpc::experimental::CallbackGenericService* service) {
grpc::CallbackGenericService* service) {
GPR_ASSERT(
service->server_ == nullptr &&
"Can only register a callback generic service against one server.");
@ -1174,7 +1184,7 @@ void Server::RegisterCallbackGenericService(
// TODO(vjpai): Register these dynamically based on need
for (int i = 0; i < DEFAULT_CALLBACK_REQS_PER_METHOD; i++) {
callback_reqs_to_start_.push_back(
new CallbackRequest<grpc::experimental::GenericCallbackServerContext>(
new CallbackRequest<grpc::GenericCallbackServerContext>(
this, method_index, nullptr, nullptr));
}
}
@ -1223,8 +1233,7 @@ void Server::Start(grpc::ServerCompletionQueue** cqs, size_t num_cqs) {
// service to handle any unimplemented methods using the default reactor
// creator
if (!callback_reqs_to_start_.empty() && !has_callback_generic_service_) {
unimplemented_service_.reset(
new grpc::experimental::CallbackGenericService);
unimplemented_service_.reset(new grpc::CallbackGenericService);
RegisterCallbackGenericService(unimplemented_service_.get());
}

@ -36,7 +36,6 @@
#include "src/core/lib/surface/call.h"
namespace grpc_impl {
namespace experimental {
// CompletionOp
@ -379,5 +378,4 @@ void ServerContextBase::SetLoadReportingCosts(
}
}
} // namespace experimental
} // namespace grpc_impl

@ -33,11 +33,11 @@ namespace Grpc.Core
/// <summary>
/// Current <c>AssemblyFileVersion</c> of gRPC C# assemblies
/// </summary>
public const string CurrentAssemblyFileVersion = "2.26.0.0";
public const string CurrentAssemblyFileVersion = "2.27.0.0";
/// <summary>
/// Current version of gRPC C#
/// </summary>
public const string CurrentVersion = "2.26.0-dev";
public const string CurrentVersion = "2.27.0-dev";
}
}

@ -599,6 +599,7 @@ namespace Grpc.Core.Internal
TaskCompletionSource<object> delayedStreamingWriteTcs = null;
bool releasedResources;
bool origCancelRequested;
lock (myLock)
{
finished = true;
@ -610,6 +611,7 @@ namespace Grpc.Core.Internal
}
releasedResources = ReleaseResourcesIfPossible();
origCancelRequested = cancelRequested;
}
if (releasedResources)
@ -626,6 +628,14 @@ namespace Grpc.Core.Internal
if (status.StatusCode != StatusCode.OK)
{
streamingResponseCallFinishedTcs.SetException(new RpcException(status, receivedStatus.Trailers));
if (status.StatusCode == StatusCode.Cancelled || origCancelRequested)
{
// Make sure the exception set to the Task is observed,
// otherwise this can trigger "Unobserved exception" when the response stream
// is not read until its end and the task created by the TCS is garbage collected.
// See https://github.com/grpc/grpc/issues/17458
var _ = streamingResponseCallFinishedTcs.Task.Exception;
}
return;
}

@ -8,6 +8,10 @@
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.1' ">
<DefineConstants>$(DefineConstants);GRPC_SUPPORT_WATCH;</DefineConstants>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../Grpc.HealthCheck/Grpc.HealthCheck.csproj" />
<ProjectReference Include="../Grpc.Core/Grpc.Core.csproj" />

@ -1,4 +1,4 @@
#region Copyright notice and license
#region Copyright notice and license
// Copyright 2015 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");

@ -1,4 +1,4 @@
#region Copyright notice and license
#region Copyright notice and license
// Copyright 2015 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
@ -16,8 +16,10 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core;
@ -83,6 +85,169 @@ namespace Grpc.HealthCheck.Tests
Assert.Throws(typeof(ArgumentNullException), () => impl.ClearStatus(null));
}
#if GRPC_SUPPORT_WATCH
[Test]
public async Task Watch()
{
var cts = new CancellationTokenSource();
var context = new TestServerCallContext(cts.Token);
var writer = new TestResponseStreamWriter();
var impl = new HealthServiceImpl();
var callTask = impl.Watch(new HealthCheckRequest { Service = "" }, writer, context);
// Calling Watch on a service that doesn't have a value set will initially return ServiceUnknown
var nextWriteTask = writer.WrittenMessagesReader.ReadAsync();
Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.ServiceUnknown, (await nextWriteTask).Status);
nextWriteTask = writer.WrittenMessagesReader.ReadAsync();
impl.SetStatus("", HealthCheckResponse.Types.ServingStatus.Serving);
Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.Serving, (await nextWriteTask).Status);
nextWriteTask = writer.WrittenMessagesReader.ReadAsync();
impl.SetStatus("", HealthCheckResponse.Types.ServingStatus.NotServing);
Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.NotServing, (await nextWriteTask).Status);
nextWriteTask = writer.WrittenMessagesReader.ReadAsync();
impl.SetStatus("", HealthCheckResponse.Types.ServingStatus.Unknown);
Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.Unknown, (await nextWriteTask).Status);
// Setting status for a different service name will not update Watch results
nextWriteTask = writer.WrittenMessagesReader.ReadAsync();
impl.SetStatus("grpc.test.TestService", HealthCheckResponse.Types.ServingStatus.Serving);
Assert.IsFalse(nextWriteTask.IsCompleted);
impl.ClearStatus("");
Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.ServiceUnknown, (await nextWriteTask).Status);
Assert.IsFalse(callTask.IsCompleted);
cts.Cancel();
await callTask;
}
[Test]
public async Task Watch_MultipleWatchesForSameService()
{
var cts = new CancellationTokenSource();
var context = new TestServerCallContext(cts.Token);
var writer1 = new TestResponseStreamWriter();
var writer2 = new TestResponseStreamWriter();
var impl = new HealthServiceImpl();
var callTask1 = impl.Watch(new HealthCheckRequest { Service = "" }, writer1, context);
var callTask2 = impl.Watch(new HealthCheckRequest { Service = "" }, writer2, context);
// Calling Watch on a service that doesn't have a value set will initially return ServiceUnknown
var nextWriteTask1 = writer1.WrittenMessagesReader.ReadAsync();
var nextWriteTask2 = writer2.WrittenMessagesReader.ReadAsync();
Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.ServiceUnknown, (await nextWriteTask1).Status);
Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.ServiceUnknown, (await nextWriteTask2).Status);
nextWriteTask1 = writer1.WrittenMessagesReader.ReadAsync();
nextWriteTask2 = writer2.WrittenMessagesReader.ReadAsync();
impl.SetStatus("", HealthCheckResponse.Types.ServingStatus.Serving);
Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.Serving, (await nextWriteTask1).Status);
Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.Serving, (await nextWriteTask2).Status);
nextWriteTask1 = writer1.WrittenMessagesReader.ReadAsync();
nextWriteTask2 = writer2.WrittenMessagesReader.ReadAsync();
impl.ClearStatus("");
Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.ServiceUnknown, (await nextWriteTask1).Status);
Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.ServiceUnknown, (await nextWriteTask2).Status);
cts.Cancel();
await callTask1;
await callTask2;
}
[Test]
public async Task Watch_MultipleWatchesForDifferentServices()
{
var cts = new CancellationTokenSource();
var context = new TestServerCallContext(cts.Token);
var writer1 = new TestResponseStreamWriter();
var writer2 = new TestResponseStreamWriter();
var impl = new HealthServiceImpl();
var callTask1 = impl.Watch(new HealthCheckRequest { Service = "One" }, writer1, context);
var callTask2 = impl.Watch(new HealthCheckRequest { Service = "Two" }, writer2, context);
// Calling Watch on a service that doesn't have a value set will initially return ServiceUnknown
var nextWriteTask1 = writer1.WrittenMessagesReader.ReadAsync();
var nextWriteTask2 = writer2.WrittenMessagesReader.ReadAsync();
Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.ServiceUnknown, (await nextWriteTask1).Status);
Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.ServiceUnknown, (await nextWriteTask2).Status);
nextWriteTask1 = writer1.WrittenMessagesReader.ReadAsync();
nextWriteTask2 = writer2.WrittenMessagesReader.ReadAsync();
impl.SetStatus("One", HealthCheckResponse.Types.ServingStatus.Serving);
impl.SetStatus("Two", HealthCheckResponse.Types.ServingStatus.NotServing);
Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.Serving, (await nextWriteTask1).Status);
Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.NotServing, (await nextWriteTask2).Status);
nextWriteTask1 = writer1.WrittenMessagesReader.ReadAsync();
nextWriteTask2 = writer2.WrittenMessagesReader.ReadAsync();
impl.ClearAll();
Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.ServiceUnknown, (await nextWriteTask1).Status);
Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.ServiceUnknown, (await nextWriteTask2).Status);
cts.Cancel();
await callTask1;
await callTask2;
}
[Test]
public async Task Watch_ExceedMaximumCapacitySize_DiscardOldValues()
{
var cts = new CancellationTokenSource();
var context = new TestServerCallContext(cts.Token);
var writer = new TestResponseStreamWriter();
var impl = new HealthServiceImpl();
var callTask = impl.Watch(new HealthCheckRequest { Service = "" }, writer, context);
// Write new 10 statuses. Only last 5 statuses will be returned when we read them from watch writer
for (var i = 0; i < HealthServiceImpl.MaxStatusBufferSize * 2; i++)
{
// These statuses aren't "valid" but it is useful for testing to have an incrementing number
impl.SetStatus("", (HealthCheckResponse.Types.ServingStatus)i);
}
// Read messages in a background task
var statuses = new List<HealthCheckResponse.Types.ServingStatus>();
var readStatusesTask = Task.Run(async () => {
while (await writer.WrittenMessagesReader.WaitToReadAsync())
{
if (writer.WrittenMessagesReader.TryRead(out var response))
{
statuses.Add(response.Status);
}
}
});
// Tell server we're done watching and it can write what it has left and then exit
cts.Cancel();
await callTask;
// Ensure we've read all the queued statuses
writer.Complete();
await readStatusesTask;
// Collection will contain initial written message (ServiceUnknown) plus 5 queued messages
Assert.AreEqual(HealthServiceImpl.MaxStatusBufferSize + 1, statuses.Count);
// Initial written message
Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.ServiceUnknown, statuses[0]);
// Last 5 queued messages
Assert.AreEqual((HealthCheckResponse.Types.ServingStatus)5, statuses[1]);
Assert.AreEqual((HealthCheckResponse.Types.ServingStatus)6, statuses[2]);
Assert.AreEqual((HealthCheckResponse.Types.ServingStatus)7, statuses[3]);
Assert.AreEqual((HealthCheckResponse.Types.ServingStatus)8, statuses[4]);
Assert.AreEqual((HealthCheckResponse.Types.ServingStatus)9, statuses[5]);
}
#endif
private static HealthCheckResponse.Types.ServingStatus GetStatusHelper(HealthServiceImpl impl, string service)
{
return impl.Check(new HealthCheckRequest { Service = service }, null).Result.Status;

@ -0,0 +1,54 @@
#region Copyright notice and license
// 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.
#endregion
#if GRPC_SUPPORT_WATCH
using System.Threading.Channels;
using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Health.V1;
namespace Grpc.HealthCheck.Tests
{
internal class TestResponseStreamWriter : IServerStreamWriter<HealthCheckResponse>
{
private Channel<HealthCheckResponse> _channel;
public TestResponseStreamWriter(int maxCapacity = 1)
{
_channel = System.Threading.Channels.Channel.CreateBounded<HealthCheckResponse>(new BoundedChannelOptions(maxCapacity) {
SingleReader = false,
SingleWriter = true,
FullMode = BoundedChannelFullMode.Wait
});
}
public ChannelReader<HealthCheckResponse> WrittenMessagesReader => _channel.Reader;
public WriteOptions WriteOptions { get; set; }
public Task WriteAsync(HealthCheckResponse message)
{
return _channel.Writer.WriteAsync(message).AsTask();
}
public void Complete()
{
_channel.Writer.Complete();
}
}
}
#endif

@ -0,0 +1,57 @@
#region Copyright notice and license
// 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.
#endregion
#if GRPC_SUPPORT_WATCH
using System;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core;
namespace Grpc.HealthCheck.Tests
{
internal class TestServerCallContext : ServerCallContext
{
private readonly CancellationToken _cancellationToken;
public TestServerCallContext(CancellationToken cancellationToken)
{
_cancellationToken = cancellationToken;
}
protected override string MethodCore { get; }
protected override string HostCore { get; }
protected override string PeerCore { get; }
protected override DateTime DeadlineCore { get; }
protected override Metadata RequestHeadersCore { get; }
protected override CancellationToken CancellationTokenCore => _cancellationToken;
protected override Metadata ResponseTrailersCore { get; }
protected override Status StatusCore { get; set; }
protected override WriteOptions WriteOptionsCore { get; set; }
protected override AuthContext AuthContextCore { get; }
protected override ContextPropagationToken CreatePropagationTokenCore(ContextPropagationOptions options)
{
throw new NotImplementedException();
}
protected override Task WriteResponseHeadersAsyncCore(Metadata responseHeaders)
{
throw new NotImplementedException();
}
}
}
#endif

@ -14,11 +14,15 @@
</PropertyGroup>
<PropertyGroup>
<TargetFrameworks>net45;netstandard1.5;netstandard2.0</TargetFrameworks>
<TargetFrameworks>net45;net462;netstandard1.5;netstandard2.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'net462' or '$(TargetFramework)' == 'netstandard1.5' or '$(TargetFramework)' == 'netstandard2.0' ">
<DefineConstants>$(DefineConstants);GRPC_SUPPORT_WATCH;</DefineConstants>
</PropertyGroup>
<Import Project="..\Grpc.Core\SourceLink.csproj.include" />
<ItemGroup>
@ -35,7 +39,11 @@
<PackageReference Include="Google.Protobuf" Version="$(GoogleProtobufVersion)" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
<ItemGroup Condition=" '$(TargetFramework)' == 'net462' or '$(TargetFramework)' == 'netstandard1.5' or '$(TargetFramework)' == 'netstandard2.0' ">
<PackageReference Include="System.Threading.Channels" Version="4.6.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' or '$(TargetFramework)' == 'net462' ">
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>

@ -1,4 +1,4 @@
#region Copyright notice and license
#region Copyright notice and license
// Copyright 2015 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
@ -17,11 +17,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
#if GRPC_SUPPORT_WATCH
using System.Threading.Channels;
#endif
using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Core.Utils;
using Grpc.Health.V1;
namespace Grpc.HealthCheck
@ -38,10 +39,19 @@ namespace Grpc.HealthCheck
/// </summary>
public class HealthServiceImpl : Grpc.Health.V1.Health.HealthBase
{
private readonly object myLock = new object();
private readonly Dictionary<string, HealthCheckResponse.Types.ServingStatus> statusMap =
// The maximum number of statuses to buffer on the server.
internal const int MaxStatusBufferSize = 5;
private readonly object statusLock = new object();
private readonly Dictionary<string, HealthCheckResponse.Types.ServingStatus> statusMap =
new Dictionary<string, HealthCheckResponse.Types.ServingStatus>();
#if GRPC_SUPPORT_WATCH
private readonly object watchersLock = new object();
private readonly Dictionary<string, List<ChannelWriter<HealthCheckResponse>>> watchers =
new Dictionary<string, List<ChannelWriter<HealthCheckResponse>>>();
#endif
/// <summary>
/// Sets the health status for given service.
/// </summary>
@ -49,10 +59,19 @@ namespace Grpc.HealthCheck
/// <param name="status">the health status</param>
public void SetStatus(string service, HealthCheckResponse.Types.ServingStatus status)
{
lock (myLock)
HealthCheckResponse.Types.ServingStatus previousStatus;
lock (statusLock)
{
previousStatus = GetServiceStatus(service);
statusMap[service] = status;
}
#if GRPC_SUPPORT_WATCH
if (status != previousStatus)
{
NotifyStatus(service, status);
}
#endif
}
/// <summary>
@ -61,21 +80,42 @@ namespace Grpc.HealthCheck
/// <param name="service">The service. Cannot be null.</param>
public void ClearStatus(string service)
{
lock (myLock)
HealthCheckResponse.Types.ServingStatus previousStatus;
lock (statusLock)
{
previousStatus = GetServiceStatus(service);
statusMap.Remove(service);
}
#if GRPC_SUPPORT_WATCH
if (previousStatus != HealthCheckResponse.Types.ServingStatus.ServiceUnknown)
{
NotifyStatus(service, HealthCheckResponse.Types.ServingStatus.ServiceUnknown);
}
#endif
}
/// <summary>
/// Clears statuses for all services.
/// </summary>
public void ClearAll()
{
lock (myLock)
List<KeyValuePair<string, HealthCheckResponse.Types.ServingStatus>> statuses;
lock (statusLock)
{
statuses = statusMap.ToList();
statusMap.Clear();
}
#if GRPC_SUPPORT_WATCH
foreach (KeyValuePair<string, HealthCheckResponse.Types.ServingStatus> status in statuses)
{
if (status.Value != HealthCheckResponse.Types.ServingStatus.ServiceUnknown)
{
NotifyStatus(status.Key, HealthCheckResponse.Types.ServingStatus.ServiceUnknown);
}
}
#endif
}
/// <summary>
@ -86,17 +126,150 @@ namespace Grpc.HealthCheck
/// <returns>The asynchronous response.</returns>
public override Task<HealthCheckResponse> Check(HealthCheckRequest request, ServerCallContext context)
{
lock (myLock)
HealthCheckResponse response = GetHealthCheckResponse(request.Service, throwOnNotFound: true);
return Task.FromResult(response);
}
#if GRPC_SUPPORT_WATCH
/// <summary>
/// Performs a watch for the serving status of the requested service.
/// The server will immediately send back a message indicating the current
/// serving status. It will then subsequently send a new message whenever
/// the service's serving status changes.
///
/// If the requested service is unknown when the call is received, the
/// server will send a message setting the serving status to
/// SERVICE_UNKNOWN but will *not* terminate the call. If at some
/// future point, the serving status of the service becomes known, the
/// server will send a new message with the service's serving status.
///
/// If the call terminates with status UNIMPLEMENTED, then clients
/// should assume this method is not supported and should not retry the
/// call. If the call terminates with any other status (including OK),
/// clients should retry the call with appropriate exponential backoff.
/// </summary>
/// <param name="request">The request received from the client.</param>
/// <param name="responseStream">Used for sending responses back to the client.</param>
/// <param name="context">The context of the server-side call handler being invoked.</param>
/// <returns>A task indicating completion of the handler.</returns>
public override async Task Watch(HealthCheckRequest request, IServerStreamWriter<HealthCheckResponse> responseStream, ServerCallContext context)
{
string service = request.Service;
HealthCheckResponse response = GetHealthCheckResponse(service, throwOnNotFound: false);
await responseStream.WriteAsync(response);
// Channel is used to to marshall multiple callers updating status into a single queue.
// This is required because IServerStreamWriter is not thread safe.
//
// A queue of unwritten statuses could build up if flow control causes responseStream.WriteAsync to await.
// When this number is exceeded the server will discard older statuses. The discarded intermediate statues
// will never be sent to the client.
Channel<HealthCheckResponse> channel = Channel.CreateBounded<HealthCheckResponse>(new BoundedChannelOptions(capacity: MaxStatusBufferSize) {
SingleReader = true,
SingleWriter = false,
FullMode = BoundedChannelFullMode.DropOldest
});
lock (watchersLock)
{
var service = request.Service;
if (!watchers.TryGetValue(service, out List<ChannelWriter<HealthCheckResponse>> channelWriters))
{
channelWriters = new List<ChannelWriter<HealthCheckResponse>>();
watchers.Add(service, channelWriters);
}
channelWriters.Add(channel.Writer);
}
// Watch calls run until ended by the client canceling them.
context.CancellationToken.Register(() => {
lock (watchersLock)
{
if (watchers.TryGetValue(service, out List<ChannelWriter<HealthCheckResponse>> channelWriters))
{
// Remove the writer from the watchers
if (channelWriters.Remove(channel.Writer))
{
// Remove empty collection if service has no more response streams
if (channelWriters.Count == 0)
{
watchers.Remove(service);
}
}
}
}
// Signal the writer is complete and the watch method can exit.
channel.Writer.Complete();
});
// Read messages. WaitToReadAsync will wait until new messages are available.
// Loop will exit when the call is canceled and the writer is marked as complete.
while (await channel.Reader.WaitToReadAsync())
{
if (channel.Reader.TryRead(out HealthCheckResponse item))
{
await responseStream.WriteAsync(item);
}
}
}
private void NotifyStatus(string service, HealthCheckResponse.Types.ServingStatus status)
{
lock (watchersLock)
{
if (watchers.TryGetValue(service, out List<ChannelWriter<HealthCheckResponse>> channelWriters))
{
HealthCheckResponse response = new HealthCheckResponse { Status = status };
foreach (ChannelWriter<HealthCheckResponse> writer in channelWriters)
{
if (!writer.TryWrite(response))
{
throw new InvalidOperationException("Unable to queue health check notification.");
}
}
}
}
}
#endif
private HealthCheckResponse GetHealthCheckResponse(string service, bool throwOnNotFound)
{
HealthCheckResponse response = null;
lock (statusLock)
{
HealthCheckResponse.Types.ServingStatus status;
if (!statusMap.TryGetValue(service, out status))
{
// TODO(jtattermusch): returning specific status from server handler is not supported yet.
throw new RpcException(new Status(StatusCode.NotFound, ""));
if (throwOnNotFound)
{
// TODO(jtattermusch): returning specific status from server handler is not supported yet.
throw new RpcException(new Status(StatusCode.NotFound, ""));
}
else
{
status = HealthCheckResponse.Types.ServingStatus.ServiceUnknown;
}
}
return Task.FromResult(new HealthCheckResponse { Status = status });
response = new HealthCheckResponse { Status = status };
}
return response;
}
private HealthCheckResponse.Types.ServingStatus GetServiceStatus(string service)
{
if (statusMap.TryGetValue(service, out HealthCheckResponse.Types.ServingStatus s))
{
return s;
}
else
{
// A service with no set status has a status of ServiceUnknown
return HealthCheckResponse.Types.ServingStatus.ServiceUnknown;
}
}
}

@ -1,4 +1,4 @@
#region Copyright notice and license
#region Copyright notice and license
// Copyright 2015 gRPC authors.
//
@ -27,3 +27,13 @@ using System.Runtime.CompilerServices;
[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
#if SIGNED
[assembly: InternalsVisibleTo("Grpc.HealthCheck.Tests,PublicKey=" +
"00240000048000009400000006020000002400005253413100040000010001002f5797a92c6fcde81bd4098f43" +
"0442bb8e12768722de0b0cb1b15e955b32a11352740ee59f2c94c48edc8e177d1052536b8ac651bce11ce5da3a" +
"27fc95aff3dc604a6971417453f9483c7b5e836756d5b271bf8f2403fe186e31956148c03d804487cf642f8cc0" +
"71394ee9672dfe5b55ea0f95dfd5a7f77d22c962ccf51320d3")]
#else
[assembly: InternalsVisibleTo("Grpc.HealthCheck.Tests")]
#endif

@ -0,0 +1,100 @@
#region Copyright notice and license
// Copyright 2019 The gRPC Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// 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.
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
using Grpc.Testing;
using NUnit.Framework;
namespace Grpc.IntegrationTesting
{
/// <summary>
/// Runs interop tests in-process.
/// </summary>
public class UnobservedTaskExceptionTest
{
const string Host = "localhost";
Server server;
Channel channel;
TestService.TestServiceClient client;
[OneTimeSetUp]
public void Init()
{
// Disable SO_REUSEPORT to prevent https://github.com/grpc/grpc/issues/10755
server = new Server(new[] { new ChannelOption(ChannelOptions.SoReuseport, 0) })
{
Services = { TestService.BindService(new TestServiceImpl()) },
Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } }
};
server.Start();
int port = server.Ports.Single().BoundPort;
channel = new Channel(Host, port, ChannelCredentials.Insecure);
client = new TestService.TestServiceClient(channel);
}
[OneTimeTearDown]
public void Cleanup()
{
channel.ShutdownAsync().Wait();
server.ShutdownAsync().Wait();
}
[Test]
public async Task NoUnobservedTaskExceptionForAbandonedStreamingResponse()
{
// Verify that https://github.com/grpc/grpc/issues/17458 has been fixed.
// Create a streaming response call, then cancel it without reading all the responses
// and check that no unobserved task exceptions have been thrown.
var unobservedTaskExceptionCounter = new AtomicCounter();
TaskScheduler.UnobservedTaskException += (sender, e) => {
unobservedTaskExceptionCounter.Increment();
Console.WriteLine("Detected unobserved task exception: " + e.Exception);
};
var bodySizes = new List<int> { 10, 10, 10, 10, 10 };
var request = new StreamingOutputCallRequest {
ResponseParameters = { bodySizes.Select((size) => new ResponseParameters { Size = size }) }
};
for (int i = 0; i < 50; i++)
{
Console.WriteLine($"Starting iteration {i}");
using (var call = client.StreamingOutputCall(request))
{
// Intentionally only read the first response (we know there's more)
// The call will be cancelled as soon as we leave the "using" statement.
var firstResponse = await call.ResponseStream.MoveNext();
}
// Make it more likely to trigger the "Unobserved task exception" warning
GC.Collect();
}
Assert.AreEqual(0, unobservedTaskExceptionCounter.Count);
}
}
}

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26430.4
# Visual Studio Version 16
VisualStudioVersion = 16.0.29505.145
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Core.Api", "Grpc.Core.Api\Grpc.Core.Api.csproj", "{63FCEA50-1505-11E9-B56E-0800200C9A66}"
EndProject
@ -51,7 +51,7 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{63FCEA50-1505-11E9-B56E-0800200C9A66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{63FCEA50-1505-11E9-B56E-0800200C9A66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{63FCEA50-1505-11E9-B56E-0800200C9A66}.Debug|Any CPU.Build.0 = Debug|Any CPU
{63FCEA50-1505-11E9-B56E-0800200C9A66}.Release|Any CPU.ActiveCfg = Release|Any CPU
{63FCEA50-1505-11E9-B56E-0800200C9A66}.Release|Any CPU.Build.0 = Release|Any CPU
@ -139,4 +139,7 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BF5C0B7B-764F-4668-A052-A12BCCDA7304}
EndGlobalSection
EndGlobal

@ -1,7 +1,7 @@
<!-- This file is generated -->
<Project>
<PropertyGroup>
<GrpcCsharpVersion>2.26.0-dev</GrpcCsharpVersion>
<GrpcCsharpVersion>2.27.0-dev</GrpcCsharpVersion>
<GoogleProtobufVersion>3.8.0</GoogleProtobufVersion>
</PropertyGroup>
</Project>

@ -13,7 +13,7 @@
@rem limitations under the License.
@rem Current package versions
set VERSION=2.26.0-dev
set VERSION=2.27.0-dev
@rem Adjust the location of nuget.exe
set NUGET=C:\nuget\nuget.exe

@ -68,7 +68,8 @@
"Grpc.IntegrationTesting.InteropClientServerTest",
"Grpc.IntegrationTesting.MetadataCredentialsTest",
"Grpc.IntegrationTesting.RunnerClientServerTest",
"Grpc.IntegrationTesting.SslCredentialsTest"
"Grpc.IntegrationTesting.SslCredentialsTest",
"Grpc.IntegrationTesting.UnobservedTaskExceptionTest"
],
"Grpc.Reflection.Tests": [
"Grpc.Reflection.Tests.ReflectionClientServerTest",

@ -42,7 +42,7 @@ Pod::Spec.new do |s|
# exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed
# before them.
s.name = '!ProtoCompiler-gRPCCppPlugin'
v = '1.26.0-dev'
v = '1.27.0-dev'
s.version = v
s.summary = 'The gRPC ProtoC plugin generates C++ files from .proto services.'
s.description = <<-DESC

@ -42,7 +42,7 @@ Pod::Spec.new do |s|
# exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed
# before them.
s.name = '!ProtoCompiler-gRPCPlugin'
v = '1.26.0-dev'
v = '1.27.0-dev'
s.version = v
s.summary = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.'
s.description = <<-DESC

@ -22,4 +22,4 @@
// instead. This file can be regenerated from the template by running
// `tools/buildgen/generate_projects.sh`.
#define GRPC_OBJC_VERSION_STRING @"1.26.0-dev"
#define GRPC_OBJC_VERSION_STRING @"1.27.0-dev"

@ -22,5 +22,5 @@
// instead. This file can be regenerated from the template by running
// `tools/buildgen/generate_projects.sh`.
#define GRPC_OBJC_VERSION_STRING @"1.26.0-dev"
#define GRPC_OBJC_VERSION_STRING @"1.27.0-dev"
#define GRPC_C_VERSION_STRING @"9.0.0"

@ -2,7 +2,7 @@
"name": "grpc/grpc-dev",
"description": "gRPC library for PHP - for Development use only",
"license": "Apache-2.0",
"version": "1.26.0",
"version": "1.27.0",
"require": {
"php": ">=5.5.0",
"google/protobuf": "^v3.3.0"

@ -31,6 +31,8 @@ grpc_byte_buffer *string_to_byte_buffer(char *string, size_t length) {
return buffer;
}
#if PHP_MAJOR_VERSION < 7
void byte_buffer_to_string(grpc_byte_buffer *buffer, char **out_string,
size_t *out_length) {
grpc_byte_buffer_reader reader;
@ -50,3 +52,31 @@ void byte_buffer_to_string(grpc_byte_buffer *buffer, char **out_string,
*out_string = string;
*out_length = length;
}
#else
zend_string* byte_buffer_to_zend_string(grpc_byte_buffer *buffer) {
grpc_byte_buffer_reader reader;
if (buffer == NULL || !grpc_byte_buffer_reader_init(&reader, buffer)) {
/* TODO(dgq): distinguish between the error cases. */
return NULL;
}
const size_t length = grpc_byte_buffer_length(reader.buffer_out);
zend_string* zstr = zend_string_alloc(length, 0);
char* buf = ZSTR_VAL(zstr);
grpc_slice next;
while (grpc_byte_buffer_reader_next(&reader, &next) != 0) {
const size_t next_len = GRPC_SLICE_LENGTH(next);
memcpy(buf, GRPC_SLICE_START_PTR(next), next_len);
buf += next_len;
grpc_slice_unref(next);
}
*buf = '\0';
return zstr;
}
#endif // PHP_MAJOR_VERSION < 7

@ -23,7 +23,11 @@
grpc_byte_buffer *string_to_byte_buffer(char *string, size_t length);
#if PHP_MAJOR_VERSION < 7
void byte_buffer_to_string(grpc_byte_buffer *buffer, char **out_string,
size_t *out_length);
#else
zend_string* byte_buffer_to_zend_string(grpc_byte_buffer *buffer);
#endif // PHP_MAJOR_VERSION < 7
#endif /* NET_GRPC_PHP_GRPC_BYTE_BUFFER_H_ */

@ -294,8 +294,13 @@ PHP_METHOD(Call, startBatch) {
grpc_byte_buffer *message;
int cancelled;
grpc_call_error error;
#if PHP_MAJOR_VERSION < 7
char *message_str;
size_t message_len;
#else
zend_string* zmessage = NULL;
#endif // PHP_MAJOR_VERSION < 7
grpc_metadata_array_init(&metadata);
grpc_metadata_array_init(&trailing_metadata);
@ -483,12 +488,28 @@ PHP_METHOD(Call, startBatch) {
PHP_GRPC_DELREF(array);
break;
case GRPC_OP_RECV_MESSAGE:
#if PHP_MAJOR_VERSION < 7
byte_buffer_to_string(message, &message_str, &message_len);
#else
zmessage = byte_buffer_to_zend_string(message);
#endif // PHP_MAJOR_VERSION < 7
#if PHP_MAJOR_VERSION < 7
if (message_str == NULL) {
#else
if (zmessage == NULL) {
#endif // PHP_MAJOR_VERSION < 7
add_property_null(result, "message");
} else {
#if PHP_MAJOR_VERSION < 7
php_grpc_add_property_stringl(result, "message", message_str,
message_len, false);
#else
zval zmessage_val;
ZVAL_NEW_STR(&zmessage_val, zmessage);
add_property_zval(result, "message", &zmessage_val);
zval_ptr_dtor(&zmessage_val);
#endif // PHP_MAJOR_VERSION < 7
}
break;
case GRPC_OP_RECV_STATUS_ON_CLIENT:
@ -537,7 +558,9 @@ cleanup:
}
if (ops[i].op == GRPC_OP_RECV_MESSAGE) {
grpc_byte_buffer_destroy(message);
#if PHP_MAJOR_VERSION < 7
PHP_GRPC_FREE_STD_ZVAL(message_str);
#endif // PHP_MAJOR_VERSION < 7
}
}
RETURN_DESTROY_ZVAL(result);

@ -20,6 +20,6 @@
#ifndef VERSION_H
#define VERSION_H
#define PHP_GRPC_VERSION "1.26.0dev"
#define PHP_GRPC_VERSION "1.27.0dev"
#endif /* VERSION_H */

@ -14,4 +14,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc/_grpcio_metadata.py.template`!!!
__version__ = """1.26.0.dev0"""
__version__ = """1.27.0.dev0"""

@ -14,4 +14,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!!
VERSION = '1.26.0.dev0'
VERSION = '1.27.0.dev0'

@ -14,4 +14,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_channelz/grpc_version.py.template`!!!
VERSION = '1.26.0.dev0'
VERSION = '1.27.0.dev0'

@ -14,4 +14,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!!
VERSION = '1.26.0.dev0'
VERSION = '1.27.0.dev0'

@ -14,4 +14,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!!
VERSION = '1.26.0.dev0'
VERSION = '1.27.0.dev0'

@ -14,4 +14,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_status/grpc_version.py.template`!!!
VERSION = '1.26.0.dev0'
VERSION = '1.27.0.dev0'

@ -14,4 +14,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_testing/grpc_version.py.template`!!!
VERSION = '1.26.0.dev0'
VERSION = '1.27.0.dev0'

@ -14,4 +14,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!!
VERSION = '1.26.0.dev0'
VERSION = '1.27.0.dev0'

@ -14,5 +14,5 @@
# GRPC contains the General RPC module.
module GRPC
VERSION = '1.26.0.dev'
VERSION = '1.27.0.dev'
end

@ -14,6 +14,6 @@
module GRPC
module Tools
VERSION = '1.26.0.dev'
VERSION = '1.27.0.dev'
end
end

@ -104,15 +104,15 @@ TEST(StringViewTest, Cmp) {
grpc_core::StringView str1(kStr1);
grpc_core::StringView str2(kStr2);
grpc_core::StringView str3(kStr3);
EXPECT_EQ(grpc_core::StringViewCmp(str1, str1), 0);
EXPECT_LT(grpc_core::StringViewCmp(str1, str2), 0);
EXPECT_LT(grpc_core::StringViewCmp(str1, str3), 0);
EXPECT_EQ(grpc_core::StringViewCmp(str2, str2), 0);
EXPECT_GT(grpc_core::StringViewCmp(str2, str1), 0);
EXPECT_GT(grpc_core::StringViewCmp(str2, str3), 0);
EXPECT_EQ(grpc_core::StringViewCmp(str3, str3), 0);
EXPECT_GT(grpc_core::StringViewCmp(str3, str1), 0);
EXPECT_LT(grpc_core::StringViewCmp(str3, str2), 0);
EXPECT_EQ(str1.compare(str1), 0);
EXPECT_LT(str1.compare(str2), 0);
EXPECT_LT(str1.compare(str3), 0);
EXPECT_EQ(str2.compare(str2), 0);
EXPECT_GT(str2.compare(str1), 0);
EXPECT_GT(str2.compare(str3), 0);
EXPECT_EQ(str3.compare(str3), 0);
EXPECT_GT(str3.compare(str1), 0);
EXPECT_LT(str3.compare(str2), 0);
}
TEST(StringViewTest, RemovePrefix) {

@ -752,8 +752,8 @@ static void test_valid_sts_creds_options(void) {
grpc_core::StringView host;
grpc_core::StringView port;
GPR_ASSERT(grpc_core::SplitHostPort(sts_url->authority, &host, &port));
GPR_ASSERT(grpc_core::StringViewCmp(host, "foo.com") == 0);
GPR_ASSERT(grpc_core::StringViewCmp(port, "5555") == 0);
GPR_ASSERT(host == "foo.com");
GPR_ASSERT(port == "5555");
grpc_uri_destroy(sts_url);
}

@ -21,7 +21,6 @@
#include <fcntl.h>
#include <gmock/gmock.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>

@ -33,6 +33,7 @@
#include <grpcpp/impl/codegen/client_callback.h>
#include <grpcpp/impl/codegen/client_context.h>
#include <grpcpp/impl/codegen/completion_queue.h>
#include <grpcpp/impl/codegen/message_allocator.h>
#include <grpcpp/impl/codegen/method_handler.h>
#include <grpcpp/impl/codegen/proto_utils.h>
#include <grpcpp/impl/codegen/rpc_method.h>
@ -44,19 +45,6 @@
#include <grpcpp/impl/codegen/stub_options.h>
#include <grpcpp/impl/codegen/sync_stream.h>
namespace grpc_impl {
class CompletionQueue;
class ServerCompletionQueue;
class ServerContext;
} // namespace grpc_impl
namespace grpc {
namespace experimental {
template <typename RequestT, typename ResponseT>
class MessageAllocator;
} // namespace experimental
} // namespace grpc
namespace grpc {
namespace testing {

@ -43,6 +43,12 @@ namespace grpc {
namespace testing {
namespace {
#ifndef GRPC_CALLBACK_API_NONEXPERIMENTAL
using ::grpc::experimental::CallbackGenericService;
using ::grpc::experimental::GenericCallbackServerContext;
using ::grpc::experimental::ServerGenericBidiReactor;
#endif
void* tag(int i) { return (void*)static_cast<intptr_t>(i); }
bool VerifyReturnSuccess(CompletionQueue* cq, int i) {
@ -245,11 +251,10 @@ class HybridEnd2endTest : public ::testing::TestWithParam<bool> {
: false;
}
bool SetUpServer(
::grpc::Service* service1, ::grpc::Service* service2,
AsyncGenericService* generic_service,
experimental::CallbackGenericService* callback_generic_service,
int max_message_size = 0) {
bool SetUpServer(::grpc::Service* service1, ::grpc::Service* service2,
AsyncGenericService* generic_service,
CallbackGenericService* callback_generic_service,
int max_message_size = 0) {
int port = grpc_pick_unused_port_or_die();
server_address_ << "localhost:" << port;
@ -268,8 +273,12 @@ class HybridEnd2endTest : public ::testing::TestWithParam<bool> {
builder.RegisterAsyncGenericService(generic_service);
}
if (callback_generic_service) {
#ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
builder.RegisterCallbackGenericService(callback_generic_service);
#else
builder.experimental().RegisterCallbackGenericService(
callback_generic_service);
#endif
}
if (max_message_size != 0) {
@ -807,13 +816,13 @@ TEST_F(HybridEnd2endTest, GenericEcho) {
TEST_P(HybridEnd2endTest, CallbackGenericEcho) {
EchoTestService::WithGenericMethod_Echo<TestServiceImpl> service;
class GenericEchoService : public experimental::CallbackGenericService {
class GenericEchoService : public CallbackGenericService {
private:
experimental::ServerGenericBidiReactor* CreateReactor(
experimental::GenericCallbackServerContext* context) override {
ServerGenericBidiReactor* CreateReactor(
GenericCallbackServerContext* context) override {
EXPECT_EQ(context->method(), "/grpc.testing.EchoTestService/Echo");
class Reactor : public experimental::ServerGenericBidiReactor {
class Reactor : public ServerGenericBidiReactor {
public:
Reactor() { StartRead(&request_); }

@ -34,7 +34,6 @@
#include "test/cpp/util/subprocess.h"
#include <gtest/gtest.h>
#include <pthread.h>
#include <sys/time.h>
#include <thread>

@ -27,6 +27,8 @@ grpc_cc_test(
external_deps = [
"gtest",
"opencensus-stats-test",
"opencensus-tags",
"opencensus-with-tag-map",
],
language = "C++",
tags = ["no_windows"], # TODO(jtattermusch): fix test on windows

@ -27,7 +27,10 @@
#include "include/grpc++/grpc++.h"
#include "include/grpcpp/opencensus.h"
#include "opencensus/stats/stats.h"
#include "opencensus/stats/tag_key.h"
#include "opencensus/stats/testing/test_utils.h"
#include "opencensus/tags/tag_map.h"
#include "opencensus/tags/with_tag_map.h"
#include "src/cpp/ext/filters/census/grpc_plugin.h"
#include "src/proto/grpc/testing/echo.grpc.pb.h"
#include "test/core/util/test_config.h"
@ -41,6 +44,12 @@ using ::opencensus::stats::Distribution;
using ::opencensus::stats::View;
using ::opencensus::stats::ViewDescriptor;
using ::opencensus::stats::testing::TestUtils;
using ::opencensus::tags::TagKey;
using ::opencensus::tags::TagMap;
using ::opencensus::tags::WithTagMap;
static const auto TEST_TAG_KEY = TagKey::Register("my_key");
static const auto TEST_TAG_VALUE = "my_value";
class EchoServer final : public EchoTestService::Service {
::grpc::Status Echo(::grpc::ServerContext* context,
@ -104,7 +113,8 @@ TEST_F(StatsPluginEnd2EndTest, ErrorCount) {
.set_measure(kRpcClientRoundtripLatencyMeasureName)
.set_name("client_method")
.set_aggregation(Aggregation::Count())
.add_column(ClientMethodTagKey());
.add_column(ClientMethodTagKey())
.add_column(TEST_TAG_KEY);
View client_method_view(client_method_descriptor);
const auto server_method_descriptor =
ViewDescriptor()
@ -112,6 +122,7 @@ TEST_F(StatsPluginEnd2EndTest, ErrorCount) {
.set_name("server_method")
.set_aggregation(Aggregation::Count())
.add_column(ServerMethodTagKey());
//.add_column(TEST_TAG_KEY);
View server_method_view(server_method_descriptor);
const auto client_status_descriptor =
@ -119,7 +130,8 @@ TEST_F(StatsPluginEnd2EndTest, ErrorCount) {
.set_measure(kRpcClientRoundtripLatencyMeasureName)
.set_name("client_status")
.set_aggregation(Aggregation::Count())
.add_column(ClientStatusTagKey());
.add_column(ClientStatusTagKey())
.add_column(TEST_TAG_KEY);
View client_status_view(client_status_descriptor);
const auto server_status_descriptor =
ViewDescriptor()
@ -136,19 +148,56 @@ TEST_F(StatsPluginEnd2EndTest, ErrorCount) {
request.mutable_param()->mutable_expected_error()->set_code(i);
EchoResponse response;
::grpc::ClientContext context;
::grpc::Status status = stub_->Echo(&context, request, &response);
{
WithTagMap tags({{TEST_TAG_KEY, TEST_TAG_VALUE}});
::grpc::Status status = stub_->Echo(&context, request, &response);
}
}
absl::SleepFor(absl::Milliseconds(500));
TestUtils::Flush();
EXPECT_THAT(client_method_view.GetData().int_data(),
::testing::UnorderedElementsAre(::testing::Pair(
::testing::ElementsAre(client_method_name_), 17)));
// Client side views can be tagged with custom tags.
EXPECT_THAT(
client_method_view.GetData().int_data(),
::testing::UnorderedElementsAre(::testing::Pair(
::testing::ElementsAre(client_method_name_, TEST_TAG_VALUE), 17)));
// TODO: Implement server view tagging with custom tags.
EXPECT_THAT(server_method_view.GetData().int_data(),
::testing::UnorderedElementsAre(::testing::Pair(
::testing::ElementsAre(server_method_name_), 17)));
auto codes = {
// Client side views can be tagged with custom tags.
auto client_tags = {
::testing::Pair(::testing::ElementsAre("OK", TEST_TAG_VALUE), 1),
::testing::Pair(::testing::ElementsAre("CANCELLED", TEST_TAG_VALUE), 1),
::testing::Pair(::testing::ElementsAre("UNKNOWN", TEST_TAG_VALUE), 1),
::testing::Pair(
::testing::ElementsAre("INVALID_ARGUMENT", TEST_TAG_VALUE), 1),
::testing::Pair(
::testing::ElementsAre("DEADLINE_EXCEEDED", TEST_TAG_VALUE), 1),
::testing::Pair(::testing::ElementsAre("NOT_FOUND", TEST_TAG_VALUE), 1),
::testing::Pair(::testing::ElementsAre("ALREADY_EXISTS", TEST_TAG_VALUE),
1),
::testing::Pair(
::testing::ElementsAre("PERMISSION_DENIED", TEST_TAG_VALUE), 1),
::testing::Pair(::testing::ElementsAre("UNAUTHENTICATED", TEST_TAG_VALUE),
1),
::testing::Pair(
::testing::ElementsAre("RESOURCE_EXHAUSTED", TEST_TAG_VALUE), 1),
::testing::Pair(
::testing::ElementsAre("FAILED_PRECONDITION", TEST_TAG_VALUE), 1),
::testing::Pair(::testing::ElementsAre("ABORTED", TEST_TAG_VALUE), 1),
::testing::Pair(::testing::ElementsAre("OUT_OF_RANGE", TEST_TAG_VALUE),
1),
::testing::Pair(::testing::ElementsAre("UNIMPLEMENTED", TEST_TAG_VALUE),
1),
::testing::Pair(::testing::ElementsAre("INTERNAL", TEST_TAG_VALUE), 1),
::testing::Pair(::testing::ElementsAre("UNAVAILABLE", TEST_TAG_VALUE), 1),
::testing::Pair(::testing::ElementsAre("DATA_LOSS", TEST_TAG_VALUE), 1),
};
// TODO: Implement server view tagging with custom tags.
auto server_tags = {
::testing::Pair(::testing::ElementsAre("OK"), 1),
::testing::Pair(::testing::ElementsAre("CANCELLED"), 1),
::testing::Pair(::testing::ElementsAre("UNKNOWN"), 1),
@ -169,9 +218,9 @@ TEST_F(StatsPluginEnd2EndTest, ErrorCount) {
};
EXPECT_THAT(client_status_view.GetData().int_data(),
::testing::UnorderedElementsAreArray(codes));
::testing::UnorderedElementsAreArray(client_tags));
EXPECT_THAT(server_status_view.GetData().int_data(),
::testing::UnorderedElementsAreArray(codes));
::testing::UnorderedElementsAreArray(server_tags));
}
TEST_F(StatsPluginEnd2EndTest, RequestReceivedBytesPerRpc) {

@ -14,4 +14,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!!
VERSION = '1.26.0.dev0'
VERSION = '1.27.0.dev0'

@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++"
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = 1.26.0-dev
PROJECT_NUMBER = 1.27.0-dev
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a

@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++"
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = 1.26.0-dev
PROJECT_NUMBER = 1.27.0-dev
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a

@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC Objective-C"
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = 1.26.0-dev
PROJECT_NUMBER = 1.27.0-dev
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a

@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC Objective-C"
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = 1.26.0-dev
PROJECT_NUMBER = 1.27.0-dev
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a

@ -0,0 +1,94 @@
#!/usr/bin/env powershell
# Install Python 3.8 for x64 and x86 in order to build wheels on Windows.
Set-StrictMode -Version 2
# Avoid "Could not create SSL/TLS secure channel"
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
function Install-Python {
Param(
[string]$PythonVersion,
[string]$PythonInstaller,
[string]$PythonInstallPath,
[string]$PythonInstallerHash
)
$PythonInstallerUrl = "https://www.python.org/ftp/python/$PythonVersion/$PythonInstaller.exe"
$PythonInstallerPath = "C:\tools\$PythonInstaller.exe"
# Downloads installer
Write-Host "Downloading the Python installer: $PythonInstallerUrl => $PythonInstallerPath"
Invoke-WebRequest -Uri $PythonInstallerUrl -OutFile $PythonInstallerPath
# Validates checksum
$HashFromDownload = Get-FileHash -Path $PythonInstallerPath -Algorithm MD5
if ($HashFromDownload.Hash -ne $PythonInstallerHash) {
throw "Invalid Python installer: failed checksum!"
}
Write-Host "Python installer $PythonInstallerPath validated."
# Installs Python
& $PythonInstallerPath /quiet InstallAllUsers=1 PrependPath=1 Include_test=0 TargetDir=$PythonInstallPath
if (-Not $?) {
throw "The Python installation exited with error!"
}
# Validates Python binary
# NOTE(lidiz) Even if the install command finishes in the script, that
# doesn't mean the Python installation is finished. If using "ps" to check
# for running processes, you might see ongoing installers at this point.
# So, we needs this "hack" to reliably validate that the Python binary is
# functioning properly.
$ValidationStartTime = Get-Date
$EarlyExitDDL = $ValidationStartTime.addminutes(5)
$PythonBinary = "$PythonInstallPath\python.exe"
While ($True) {
$CurrentTime = Get-Date
if ($CurrentTime -ge $EarlyExitDDL) {
throw "Invalid Python installation! Timeout!"
}
& $PythonBinary -c 'print(42)'
if ($?) {
Write-Host "Python binary works properly."
break
}
Start-Sleep -Seconds 1
}
# Waits until the installer process is gone
$ValidationStartTime = Get-Date
$EarlyExitDDL = $ValidationStartTime.addminutes(5)
While ($True) {
$CurrentTime = Get-Date
if ($CurrentTime -ge $EarlyExitDDL) {
throw "Python installation process hangs!"
}
$InstallProcess = Get-Process -Name $PythonInstaller
if ($InstallProcess -eq $null) {
Write-Host "Installation process exits normally."
break
}
Start-Sleep -Seconds 1
}
# Installs pip
& $PythonBinary -m ensurepip --user
Write-Host "Python $PythonVersion installed by $PythonInstaller at $PythonInstallPath."
}
$Python38x86Config = @{
PythonVersion = "3.8.0"
PythonInstaller = "python-3.8.0"
PythonInstallPath = "C:\Python38_32bit"
PythonInstallerHash = "412a649d36626d33b8ca5593cf18318c"
}
Install-Python @Python38x86Config
$Python38x64Config = @{
PythonVersion = "3.8.0"
PythonInstaller = "python-3.8.0-amd64"
PythonInstallPath = "C:\Python38"
PythonInstallerHash = "29ea87f24c32f5e924b7d63f8a08ee8d"
}
Install-Python @Python38x64Config

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save