Merge branch 'master' into revert-18502-revert-18242-grpc_namespace_serverbuilder

pull/18510/head
Karthik Ravi Shankar 6 years ago
commit 29c0aacfc0
  1. 36
      BUILD
  2. 24
      bazel/grpc_build_system.bzl
  3. 121
      examples/BUILD
  4. 4
      examples/cpp/helloworld/greeter_async_client.cc
  5. 4
      examples/cpp/helloworld/greeter_async_client2.cc
  6. 4
      examples/cpp/helloworld/greeter_async_server.cc
  7. 31
      examples/cpp/route_guide/helper.cc
  8. 4
      examples/cpp/route_guide/route_guide_client.cc
  9. 4
      examples/cpp/route_guide/route_guide_server.cc
  10. 56
      examples/python/errors/BUILD.bazel
  11. 107
      examples/python/errors/README.md
  12. 56
      examples/python/errors/client.py
  13. 90
      examples/python/errors/server.py
  14. 54
      examples/python/errors/test/_error_handling_example_test.py
  15. 16
      include/grpcpp/impl/codegen/server_callback.h
  16. 230
      src/core/ext/filters/client_channel/client_channel.cc
  17. 7
      src/core/ext/filters/client_channel/lb_policy.cc
  18. 11
      src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
  19. 2
      src/core/lib/gprpp/fork.cc
  20. 27
      src/core/lib/iomgr/cfstream_handle.cc
  21. 10
      src/core/lib/iomgr/tcp_client_windows.cc
  22. 7
      src/cpp/client/channel_cc.cc
  23. 6
      src/csharp/Grpc.Core/Channel.cs
  24. 50
      src/php/ext/grpc/php_grpc.c
  25. 2
      src/php/ext/grpc/php_grpc.h
  26. 15
      src/php/ext/grpc/tests/grpc-default-ini.phpt
  27. 24
      src/php/ext/grpc/tests/grpc-set-ini.phpt
  28. 1
      src/python/grpcio_tests/tests/BUILD.bazel
  29. 1
      test/core/bad_connection/BUILD
  30. 1
      test/core/client_channel/BUILD
  31. 11
      test/core/end2end/generate_tests.bzl
  32. 10
      test/core/iomgr/BUILD
  33. 1
      test/cpp/common/BUILD
  34. 2
      test/cpp/end2end/BUILD
  35. 150
      test/cpp/end2end/cfstream_test.cc
  36. 1
      test/cpp/end2end/test_service_impl.cc
  37. 1
      test/cpp/interop/BUILD
  38. 18
      test/cpp/microbenchmarks/BUILD
  39. 5
      test/cpp/naming/generate_resolver_component_tests.bzl
  40. 1
      test/cpp/performance/BUILD
  41. 1
      test/cpp/qps/qps_benchmark_script.bzl
  42. 3
      test/cpp/server/BUILD
  43. 1
      test/cpp/server/load_reporter/BUILD
  44. 15
      test/cpp/util/proto_reflection_descriptor_database.cc
  45. 8
      tools/remote_build/README.md
  46. 3
      tools/remote_build/windows.bazelrc

36
BUILD

@ -362,10 +362,10 @@ grpc_cc_library(
"gpr", "gpr",
"grpc", "grpc",
"grpc++_base", "grpc++_base",
"grpc_cfstream",
"grpc++_codegen_base", "grpc++_codegen_base",
"grpc++_codegen_base_src", "grpc++_codegen_base_src",
"grpc++_codegen_proto", "grpc++_codegen_proto",
"grpc_cfstream",
], ],
) )
@ -2318,34 +2318,34 @@ grpc_cc_library(
name = "envoy_ads_upb", name = "envoy_ads_upb",
srcs = [ srcs = [
"src/core/ext/upb-generated/envoy/api/v2/auth/cert.upb.c", "src/core/ext/upb-generated/envoy/api/v2/auth/cert.upb.c",
"src/core/ext/upb-generated/envoy/api/v2/cds.upb.c",
"src/core/ext/upb-generated/envoy/api/v2/cluster/circuit_breaker.upb.c", "src/core/ext/upb-generated/envoy/api/v2/cluster/circuit_breaker.upb.c",
"src/core/ext/upb-generated/envoy/api/v2/cluster/outlier_detection.upb.c", "src/core/ext/upb-generated/envoy/api/v2/cluster/outlier_detection.upb.c",
"src/core/ext/upb-generated/envoy/api/v2/discovery.upb.c", "src/core/ext/upb-generated/envoy/api/v2/discovery.upb.c",
"src/core/ext/upb-generated/envoy/api/v2/endpoint/endpoint.upb.c",
"src/core/ext/upb-generated/envoy/api/v2/cds.upb.c",
"src/core/ext/upb-generated/envoy/api/v2/eds.upb.c", "src/core/ext/upb-generated/envoy/api/v2/eds.upb.c",
"src/core/ext/upb-generated/envoy/api/v2/endpoint/endpoint.upb.c",
"src/core/ext/upb-generated/envoy/service/discovery/v2/ads.upb.c", "src/core/ext/upb-generated/envoy/service/discovery/v2/ads.upb.c",
], ],
hdrs = [ hdrs = [
"src/core/ext/upb-generated/envoy/api/v2/auth/cert.upb.h", "src/core/ext/upb-generated/envoy/api/v2/auth/cert.upb.h",
"src/core/ext/upb-generated/envoy/api/v2/cds.upb.h",
"src/core/ext/upb-generated/envoy/api/v2/cluster/circuit_breaker.upb.h", "src/core/ext/upb-generated/envoy/api/v2/cluster/circuit_breaker.upb.h",
"src/core/ext/upb-generated/envoy/api/v2/cluster/outlier_detection.upb.h", "src/core/ext/upb-generated/envoy/api/v2/cluster/outlier_detection.upb.h",
"src/core/ext/upb-generated/envoy/api/v2/discovery.upb.h", "src/core/ext/upb-generated/envoy/api/v2/discovery.upb.h",
"src/core/ext/upb-generated/envoy/api/v2/endpoint/endpoint.upb.h",
"src/core/ext/upb-generated/envoy/api/v2/cds.upb.h",
"src/core/ext/upb-generated/envoy/api/v2/eds.upb.h", "src/core/ext/upb-generated/envoy/api/v2/eds.upb.h",
"src/core/ext/upb-generated/envoy/api/v2/endpoint/endpoint.upb.h",
"src/core/ext/upb-generated/envoy/service/discovery/v2/ads.upb.h", "src/core/ext/upb-generated/envoy/service/discovery/v2/ads.upb.h",
], ],
language = "c++",
external_deps = [ external_deps = [
"upb_lib", "upb_lib",
], ],
language = "c++",
deps = [ deps = [
":envoy_core_upb", ":envoy_core_upb",
":envoy_type_upb", ":envoy_type_upb",
":google_api_upb", ":google_api_upb",
":proto_gen_validate_upb", ":proto_gen_validate_upb",
] ],
) )
grpc_cc_library( grpc_cc_library(
@ -2366,15 +2366,16 @@ grpc_cc_library(
"src/core/ext/upb-generated/envoy/api/v2/core/health_check.upb.h", "src/core/ext/upb-generated/envoy/api/v2/core/health_check.upb.h",
"src/core/ext/upb-generated/envoy/api/v2/core/protocol.upb.h", "src/core/ext/upb-generated/envoy/api/v2/core/protocol.upb.h",
], ],
language = "c++",
external_deps = [ external_deps = [
"upb_lib", "upb_lib",
], ],
language = "c++",
tags = ["no_windows"],
deps = [ deps = [
":envoy_type_upb", ":envoy_type_upb",
":google_api_upb", ":google_api_upb",
":proto_gen_validate_upb" ":proto_gen_validate_upb",
] ],
) )
grpc_cc_library( grpc_cc_library(
@ -2387,14 +2388,15 @@ grpc_cc_library(
"src/core/ext/upb-generated/envoy/type/percent.upb.h", "src/core/ext/upb-generated/envoy/type/percent.upb.h",
"src/core/ext/upb-generated/envoy/type/range.upb.h", "src/core/ext/upb-generated/envoy/type/range.upb.h",
], ],
language = "c++",
external_deps = [ external_deps = [
"upb_lib", "upb_lib",
], ],
language = "c++",
tags = ["no_windows"],
deps = [ deps = [
":google_api_upb", ":google_api_upb",
":proto_gen_validate_upb" ":proto_gen_validate_upb",
] ],
) )
grpc_cc_library( grpc_cc_library(
@ -2407,13 +2409,14 @@ grpc_cc_library(
"src/core/ext/upb-generated/gogoproto/gogo.upb.h", "src/core/ext/upb-generated/gogoproto/gogo.upb.h",
"src/core/ext/upb-generated/validate/validate.upb.h", "src/core/ext/upb-generated/validate/validate.upb.h",
], ],
language = "c++",
external_deps = [ external_deps = [
"upb_lib", "upb_lib",
], ],
language = "c++",
tags = ["no_windows"],
deps = [ deps = [
":google_api_upb", ":google_api_upb",
] ],
) )
grpc_cc_library( grpc_cc_library(
@ -2442,10 +2445,11 @@ grpc_cc_library(
"src/core/ext/upb-generated/google/protobuf/wrappers.upb.h", "src/core/ext/upb-generated/google/protobuf/wrappers.upb.h",
"src/core/ext/upb-generated/google/rpc/status.upb.h", "src/core/ext/upb-generated/google/rpc/status.upb.h",
], ],
language = "c++",
external_deps = [ external_deps = [
"upb_lib", "upb_lib",
], ],
language = "c++",
tags = ["no_windows"],
) )
grpc_generate_one_off_targets() grpc_generate_one_off_targets()

@ -80,7 +80,8 @@ def grpc_cc_library(
visibility = None, visibility = None,
alwayslink = 0, alwayslink = 0,
data = [], data = [],
use_cfstream = False): use_cfstream = False,
tags = []):
copts = [] copts = []
if use_cfstream: if use_cfstream:
copts = if_mac(["-DGRPC_CFSTREAM"]) copts = if_mac(["-DGRPC_CFSTREAM"])
@ -117,6 +118,7 @@ def grpc_cc_library(
], ],
alwayslink = alwayslink, alwayslink = alwayslink,
data = data, data = data,
tags = tags,
) )
def grpc_proto_plugin(name, srcs = [], deps = []): def grpc_proto_plugin(name, srcs = [], deps = []):
@ -149,7 +151,6 @@ def grpc_cc_test(name, srcs = [], deps = [], external_deps = [], args = [], data
if language.upper() == "C": if language.upper() == "C":
copts = copts + if_not_windows(["-std=c99"]) copts = copts + if_not_windows(["-std=c99"])
args = { args = {
"name": name,
"srcs": srcs, "srcs": srcs,
"args": args, "args": args,
"data": data, "data": data,
@ -161,7 +162,17 @@ def grpc_cc_test(name, srcs = [], deps = [], external_deps = [], args = [], data
"exec_compatible_with": exec_compatible_with, "exec_compatible_with": exec_compatible_with,
} }
if uses_polling: if uses_polling:
native.cc_test(testonly = True, tags = ["manual"], **args) # Only run targets with pollers for non-MSVC
# TODO(yfen): Enable MSVC for poller-enabled targets without pollers
native.cc_test(
name = name,
testonly = True,
tags = [
"manual",
"no_windows",
],
**args
)
for poller in POLLERS: for poller in POLLERS:
native.sh_test( native.sh_test(
name = name + "@poller=" + poller, name = name + "@poller=" + poller,
@ -175,13 +186,13 @@ def grpc_cc_test(name, srcs = [], deps = [], external_deps = [], args = [], data
poller, poller,
"$(location %s)" % name, "$(location %s)" % name,
] + args["args"], ] + args["args"],
tags = tags, tags = (tags + ["no_windows"]),
exec_compatible_with = exec_compatible_with, exec_compatible_with = exec_compatible_with,
) )
else: else:
native.cc_test(**args) native.cc_test(tags = tags, **args)
def grpc_cc_binary(name, srcs = [], deps = [], external_deps = [], args = [], data = [], language = "C++", testonly = False, linkshared = False, linkopts = []): def grpc_cc_binary(name, srcs = [], deps = [], external_deps = [], args = [], data = [], language = "C++", testonly = False, linkshared = False, linkopts = [], tags = []):
copts = [] copts = []
if language.upper() == "C": if language.upper() == "C":
copts = ["-std=c99"] copts = ["-std=c99"]
@ -195,6 +206,7 @@ def grpc_cc_binary(name, srcs = [], deps = [], external_deps = [], args = [], da
deps = deps + _get_external_deps(external_deps), deps = deps + _get_external_deps(external_deps),
copts = copts, copts = copts,
linkopts = if_not_windows(["-pthread"]) + linkopts, linkopts = if_not_windows(["-pthread"]) + linkopts,
tags = tags,
) )
def grpc_generate_one_off_targets(): def grpc_generate_one_off_targets():

@ -16,7 +16,9 @@ licenses(["notice"]) # 3-clause BSD
package(default_visibility = ["//visibility:public"]) package(default_visibility = ["//visibility:public"])
load("@grpc_python_dependencies//:requirements.bzl", "requirement")
load("//bazel:grpc_build_system.bzl", "grpc_proto_library") load("//bazel:grpc_build_system.bzl", "grpc_proto_library")
load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_library")
grpc_proto_library( grpc_proto_library(
name = "auth_sample", name = "auth_sample",
@ -43,60 +45,121 @@ grpc_proto_library(
srcs = ["protos/keyvaluestore.proto"], srcs = ["protos/keyvaluestore.proto"],
) )
py_proto_library(
name = "py_helloworld",
protos = ["protos/helloworld.proto"],
with_grpc = True,
deps = [requirement('protobuf'),],
)
cc_binary( cc_binary(
name = "greeter_client", name = "greeter_client",
srcs = ["cpp/helloworld/greeter_client.cc"], srcs = ["cpp/helloworld/greeter_client.cc"],
defines = ["BAZEL_BUILD"], defines = ["BAZEL_BUILD"],
deps = [":helloworld", "//:grpc++"], deps = [
":helloworld",
"//:grpc++",
],
)
cc_binary(
name = "greeter_async_client",
srcs = ["cpp/helloworld/greeter_async_client.cc"],
defines = ["BAZEL_BUILD"],
deps = [
":helloworld",
"//:grpc++",
],
)
cc_binary(
name = "greeter_async_client2",
srcs = ["cpp/helloworld/greeter_async_client2.cc"],
defines = ["BAZEL_BUILD"],
deps = [
":helloworld",
"//:grpc++",
],
) )
cc_binary( cc_binary(
name = "greeter_server", name = "greeter_server",
srcs = ["cpp/helloworld/greeter_server.cc"], srcs = ["cpp/helloworld/greeter_server.cc"],
defines = ["BAZEL_BUILD"], defines = ["BAZEL_BUILD"],
deps = [":helloworld", "//:grpc++"], deps = [
":helloworld",
"//:grpc++",
],
)
cc_binary(
name = "greeter_async_server",
srcs = ["cpp/helloworld/greeter_async_server.cc"],
defines = ["BAZEL_BUILD"],
deps = [
":helloworld",
"//:grpc++",
],
) )
cc_binary( cc_binary(
name = "metadata_client", name = "metadata_client",
srcs = ["cpp/metadata/greeter_client.cc"], srcs = ["cpp/metadata/greeter_client.cc"],
defines = ["BAZEL_BUILD"], defines = ["BAZEL_BUILD"],
deps = [":helloworld", "//:grpc++"], deps = [
":helloworld",
"//:grpc++",
],
) )
cc_binary( cc_binary(
name = "metadata_server", name = "metadata_server",
srcs = ["cpp/metadata/greeter_server.cc"], srcs = ["cpp/metadata/greeter_server.cc"],
defines = ["BAZEL_BUILD"], defines = ["BAZEL_BUILD"],
deps = [":helloworld", "//:grpc++"], deps = [
":helloworld",
"//:grpc++",
],
) )
cc_binary( cc_binary(
name = "lb_client", name = "lb_client",
srcs = ["cpp/load_balancing/greeter_client.cc"], srcs = ["cpp/load_balancing/greeter_client.cc"],
defines = ["BAZEL_BUILD"], defines = ["BAZEL_BUILD"],
deps = [":helloworld", "//:grpc++"], deps = [
":helloworld",
"//:grpc++",
],
) )
cc_binary( cc_binary(
name = "lb_server", name = "lb_server",
srcs = ["cpp/load_balancing/greeter_server.cc"], srcs = ["cpp/load_balancing/greeter_server.cc"],
defines = ["BAZEL_BUILD"], defines = ["BAZEL_BUILD"],
deps = [":helloworld", "//:grpc++"], deps = [
":helloworld",
"//:grpc++",
],
) )
cc_binary( cc_binary(
name = "compression_client", name = "compression_client",
srcs = ["cpp/compression/greeter_client.cc"], srcs = ["cpp/compression/greeter_client.cc"],
defines = ["BAZEL_BUILD"], defines = ["BAZEL_BUILD"],
deps = [":helloworld", "//:grpc++"], deps = [
":helloworld",
"//:grpc++",
],
) )
cc_binary( cc_binary(
name = "compression_server", name = "compression_server",
srcs = ["cpp/compression/greeter_server.cc"], srcs = ["cpp/compression/greeter_server.cc"],
defines = ["BAZEL_BUILD"], defines = ["BAZEL_BUILD"],
deps = [":helloworld", "//:grpc++"], deps = [
":helloworld",
"//:grpc++",
],
) )
cc_binary( cc_binary(
@ -104,12 +167,48 @@ cc_binary(
srcs = ["cpp/keyvaluestore/caching_interceptor.h", srcs = ["cpp/keyvaluestore/caching_interceptor.h",
"cpp/keyvaluestore/client.cc"], "cpp/keyvaluestore/client.cc"],
defines = ["BAZEL_BUILD"], defines = ["BAZEL_BUILD"],
deps = [":keyvaluestore", "//:grpc++"], deps = [
":keyvaluestore",
"//:grpc++",
],
) )
cc_binary( cc_binary(
name = "keyvaluestore_server", name = "keyvaluestore_server",
srcs = ["cpp/keyvaluestore/server.cc"], srcs = ["cpp/keyvaluestore/server.cc"],
defines = ["BAZEL_BUILD"], defines = ["BAZEL_BUILD"],
deps = [":keyvaluestore", "//:grpc++"], deps = [
) ":keyvaluestore",
"//:grpc++",
],
)
cc_binary(
name = "route_guide_client",
srcs = [
"cpp/route_guide/helper.cc",
"cpp/route_guide/helper.h",
"cpp/route_guide/route_guide_client.cc",
],
data = ["cpp/route_guide/route_guide_db.json"],
defines = ["BAZEL_BUILD"],
deps = [
":route_guide",
"//:grpc++",
],
)
cc_binary(
name = "route_guide_server",
srcs = [
"cpp/route_guide/helper.cc",
"cpp/route_guide/helper.h",
"cpp/route_guide/route_guide_server.cc",
],
data = ["cpp/route_guide/route_guide_db.json"],
defines = ["BAZEL_BUILD"],
deps = [
":route_guide",
"//:grpc++",
],
)

@ -23,7 +23,11 @@
#include <grpcpp/grpcpp.h> #include <grpcpp/grpcpp.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#ifdef BAZEL_BUILD
#include "examples/protos/helloworld.grpc.pb.h"
#else
#include "helloworld.grpc.pb.h" #include "helloworld.grpc.pb.h"
#endif
using grpc::Channel; using grpc::Channel;
using grpc::ClientAsyncResponseReader; using grpc::ClientAsyncResponseReader;

@ -24,7 +24,11 @@
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <thread> #include <thread>
#ifdef BAZEL_BUILD
#include "examples/protos/helloworld.grpc.pb.h"
#else
#include "helloworld.grpc.pb.h" #include "helloworld.grpc.pb.h"
#endif
using grpc::Channel; using grpc::Channel;
using grpc::ClientAsyncResponseReader; using grpc::ClientAsyncResponseReader;

@ -24,7 +24,11 @@
#include <grpcpp/grpcpp.h> #include <grpcpp/grpcpp.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#ifdef BAZEL_BUILD
#include "examples/protos/helloworld.grpc.pb.h"
#else
#include "helloworld.grpc.pb.h" #include "helloworld.grpc.pb.h"
#endif
using grpc::Server; using grpc::Server;
using grpc::ServerAsyncResponseWriter; using grpc::ServerAsyncResponseWriter;

@ -23,7 +23,11 @@
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <vector> #include <vector>
#ifdef BAZEL_BUILD
#include "examples/protos/route_guide.grpc.pb.h"
#else
#include "route_guide.grpc.pb.h" #include "route_guide.grpc.pb.h"
#endif
namespace routeguide { namespace routeguide {
@ -35,13 +39,16 @@ std::string GetDbFileContent(int argc, char** argv) {
size_t start_position = argv_1.find(arg_str); size_t start_position = argv_1.find(arg_str);
if (start_position != std::string::npos) { if (start_position != std::string::npos) {
start_position += arg_str.size(); start_position += arg_str.size();
if (argv_1[start_position] == ' ' || if (argv_1[start_position] == ' ' || argv_1[start_position] == '=') {
argv_1[start_position] == '=') {
db_path = argv_1.substr(start_position + 1); db_path = argv_1.substr(start_position + 1);
} }
} }
} else { } else {
#ifdef BAZEL_BUILD
db_path = "cpp/route_guide/route_guide_db.json";
#else
db_path = "route_guide_db.json"; db_path = "route_guide_db.json";
#endif
} }
std::ifstream db_file(db_path); std::ifstream db_file(db_path);
if (!db_file.is_open()) { if (!db_file.is_open()) {
@ -60,17 +67,13 @@ class Parser {
public: public:
explicit Parser(const std::string& db) : db_(db) { explicit Parser(const std::string& db) : db_(db) {
// Remove all spaces. // Remove all spaces.
db_.erase( db_.erase(std::remove_if(db_.begin(), db_.end(), isspace), db_.end());
std::remove_if(db_.begin(), db_.end(), isspace),
db_.end());
if (!Match("[")) { if (!Match("[")) {
SetFailedAndReturnFalse(); SetFailedAndReturnFalse();
} }
} }
bool Finished() { bool Finished() { return current_ >= db_.size(); }
return current_ >= db_.size();
}
bool TryParseOne(Feature* feature) { bool TryParseOne(Feature* feature) {
if (failed_ || Finished() || !Match("{")) { if (failed_ || Finished() || !Match("{")) {
@ -96,7 +99,7 @@ class Parser {
if (current_ == db_.size()) { if (current_ == db_.size()) {
return SetFailedAndReturnFalse(); return SetFailedAndReturnFalse();
} }
feature->set_name(db_.substr(name_start, current_-name_start-1)); feature->set_name(db_.substr(name_start, current_ - name_start - 1));
if (!Match("},")) { if (!Match("},")) {
if (db_[current_ - 1] == ']' && current_ == db_.size()) { if (db_[current_ - 1] == ']' && current_ == db_.size()) {
return true; return true;
@ -107,7 +110,6 @@ class Parser {
} }
private: private:
bool SetFailedAndReturnFalse() { bool SetFailedAndReturnFalse() {
failed_ = true; failed_ = true;
return false; return false;
@ -121,7 +123,8 @@ class Parser {
void ReadLong(long* l) { void ReadLong(long* l) {
size_t start = current_; size_t start = current_;
while (current_ != db_.size() && db_[current_] != ',' && db_[current_] != '}') { while (current_ != db_.size() && db_[current_] != ',' &&
db_[current_] != '}') {
current_++; current_++;
} }
// It will throw an exception if fails. // It will throw an exception if fails.
@ -154,10 +157,8 @@ void ParseDb(const std::string& db, std::vector<Feature>* feature_list) {
break; break;
} }
} }
std::cout << "DB parsed, loaded " << feature_list->size() std::cout << "DB parsed, loaded " << feature_list->size() << " features."
<< " features." << std::endl; << std::endl;
} }
} // namespace routeguide } // namespace routeguide

@ -29,7 +29,11 @@
#include <grpcpp/create_channel.h> #include <grpcpp/create_channel.h>
#include <grpcpp/security/credentials.h> #include <grpcpp/security/credentials.h>
#include "helper.h" #include "helper.h"
#ifdef BAZEL_BUILD
#include "examples/protos/route_guide.grpc.pb.h"
#else
#include "route_guide.grpc.pb.h" #include "route_guide.grpc.pb.h"
#endif
using grpc::Channel; using grpc::Channel;
using grpc::ClientContext; using grpc::ClientContext;

@ -29,7 +29,11 @@
#include <grpcpp/server_context.h> #include <grpcpp/server_context.h>
#include <grpcpp/security/server_credentials.h> #include <grpcpp/security/server_credentials.h>
#include "helper.h" #include "helper.h"
#ifdef BAZEL_BUILD
#include "examples/protos/route_guide.grpc.pb.h"
#else
#include "route_guide.grpc.pb.h" #include "route_guide.grpc.pb.h"
#endif
using grpc::Server; using grpc::Server;
using grpc::ServerBuilder; using grpc::ServerBuilder;

@ -0,0 +1,56 @@
# 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.
load("@grpc_python_dependencies//:requirements.bzl", "requirement")
py_library(
name = "client",
testonly = 1,
srcs = ["client.py"],
deps = [
"//src/python/grpcio/grpc:grpcio",
"//src/python/grpcio_status/grpc_status:grpc_status",
"//examples:py_helloworld",
requirement('googleapis-common-protos'),
],
)
py_library(
name = "server",
testonly = 1,
srcs = ["server.py"],
deps = [
"//src/python/grpcio/grpc:grpcio",
"//src/python/grpcio_status/grpc_status:grpc_status",
"//examples:py_helloworld",
] + select({
"//conditions:default": [requirement("futures")],
"//:python3": [],
}),
)
py_test(
name = "test/_error_handling_example_test",
srcs = ["test/_error_handling_example_test.py"],
deps = [
":client",
":server",
"//src/python/grpcio_tests/tests:bazel_namespace_package_hack",
],
size = "small",
imports = [
"../../../src/python/grpcio_status",
"../../../src/python/grpcio_tests",
],
)

@ -0,0 +1,107 @@
# gRPC Python Error Handling Example
The goal of this example is sending error status from server that is more complicated than a code and detail string.
The definition for an RPC method in proto files contains request message and response message. There are many error states that can be shared across RPC methods (e.g. stack trace, insufficient quota). Using a different path to handle error will make the code more maintainable.
Ideally, the final status of an RPC should be described in the trailing headers of HTTP2, and gRPC Python provides helper functions in `grpcio-status` package to assist the packing and unpacking of error status.
### Requirement
```
grpcio>=1.18.0
grpcio-status>=1.18.0
googleapis-common-protos>=1.5.5
```
### Error Detail Proto
You may provide any custom proto message as error detail in your implementation. Here are protos are defined by Google Cloud Library Team:
* [code.proto]([https://github.com/googleapis/api-common-protos/blob/master/google/rpc/code.proto](https://github.com/googleapis/api-common-protos/blob/87185dfffad4afa5a33a8c153f0e1ea53b4f85dc/google/rpc/code.proto)) contains definition of RPC error codes.
* [error_details.proto]([https://github.com/googleapis/api-common-protos/blob/master/google/rpc/error_details.proto](https://github.com/googleapis/api-common-protos/blob/87185dfffad4afa5a33a8c153f0e1ea53b4f85dc/google/rpc/error_details.proto)) contains definitions of common error details.
### Definition of Status Proto
Here is the definition of Status proto. For full text, please see [status.proto](https://github.com/googleapis/api-common-protos/blob/87185dfffad4afa5a33a8c153f0e1ea53b4f85dc/google/rpc/status.proto).
```proto
// The `Status` type defines a logical error model that is suitable for different
// programming environments, including REST APIs and RPC APIs. It is used by
// [gRPC](https://github.com/grpc). The error model is designed to be:
//
// - Simple to use and understand for most users
// - Flexible enough to meet unexpected needs
//
// # Overview
//
// The `Status` message contains three pieces of data: error code, error message,
// and error details. The error code should be an enum value of
// [google.rpc.Code][google.rpc.Code], but it may accept additional error codes if needed. The
// error message should be a developer-facing English message that helps
// developers *understand* and *resolve* the error. If a localized user-facing
// error message is needed, put the localized message in the error details or
// localize it in the client. The optional error details may contain arbitrary
// information about the error. There is a predefined set of error detail types
// in the package `google.rpc` that can be used for common error conditions.
//
// # Language mapping
//
// The `Status` message is the logical representation of the error model, but it
// is not necessarily the actual wire format. When the `Status` message is
// exposed in different client libraries and different wire protocols, it can be
// mapped differently. For example, it will likely be mapped to some exceptions
// in Java, but more likely mapped to some error codes in C.
//
// # Other uses
//
// The error model and the `Status` message can be used in a variety of
// environments, either with or without APIs, to provide a
// consistent developer experience across different environments.
//
// Example uses of this error model include:
//
// - Partial errors. If a service needs to return partial errors to the client,
// it may embed the `Status` in the normal response to indicate the partial
// errors.
//
// - Workflow errors. A typical workflow has multiple steps. Each step may
// have a `Status` message for error reporting.
//
// - Batch operations. If a client uses batch request and batch response, the
// `Status` message should be used directly inside batch response, one for
// each error sub-response.
//
// - Asynchronous operations. If an API call embeds asynchronous operation
// results in its response, the status of those operations should be
// represented directly using the `Status` message.
//
// - Logging. If some API errors are stored in logs, the message `Status` could
// be used directly after any stripping needed for security/privacy reasons.
message Status {
// The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code].
int32 code = 1;
// A developer-facing error message, which should be in English. Any
// user-facing error message should be localized and sent in the
// [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client.
string message = 2;
// A list of messages that carry the error details. There is a common set of
// message types for APIs to use.
repeated google.protobuf.Any details = 3;
}
```
### Usage of Well-Known-Proto `Any`
Please check [ProtoBuf Document: Any](https://developers.google.com/protocol-buffers/docs/reference/python-generated#any)
```Python
any_message.Pack(message)
any_message.Unpack(message)
assert any_message.Is(message.DESCRIPTOR)
```

@ -0,0 +1,56 @@
# 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.
"""This example handles rich error status in client-side."""
from __future__ import print_function
import logging
import grpc
from grpc_status import rpc_status
from google.rpc import error_details_pb2
from examples.protos import helloworld_pb2
from examples.protos import helloworld_pb2_grpc
_LOGGER = logging.getLogger(__name__)
def process(stub):
try:
response = stub.SayHello(helloworld_pb2.HelloRequest(name='Alice'))
_LOGGER.info('Call success: %s', response.message)
except grpc.RpcError as rpc_error:
_LOGGER.error('Call failure: %s', rpc_error)
status = rpc_status.from_call(rpc_error)
for detail in status.details:
if detail.Is(error_details_pb2.QuotaFailure.DESCRIPTOR):
info = error_details_pb2.QuotaFailure()
detail.Unpack(info)
_LOGGER.error('Quota failure: %s', info)
else:
raise RuntimeError('Unexpected failure: %s' % detail)
def main():
# NOTE(gRPC Python Team): .close() is possible on a channel and should be
# used in circumstances in which the with statement does not fit the needs
# of the code.
with grpc.insecure_channel('localhost:50051') as channel:
stub = helloworld_pb2_grpc.GreeterStub(channel)
process(stub)
if __name__ == '__main__':
logging.basicConfig()
main()

@ -0,0 +1,90 @@
# 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.
"""This example sends out rich error status from server-side."""
from concurrent import futures
import time
import logging
import threading
import grpc
from grpc_status import rpc_status
from google.protobuf import any_pb2
from google.rpc import code_pb2, status_pb2, error_details_pb2
from examples.protos import helloworld_pb2
from examples.protos import helloworld_pb2_grpc
_ONE_DAY_IN_SECONDS = 60 * 60 * 24
def create_greet_limit_exceed_error_status(name):
detail = any_pb2.Any()
detail.Pack(
error_details_pb2.QuotaFailure(
violations=[
error_details_pb2.QuotaFailure.Violation(
subject="name: %s" % name,
description="Limit one greeting per person",
)
],))
return status_pb2.Status(
code=code_pb2.RESOURCE_EXHAUSTED,
message='Request limit exceeded.',
details=[detail],
)
class LimitedGreeter(helloworld_pb2_grpc.GreeterServicer):
def __init__(self):
self._lock = threading.RLock()
self._greeted = set()
def SayHello(self, request, context):
with self._lock:
if request.name in self._greeted:
rich_status = create_greet_limit_exceed_error_status(
request.name)
context.abort_with_status(rpc_status.to_status(rich_status))
else:
self._greeted.add(request.name)
return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name)
def create_server(server_address):
server = grpc.server(futures.ThreadPoolExecutor())
helloworld_pb2_grpc.add_GreeterServicer_to_server(LimitedGreeter(), server)
port = server.add_insecure_port(server_address)
return server, port
def serve(server):
server.start()
try:
while True:
time.sleep(_ONE_DAY_IN_SECONDS)
except KeyboardInterrupt:
server.stop(None)
def main():
server, unused_port = create_server('[::]:50051')
serve(server)
if __name__ == '__main__':
logging.basicConfig()
main()

@ -0,0 +1,54 @@
# 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.
"""Tests of the error handling example."""
# NOTE(lidiz) This module only exists in Bazel BUILD file, for more details
# please refer to comments in the "bazel_namespace_package_hack" module.
try:
from tests import bazel_namespace_package_hack
bazel_namespace_package_hack.sys_path_to_site_dir_hack()
except ImportError:
pass
import unittest
import logging
import grpc
from examples.protos import helloworld_pb2_grpc
from examples.python.errors import client as error_handling_client
from examples.python.errors import server as error_handling_server
class ErrorHandlingExampleTest(unittest.TestCase):
def setUp(self):
self._server, port = error_handling_server.create_server('[::]:0')
self._server.start()
self._channel = grpc.insecure_channel('localhost:%d' % port)
def tearDown(self):
self._channel.close()
self._server.stop(None)
def test_error_handling_example(self):
stub = helloworld_pb2_grpc.GreeterStub(self._channel)
error_handling_client.process(stub)
error_handling_client.process(stub)
# No unhandled exception raised, test passed!
if __name__ == '__main__':
logging.basicConfig()
unittest.main(verbosity=2)

@ -169,9 +169,13 @@ class ServerCallbackReaderWriter {
// The following classes are the reactor interfaces that are to be implemented // The following classes are the reactor interfaces that are to be implemented
// by the user, returned as the result of the method handler for a callback // by the user, returned as the result of the method handler for a callback
// method, and activated by the call to OnStarted. Note that none of the classes // method, and activated by the call to OnStarted. The library guarantees that
// are pure; all reactions have a default empty reaction so that the user class // OnStarted will be called for any reactor that has been created using a
// only needs to override those classes that it cares about. // method handler registered on a service. No operation initiation method may be
// called until after the call to OnStarted.
// Note that none of the classes are pure; all reactions have a default empty
// reaction so that the user class only needs to override those classes that it
// cares about.
/// \a ServerBidiReactor is the interface for a bidirectional streaming RPC. /// \a ServerBidiReactor is the interface for a bidirectional streaming RPC.
template <class Request, class Response> template <class Request, class Response>
@ -179,6 +183,9 @@ class ServerBidiReactor : public internal::ServerReactor {
public: public:
~ServerBidiReactor() = default; ~ServerBidiReactor() = default;
/// Do NOT call any operation initiation method (names that start with Start)
/// until after the library has called OnStarted on this object.
/// Send any initial metadata stored in the RPC context. If not invoked, /// Send any initial metadata stored in the RPC context. If not invoked,
/// any initial metadata will be passed along with the first Write or the /// any initial metadata will be passed along with the first Write or the
/// Finish (if there are no writes). /// Finish (if there are no writes).
@ -245,7 +252,8 @@ class ServerBidiReactor : public internal::ServerReactor {
/// \param[in] s The status outcome of this RPC /// \param[in] s The status outcome of this RPC
void Finish(Status s) { stream_->Finish(std::move(s)); } void Finish(Status s) { stream_->Finish(std::move(s)); }
/// Notify the application that a streaming RPC has started /// Notify the application that a streaming RPC has started and that it is now
/// ok to call any operation initation method.
/// ///
/// \param[in] context The context object now associated with this RPC /// \param[in] context The context object now associated with this RPC
virtual void OnStarted(ServerContext* context) {} virtual void OnStarted(ServerContext* context) {}

@ -100,49 +100,52 @@ struct QueuedPick {
}; };
typedef struct client_channel_channel_data { typedef struct client_channel_channel_data {
//
// Fields set at construction and never modified.
//
bool deadline_checking_enabled; bool deadline_checking_enabled;
bool enable_retries; bool enable_retries;
size_t per_rpc_retry_buffer_size; size_t per_rpc_retry_buffer_size;
/** combiner protecting all variables below in this data structure */
grpc_combiner* combiner;
/** owning stack */
grpc_channel_stack* owning_stack; grpc_channel_stack* owning_stack;
/** interested parties (owned) */
grpc_pollset_set* interested_parties;
// Client channel factory.
grpc_core::ClientChannelFactory* client_channel_factory; grpc_core::ClientChannelFactory* client_channel_factory;
// Subchannel pool.
grpc_core::RefCountedPtr<grpc_core::SubchannelPoolInterface> subchannel_pool;
grpc_core::channelz::ClientChannelNode* channelz_node; grpc_core::channelz::ClientChannelNode* channelz_node;
// Resolving LB policy. //
grpc_core::OrphanablePtr<LoadBalancingPolicy> resolving_lb_policy; // Fields used in the data plane. Protected by data_plane_combiner.
// Subchannel picker from LB policy. //
grpc_combiner* data_plane_combiner;
grpc_core::UniquePtr<LoadBalancingPolicy::SubchannelPicker> picker; grpc_core::UniquePtr<LoadBalancingPolicy::SubchannelPicker> picker;
// Linked list of queued picks. QueuedPick* queued_picks; // Linked list of queued picks.
QueuedPick* queued_picks; // Data from service config.
bool received_service_config_data;
bool have_service_config;
/** retry throttle data from service config */
grpc_core::RefCountedPtr<ServerRetryThrottleData> retry_throttle_data; grpc_core::RefCountedPtr<ServerRetryThrottleData> retry_throttle_data;
/** per-method service config data */
grpc_core::RefCountedPtr<ClientChannelMethodParamsTable> method_params_table; grpc_core::RefCountedPtr<ClientChannelMethodParamsTable> method_params_table;
/* the following properties are guarded by a mutex since APIs require them //
to be instantaneously available */ // Fields used in the control plane. Protected by combiner.
gpr_mu info_mu; //
grpc_core::UniquePtr<char> info_lb_policy_name; grpc_combiner* combiner;
grpc_core::UniquePtr<char> info_service_config_json; grpc_pollset_set* interested_parties;
grpc_core::RefCountedPtr<grpc_core::SubchannelPoolInterface> subchannel_pool;
grpc_core::OrphanablePtr<LoadBalancingPolicy> resolving_lb_policy;
grpc_connectivity_state_tracker state_tracker; grpc_connectivity_state_tracker state_tracker;
grpc_error* disconnect_error;
/* external_connectivity_watcher_list head is guarded by its own mutex, since //
* counts need to be grabbed immediately without polling on a cq */ // Fields accessed from both data plane and control plane combiners.
//
grpc_core::Atomic<grpc_error*> disconnect_error;
// external_connectivity_watcher_list head is guarded by its own mutex, since
// counts need to be grabbed immediately without polling on a CQ.
gpr_mu external_connectivity_watcher_list_mu; gpr_mu external_connectivity_watcher_list_mu;
struct external_connectivity_watcher* external_connectivity_watcher_list_head; struct external_connectivity_watcher* external_connectivity_watcher_list_head;
// The following properties are guarded by a mutex since APIs require them
// to be instantaneously available.
gpr_mu info_mu;
grpc_core::UniquePtr<char> info_lb_policy_name;
grpc_core::UniquePtr<char> info_service_config_json;
} channel_data; } channel_data;
// Forward declarations. // Forward declarations.
@ -166,30 +169,98 @@ static const char* get_channel_connectivity_state_change_string(
GPR_UNREACHABLE_CODE(return "UNKNOWN"); GPR_UNREACHABLE_CODE(return "UNKNOWN");
} }
static void set_connectivity_state_and_picker_locked( namespace grpc_core {
channel_data* chand, grpc_connectivity_state state, grpc_error* state_error, namespace {
const char* reason,
grpc_core::UniquePtr<LoadBalancingPolicy::SubchannelPicker> picker) { // A fire-and-forget class that sets the channel's connectivity state
// Update connectivity state. // and then hops into the data plane combiner to update the picker.
grpc_connectivity_state_set(&chand->state_tracker, state, state_error, // Must be instantiated while holding the control plane combiner.
reason); // Deletes itself when done.
if (chand->channelz_node != nullptr) { class ConnectivityStateAndPickerSetter {
chand->channelz_node->AddTraceEvent( public:
grpc_core::channelz::ChannelTrace::Severity::Info, ConnectivityStateAndPickerSetter(
grpc_slice_from_static_string( channel_data* chand, grpc_connectivity_state state,
get_channel_connectivity_state_change_string(state))); grpc_error* state_error, const char* reason,
UniquePtr<LoadBalancingPolicy::SubchannelPicker> picker)
: chand_(chand), picker_(std::move(picker)) {
// Update connectivity state here, while holding control plane combiner.
grpc_connectivity_state_set(&chand->state_tracker, state, state_error,
reason);
if (chand->channelz_node != nullptr) {
chand->channelz_node->AddTraceEvent(
channelz::ChannelTrace::Severity::Info,
grpc_slice_from_static_string(
get_channel_connectivity_state_change_string(state)));
}
// Bounce into the data plane combiner to reset the picker.
GRPC_CHANNEL_STACK_REF(chand->owning_stack,
"ConnectivityStateAndPickerSetter");
GRPC_CLOSURE_INIT(&closure_, SetPicker, this,
grpc_combiner_scheduler(chand->data_plane_combiner));
GRPC_CLOSURE_SCHED(&closure_, GRPC_ERROR_NONE);
} }
// Update picker.
chand->picker = std::move(picker); private:
// Re-process queued picks. static void SetPicker(void* arg, grpc_error* ignored) {
for (QueuedPick* pick = chand->queued_picks; pick != nullptr; auto* self = static_cast<ConnectivityStateAndPickerSetter*>(arg);
pick = pick->next) { // Update picker.
start_pick_locked(pick->elem, GRPC_ERROR_NONE); self->chand_->picker = std::move(self->picker_);
// Re-process queued picks.
for (QueuedPick* pick = self->chand_->queued_picks; pick != nullptr;
pick = pick->next) {
start_pick_locked(pick->elem, GRPC_ERROR_NONE);
}
// Clean up.
GRPC_CHANNEL_STACK_UNREF(self->chand_->owning_stack,
"ConnectivityStateAndPickerSetter");
Delete(self);
} }
}
namespace grpc_core { channel_data* chand_;
namespace { UniquePtr<LoadBalancingPolicy::SubchannelPicker> picker_;
grpc_closure closure_;
};
// A fire-and-forget class that sets the channel's service config data
// in the data plane combiner. Deletes itself when done.
class ServiceConfigSetter {
public:
ServiceConfigSetter(
channel_data* chand,
RefCountedPtr<ServerRetryThrottleData> retry_throttle_data,
RefCountedPtr<ClientChannelMethodParamsTable> method_params_table)
: chand_(chand),
retry_throttle_data_(std::move(retry_throttle_data)),
method_params_table_(std::move(method_params_table)) {
GRPC_CHANNEL_STACK_REF(chand->owning_stack, "ServiceConfigSetter");
GRPC_CLOSURE_INIT(&closure_, SetServiceConfigData, this,
grpc_combiner_scheduler(chand->data_plane_combiner));
GRPC_CLOSURE_SCHED(&closure_, GRPC_ERROR_NONE);
}
private:
static void SetServiceConfigData(void* arg, grpc_error* ignored) {
ServiceConfigSetter* self = static_cast<ServiceConfigSetter*>(arg);
channel_data* chand = self->chand_;
// Update channel state.
chand->received_service_config_data = true;
chand->retry_throttle_data = std::move(self->retry_throttle_data_);
chand->method_params_table = std::move(self->method_params_table_);
// Apply service config to queued picks.
for (QueuedPick* pick = chand->queued_picks; pick != nullptr;
pick = pick->next) {
maybe_apply_service_config_to_call_locked(pick->elem);
}
// Clean up.
GRPC_CHANNEL_STACK_UNREF(self->chand_->owning_stack, "ServiceConfigSetter");
Delete(self);
}
channel_data* chand_;
RefCountedPtr<ServerRetryThrottleData> retry_throttle_data_;
RefCountedPtr<ClientChannelMethodParamsTable> method_params_table_;
grpc_closure closure_;
};
class ClientChannelControlHelper class ClientChannelControlHelper
: public LoadBalancingPolicy::ChannelControlHelper { : public LoadBalancingPolicy::ChannelControlHelper {
@ -222,8 +293,10 @@ class ClientChannelControlHelper
void UpdateState( void UpdateState(
grpc_connectivity_state state, grpc_error* state_error, grpc_connectivity_state state, grpc_error* state_error,
UniquePtr<LoadBalancingPolicy::SubchannelPicker> picker) override { UniquePtr<LoadBalancingPolicy::SubchannelPicker> picker) override {
grpc_error* disconnect_error =
chand_->disconnect_error.Load(grpc_core::MemoryOrder::ACQUIRE);
if (grpc_client_channel_routing_trace.enabled()) { if (grpc_client_channel_routing_trace.enabled()) {
const char* extra = chand_->disconnect_error == GRPC_ERROR_NONE const char* extra = disconnect_error == GRPC_ERROR_NONE
? "" ? ""
: " (ignoring -- channel shutting down)"; : " (ignoring -- channel shutting down)";
gpr_log(GPR_INFO, "chand=%p: update: state=%s error=%s picker=%p%s", gpr_log(GPR_INFO, "chand=%p: update: state=%s error=%s picker=%p%s",
@ -231,9 +304,10 @@ class ClientChannelControlHelper
grpc_error_string(state_error), picker.get(), extra); grpc_error_string(state_error), picker.get(), extra);
} }
// Do update only if not shutting down. // Do update only if not shutting down.
if (chand_->disconnect_error == GRPC_ERROR_NONE) { if (disconnect_error == GRPC_ERROR_NONE) {
set_connectivity_state_and_picker_locked(chand_, state, state_error, // Will delete itself.
"helper", std::move(picker)); New<ConnectivityStateAndPickerSetter>(chand_, state, state_error,
"helper", std::move(picker));
} else { } else {
GRPC_ERROR_UNREF(state_error); GRPC_ERROR_UNREF(state_error);
} }
@ -255,7 +329,6 @@ static bool process_resolver_result_locked(
void* arg, grpc_core::Resolver::Result* result, const char** lb_policy_name, void* arg, grpc_core::Resolver::Result* result, const char** lb_policy_name,
grpc_core::RefCountedPtr<LoadBalancingPolicy::Config>* lb_policy_config) { grpc_core::RefCountedPtr<LoadBalancingPolicy::Config>* lb_policy_config) {
channel_data* chand = static_cast<channel_data*>(arg); channel_data* chand = static_cast<channel_data*>(arg);
chand->have_service_config = true;
ProcessedResolverResult resolver_result(result, chand->enable_retries); ProcessedResolverResult resolver_result(result, chand->enable_retries);
grpc_core::UniquePtr<char> service_config_json = grpc_core::UniquePtr<char> service_config_json =
resolver_result.service_config_json(); resolver_result.service_config_json();
@ -263,9 +336,11 @@ static bool process_resolver_result_locked(
gpr_log(GPR_INFO, "chand=%p: resolver returned service config: \"%s\"", gpr_log(GPR_INFO, "chand=%p: resolver returned service config: \"%s\"",
chand, service_config_json.get()); chand, service_config_json.get());
} }
// Update channel state. // Create service config setter to update channel state in the data
chand->retry_throttle_data = resolver_result.retry_throttle_data(); // plane combiner. Destroys itself when done.
chand->method_params_table = resolver_result.method_params_table(); grpc_core::New<grpc_core::ServiceConfigSetter>(
chand, resolver_result.retry_throttle_data(),
resolver_result.method_params_table());
// Swap out the data used by cc_get_channel_info(). // Swap out the data used by cc_get_channel_info().
gpr_mu_lock(&chand->info_mu); gpr_mu_lock(&chand->info_mu);
chand->info_lb_policy_name = resolver_result.lb_policy_name(); chand->info_lb_policy_name = resolver_result.lb_policy_name();
@ -280,11 +355,6 @@ static bool process_resolver_result_locked(
// Return results. // Return results.
*lb_policy_name = chand->info_lb_policy_name.get(); *lb_policy_name = chand->info_lb_policy_name.get();
*lb_policy_config = resolver_result.lb_policy_config(); *lb_policy_config = resolver_result.lb_policy_config();
// Apply service config to queued picks.
for (QueuedPick* pick = chand->queued_picks; pick != nullptr;
pick = pick->next) {
maybe_apply_service_config_to_call_locked(pick->elem);
}
return service_config_changed; return service_config_changed;
} }
@ -342,12 +412,16 @@ static void start_transport_op_locked(void* arg, grpc_error* error_ignored) {
} }
if (op->disconnect_with_error != GRPC_ERROR_NONE) { if (op->disconnect_with_error != GRPC_ERROR_NONE) {
chand->disconnect_error = op->disconnect_with_error; grpc_error* error = GRPC_ERROR_NONE;
GPR_ASSERT(chand->disconnect_error.CompareExchangeStrong(
&error, op->disconnect_with_error, grpc_core::MemoryOrder::ACQ_REL,
grpc_core::MemoryOrder::ACQUIRE));
grpc_pollset_set_del_pollset_set( grpc_pollset_set_del_pollset_set(
chand->resolving_lb_policy->interested_parties(), chand->resolving_lb_policy->interested_parties(),
chand->interested_parties); chand->interested_parties);
chand->resolving_lb_policy.reset(); chand->resolving_lb_policy.reset();
set_connectivity_state_and_picker_locked( // Will delete itself.
grpc_core::New<grpc_core::ConnectivityStateAndPickerSetter>(
chand, GRPC_CHANNEL_SHUTDOWN, GRPC_ERROR_REF(op->disconnect_with_error), chand, GRPC_CHANNEL_SHUTDOWN, GRPC_ERROR_REF(op->disconnect_with_error),
"shutdown from API", "shutdown from API",
grpc_core::UniquePtr<LoadBalancingPolicy::SubchannelPicker>( grpc_core::UniquePtr<LoadBalancingPolicy::SubchannelPicker>(
@ -397,10 +471,12 @@ static grpc_error* cc_init_channel_elem(grpc_channel_element* elem,
GPR_ASSERT(args->is_last); GPR_ASSERT(args->is_last);
GPR_ASSERT(elem->filter == &grpc_client_channel_filter); GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
// Initialize data members. // Initialize data members.
chand->data_plane_combiner = grpc_combiner_create();
chand->combiner = grpc_combiner_create(); chand->combiner = grpc_combiner_create();
grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE, grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE,
"client_channel"); "client_channel");
chand->disconnect_error = GRPC_ERROR_NONE; chand->disconnect_error.Store(GRPC_ERROR_NONE,
grpc_core::MemoryOrder::RELAXED);
gpr_mu_init(&chand->info_mu); gpr_mu_init(&chand->info_mu);
gpr_mu_init(&chand->external_connectivity_watcher_list_mu); gpr_mu_init(&chand->external_connectivity_watcher_list_mu);
@ -511,8 +587,10 @@ static void cc_destroy_channel_elem(grpc_channel_element* elem) {
chand->method_params_table.reset(); chand->method_params_table.reset();
grpc_client_channel_stop_backup_polling(chand->interested_parties); grpc_client_channel_stop_backup_polling(chand->interested_parties);
grpc_pollset_set_destroy(chand->interested_parties); grpc_pollset_set_destroy(chand->interested_parties);
GRPC_COMBINER_UNREF(chand->data_plane_combiner, "client_channel");
GRPC_COMBINER_UNREF(chand->combiner, "client_channel"); GRPC_COMBINER_UNREF(chand->combiner, "client_channel");
GRPC_ERROR_UNREF(chand->disconnect_error); GRPC_ERROR_UNREF(
chand->disconnect_error.Load(grpc_core::MemoryOrder::RELAXED));
grpc_connectivity_state_destroy(&chand->state_tracker); grpc_connectivity_state_destroy(&chand->state_tracker);
gpr_mu_destroy(&chand->info_mu); gpr_mu_destroy(&chand->info_mu);
gpr_mu_destroy(&chand->external_connectivity_watcher_list_mu); gpr_mu_destroy(&chand->external_connectivity_watcher_list_mu);
@ -1261,7 +1339,7 @@ static void do_retry(grpc_call_element* elem,
} }
// Schedule retry after computed delay. // Schedule retry after computed delay.
GRPC_CLOSURE_INIT(&calld->pick_closure, start_pick_locked, elem, GRPC_CLOSURE_INIT(&calld->pick_closure, start_pick_locked, elem,
grpc_combiner_scheduler(chand->combiner)); grpc_combiner_scheduler(chand->data_plane_combiner));
grpc_timer_init(&calld->retry_timer, next_attempt_time, &calld->pick_closure); grpc_timer_init(&calld->retry_timer, next_attempt_time, &calld->pick_closure);
// Update bookkeeping. // Update bookkeeping.
if (retry_state != nullptr) retry_state->retry_dispatched = true; if (retry_state != nullptr) retry_state->retry_dispatched = true;
@ -2488,7 +2566,7 @@ class QueuedPickCanceller {
auto* chand = static_cast<channel_data*>(elem->channel_data); auto* chand = static_cast<channel_data*>(elem->channel_data);
GRPC_CALL_STACK_REF(calld->owning_call, "QueuedPickCanceller"); GRPC_CALL_STACK_REF(calld->owning_call, "QueuedPickCanceller");
GRPC_CLOSURE_INIT(&closure_, &CancelLocked, this, GRPC_CLOSURE_INIT(&closure_, &CancelLocked, this,
grpc_combiner_scheduler(chand->combiner)); grpc_combiner_scheduler(chand->data_plane_combiner));
grpc_call_combiner_set_notify_on_cancel(calld->call_combiner, &closure_); grpc_call_combiner_set_notify_on_cancel(calld->call_combiner, &closure_);
} }
@ -2628,7 +2706,7 @@ static void maybe_apply_service_config_to_call_locked(grpc_call_element* elem) {
call_data* calld = static_cast<call_data*>(elem->call_data); call_data* calld = static_cast<call_data*>(elem->call_data);
// Apply service config data to the call only once, and only if the // Apply service config data to the call only once, and only if the
// channel has the data available. // channel has the data available.
if (GPR_LIKELY(chand->have_service_config && if (GPR_LIKELY(chand->received_service_config_data &&
!calld->service_config_applied)) { !calld->service_config_applied)) {
calld->service_config_applied = true; calld->service_config_applied = true;
apply_service_config_to_call_locked(elem); apply_service_config_to_call_locked(elem);
@ -2676,7 +2754,7 @@ static void start_pick_locked(void* arg, grpc_error* error) {
.send_initial_metadata_flags; .send_initial_metadata_flags;
// Apply service config to call if needed. // Apply service config to call if needed.
maybe_apply_service_config_to_call_locked(elem); maybe_apply_service_config_to_call_locked(elem);
// When done, we schedule this closure to leave the channel combiner. // When done, we schedule this closure to leave the data plane combiner.
GRPC_CLOSURE_INIT(&calld->pick_closure, pick_done, elem, GRPC_CLOSURE_INIT(&calld->pick_closure, pick_done, elem,
grpc_schedule_on_exec_ctx); grpc_schedule_on_exec_ctx);
// Attempt pick. // Attempt pick.
@ -2691,12 +2769,14 @@ static void start_pick_locked(void* arg, grpc_error* error) {
grpc_error_string(error)); grpc_error_string(error));
} }
switch (pick_result) { switch (pick_result) {
case LoadBalancingPolicy::PICK_TRANSIENT_FAILURE: case LoadBalancingPolicy::PICK_TRANSIENT_FAILURE: {
// If we're shutting down, fail all RPCs. // If we're shutting down, fail all RPCs.
if (chand->disconnect_error != GRPC_ERROR_NONE) { grpc_error* disconnect_error =
chand->disconnect_error.Load(grpc_core::MemoryOrder::ACQUIRE);
if (disconnect_error != GRPC_ERROR_NONE) {
GRPC_ERROR_UNREF(error); GRPC_ERROR_UNREF(error);
GRPC_CLOSURE_SCHED(&calld->pick_closure, GRPC_CLOSURE_SCHED(&calld->pick_closure,
GRPC_ERROR_REF(chand->disconnect_error)); GRPC_ERROR_REF(disconnect_error));
break; break;
} }
// If wait_for_ready is false, then the error indicates the RPC // If wait_for_ready is false, then the error indicates the RPC
@ -2722,7 +2802,8 @@ static void start_pick_locked(void* arg, grpc_error* error) {
// If wait_for_ready is true, then queue to retry when we get a new // If wait_for_ready is true, then queue to retry when we get a new
// picker. // picker.
GRPC_ERROR_UNREF(error); GRPC_ERROR_UNREF(error);
// Fallthrough }
// Fallthrough
case LoadBalancingPolicy::PICK_QUEUE: case LoadBalancingPolicy::PICK_QUEUE:
if (!calld->pick_queued) add_call_to_queued_picks_locked(elem); if (!calld->pick_queued) add_call_to_queued_picks_locked(elem);
break; break;
@ -2816,7 +2897,8 @@ static void cc_start_transport_stream_op_batch(
} }
GRPC_CLOSURE_SCHED( GRPC_CLOSURE_SCHED(
GRPC_CLOSURE_INIT(&batch->handler_private.closure, start_pick_locked, GRPC_CLOSURE_INIT(&batch->handler_private.closure, start_pick_locked,
elem, grpc_combiner_scheduler(chand->combiner)), elem,
grpc_combiner_scheduler(chand->data_plane_combiner)),
GRPC_ERROR_NONE); GRPC_ERROR_NONE);
} else { } else {
// For all other batches, release the call combiner. // For all other batches, release the call combiner.

@ -140,10 +140,9 @@ LoadBalancingPolicy::PickResult LoadBalancingPolicy::QueuePicker::Pick(
// the time this function returns, the pick will already have // the time this function returns, the pick will already have
// been processed, and we'll be trying to re-process the same // been processed, and we'll be trying to re-process the same
// pick again, leading to a crash. // pick again, leading to a crash.
// 2. In a subsequent PR, we will split the data plane and control // 2. We are currently running in the data plane combiner, but we
// plane synchronization into separate combiners, at which // need to bounce into the control plane combiner to call
// point this will need to hop from the data plane combiner into // ExitIdleLocked().
// the control plane combiner.
if (!exit_idle_called_) { if (!exit_idle_called_) {
exit_idle_called_ = true; exit_idle_called_ = true;
parent_->Ref().release(); // ref held by closure. parent_->Ref().release(); // ref held by closure.

@ -234,12 +234,19 @@ class GrpcLb : public LoadBalancingPolicy {
// Returns the LB token to use for a drop, or null if the call // Returns the LB token to use for a drop, or null if the call
// should not be dropped. // should not be dropped.
// Intended to be called from picker, so calls will be externally //
// synchronized. // Note: This is called from the picker, so it will be invoked in
// the channel's data plane combiner, NOT the control plane
// combiner. It should not be accessed by any other part of the LB
// policy.
const char* ShouldDrop(); const char* ShouldDrop();
private: private:
grpc_grpclb_serverlist* serverlist_; grpc_grpclb_serverlist* serverlist_;
// Guarded by the channel's data plane combiner, NOT the control
// plane combiner. It should not be accessed by anything but the
// picker via the ShouldDrop() method.
size_t drop_index_ = 0; size_t drop_index_ = 0;
}; };

@ -160,8 +160,6 @@ void Fork::GlobalInit() {
if (!override_enabled_) { if (!override_enabled_) {
#ifdef GRPC_ENABLE_FORK_SUPPORT #ifdef GRPC_ENABLE_FORK_SUPPORT
support_enabled_ = true; support_enabled_ = true;
#else
support_enabled_ = false;
#endif #endif
bool env_var_set = false; bool env_var_set = false;
char* env = gpr_getenv("GRPC_ENABLE_FORK_SUPPORT"); char* env = gpr_getenv("GRPC_ENABLE_FORK_SUPPORT");

@ -29,6 +29,7 @@
#include "src/core/lib/debug/trace.h" #include "src/core/lib/debug/trace.h"
#include "src/core/lib/iomgr/closure.h" #include "src/core/lib/iomgr/closure.h"
#include "src/core/lib/iomgr/error_cfstream.h"
#include "src/core/lib/iomgr/exec_ctx.h" #include "src/core/lib/iomgr/exec_ctx.h"
extern grpc_core::TraceFlag grpc_tcp_trace; extern grpc_core::TraceFlag grpc_tcp_trace;
@ -54,6 +55,8 @@ void CFStreamHandle::ReadCallback(CFReadStreamRef stream,
void* client_callback_info) { void* client_callback_info) {
grpc_core::ApplicationCallbackExecCtx callback_exec_ctx; grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
grpc_core::ExecCtx exec_ctx; grpc_core::ExecCtx exec_ctx;
grpc_error* error;
CFErrorRef stream_error;
CFStreamHandle* handle = static_cast<CFStreamHandle*>(client_callback_info); CFStreamHandle* handle = static_cast<CFStreamHandle*>(client_callback_info);
if (grpc_tcp_trace.enabled()) { if (grpc_tcp_trace.enabled()) {
gpr_log(GPR_DEBUG, "CFStream ReadCallback (%p, %p, %lu, %p)", handle, gpr_log(GPR_DEBUG, "CFStream ReadCallback (%p, %p, %lu, %p)", handle,
@ -68,8 +71,15 @@ void CFStreamHandle::ReadCallback(CFReadStreamRef stream,
handle->read_event_.SetReady(); handle->read_event_.SetReady();
break; break;
case kCFStreamEventErrorOccurred: case kCFStreamEventErrorOccurred:
handle->open_event_.SetReady(); stream_error = CFReadStreamCopyError(stream);
handle->read_event_.SetReady(); error = grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_CFERROR(stream_error, "read error"),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
CFRelease(stream_error);
handle->open_event_.SetShutdown(GRPC_ERROR_REF(error));
handle->write_event_.SetShutdown(GRPC_ERROR_REF(error));
handle->read_event_.SetShutdown(GRPC_ERROR_REF(error));
GRPC_ERROR_UNREF(error);
break; break;
default: default:
GPR_UNREACHABLE_CODE(return ); GPR_UNREACHABLE_CODE(return );
@ -80,6 +90,8 @@ void CFStreamHandle::WriteCallback(CFWriteStreamRef stream,
void* clientCallBackInfo) { void* clientCallBackInfo) {
grpc_core::ApplicationCallbackExecCtx callback_exec_ctx; grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
grpc_core::ExecCtx exec_ctx; grpc_core::ExecCtx exec_ctx;
grpc_error* error;
CFErrorRef stream_error;
CFStreamHandle* handle = static_cast<CFStreamHandle*>(clientCallBackInfo); CFStreamHandle* handle = static_cast<CFStreamHandle*>(clientCallBackInfo);
if (grpc_tcp_trace.enabled()) { if (grpc_tcp_trace.enabled()) {
gpr_log(GPR_DEBUG, "CFStream WriteCallback (%p, %p, %lu, %p)", handle, gpr_log(GPR_DEBUG, "CFStream WriteCallback (%p, %p, %lu, %p)", handle,
@ -94,8 +106,15 @@ void CFStreamHandle::WriteCallback(CFWriteStreamRef stream,
handle->write_event_.SetReady(); handle->write_event_.SetReady();
break; break;
case kCFStreamEventErrorOccurred: case kCFStreamEventErrorOccurred:
handle->open_event_.SetReady(); stream_error = CFWriteStreamCopyError(stream);
handle->write_event_.SetReady(); error = grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_CFERROR(stream_error, "write error"),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
CFRelease(stream_error);
handle->open_event_.SetShutdown(GRPC_ERROR_REF(error));
handle->write_event_.SetShutdown(GRPC_ERROR_REF(error));
handle->read_event_.SetShutdown(GRPC_ERROR_REF(error));
GRPC_ERROR_UNREF(error);
break; break;
default: default:
GPR_UNREACHABLE_CODE(return ); GPR_UNREACHABLE_CODE(return );

@ -213,10 +213,12 @@ static void tcp_connect(grpc_closure* on_done, grpc_endpoint** endpoint,
failure: failure:
GPR_ASSERT(error != GRPC_ERROR_NONE); GPR_ASSERT(error != GRPC_ERROR_NONE);
char* target_uri = grpc_sockaddr_to_uri(addr); char* target_uri = grpc_sockaddr_to_uri(addr);
grpc_error* final_error = grpc_error_set_str( grpc_error* final_error =
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING("Failed to connect", grpc_error_set_str(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
&error, 1), "Failed to connect", &error, 1),
GRPC_ERROR_STR_TARGET_ADDRESS, grpc_slice_from_copied_string(target_uri)); GRPC_ERROR_STR_TARGET_ADDRESS,
grpc_slice_from_copied_string(
target_uri == nullptr ? "NULL" : target_uri));
GRPC_ERROR_UNREF(error); GRPC_ERROR_UNREF(error);
if (socket != NULL) { if (socket != NULL) {
grpc_winsocket_destroy(socket); grpc_winsocket_destroy(socket);

@ -18,8 +18,6 @@
#include <grpcpp/channel.h> #include <grpcpp/channel.h>
#include <chrono>
#include <condition_variable>
#include <cstring> #include <cstring>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
@ -41,12 +39,7 @@
#include <grpcpp/support/channel_arguments.h> #include <grpcpp/support/channel_arguments.h>
#include <grpcpp/support/config.h> #include <grpcpp/support/config.h>
#include <grpcpp/support/status.h> #include <grpcpp/support/status.h>
#include <grpcpp/support/time.h>
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/surface/completion_queue.h" #include "src/core/lib/surface/completion_queue.h"
namespace grpc { namespace grpc {

@ -59,7 +59,7 @@ namespace Grpc.Core
/// <summary> /// <summary>
/// Creates a channel that connects to a specific host. /// Creates a channel that connects to a specific host.
/// Port will default to 80 for an unsecure channel and to 443 for a secure channel. /// Port will default to 80 for an unsecure channel or to 443 for a secure channel.
/// </summary> /// </summary>
/// <param name="target">Target of the channel.</param> /// <param name="target">Target of the channel.</param>
/// <param name="credentials">Credentials to secure the channel.</param> /// <param name="credentials">Credentials to secure the channel.</param>
@ -112,7 +112,7 @@ namespace Grpc.Core
/// <summary> /// <summary>
/// Gets current connectivity state of this channel. /// Gets current connectivity state of this channel.
/// After channel is has been shutdown, <c>ChannelState.Shutdown</c> will be returned. /// After channel has been shutdown, <c>ChannelState.Shutdown</c> will be returned.
/// </summary> /// </summary>
public ChannelState State public ChannelState State
{ {
@ -132,7 +132,7 @@ namespace Grpc.Core
/// <summary> /// <summary>
/// Returned tasks completes once channel state has become different from /// Returned tasks completes once channel state has become different from
/// given lastObservedState. /// given lastObservedState.
/// If deadline is reached or and error occurs, returned task is cancelled. /// If deadline is reached or an error occurs, returned task is cancelled.
/// </summary> /// </summary>
public async Task WaitForStateChangedAsync(ChannelState lastObservedState, DateTime? deadline = null) public async Task WaitForStateChangedAsync(ChannelState lastObservedState, DateTime? deadline = null)
{ {

@ -67,27 +67,22 @@ ZEND_GET_MODULE(grpc)
/* {{{ PHP_INI /* {{{ PHP_INI
*/ */
/* Remove comments and fill if you need to have entries in php.ini
PHP_INI_BEGIN() PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("grpc.global_value", "42", PHP_INI_ALL, OnUpdateLong, STD_PHP_INI_ENTRY("grpc.enable_fork_support", "0", PHP_INI_SYSTEM, OnUpdateBool,
global_value, zend_grpc_globals, grpc_globals) enable_fork_support, zend_grpc_globals, grpc_globals)
STD_PHP_INI_ENTRY("grpc.global_string", "foobar", PHP_INI_ALL, STD_PHP_INI_ENTRY("grpc.poll_strategy", NULL, PHP_INI_SYSTEM, OnUpdateString,
OnUpdateString, global_string, zend_grpc_globals, poll_strategy, zend_grpc_globals, grpc_globals)
grpc_globals)
PHP_INI_END() PHP_INI_END()
*/
/* }}} */ /* }}} */
/* {{{ php_grpc_init_globals /* {{{ php_grpc_init_globals
*/ */
/* Uncomment this function if you have INI entries static void php_grpc_init_globals(zend_grpc_globals *grpc_globals) {
static void php_grpc_init_globals(zend_grpc_globals *grpc_globals) grpc_globals->enable_fork_support = 0;
{ grpc_globals->poll_strategy = NULL;
grpc_globals->global_value = 0; }
grpc_globals->global_string = NULL;
}
*/
/* }}} */ /* }}} */
void create_new_channel( void create_new_channel(
wrapped_grpc_channel *channel, wrapped_grpc_channel *channel,
char *target, char *target,
@ -180,7 +175,7 @@ void postfork_child() {
grpc_php_shutdown_completion_queue(TSRMLS_C); grpc_php_shutdown_completion_queue(TSRMLS_C);
// clean-up grpc_core // clean-up grpc_core
grpc_shutdown(); grpc_shutdown_blocking();
if (grpc_is_initialized() > 0) { if (grpc_is_initialized() > 0) {
zend_throw_exception(spl_ce_UnexpectedValueException, zend_throw_exception(spl_ce_UnexpectedValueException,
"Oops, failed to shutdown gRPC Core after fork()", "Oops, failed to shutdown gRPC Core after fork()",
@ -208,12 +203,22 @@ void register_fork_handlers() {
} }
} }
void apply_ini_settings() {
if (GRPC_G(enable_fork_support)) {
setenv("GRPC_ENABLE_FORK_SUPPORT", "1", 1 /* overwrite? */);
}
if (GRPC_G(poll_strategy)) {
setenv("GRPC_POLL_STRATEGY", GRPC_G(poll_strategy), 1 /* overwrite? */);
}
}
/* {{{ PHP_MINIT_FUNCTION /* {{{ PHP_MINIT_FUNCTION
*/ */
PHP_MINIT_FUNCTION(grpc) { PHP_MINIT_FUNCTION(grpc) {
/* If you have INI entries, uncomment these lines ZEND_INIT_MODULE_GLOBALS(grpc, php_grpc_init_globals, NULL);
REGISTER_INI_ENTRIES(); REGISTER_INI_ENTRIES();
*/
/* Register call error constants */ /* Register call error constants */
REGISTER_LONG_CONSTANT("Grpc\\CALL_OK", GRPC_CALL_OK, REGISTER_LONG_CONSTANT("Grpc\\CALL_OK", GRPC_CALL_OK,
CONST_CS | CONST_PERSISTENT); CONST_CS | CONST_PERSISTENT);
@ -349,9 +354,7 @@ PHP_MINIT_FUNCTION(grpc) {
/* {{{ PHP_MSHUTDOWN_FUNCTION /* {{{ PHP_MSHUTDOWN_FUNCTION
*/ */
PHP_MSHUTDOWN_FUNCTION(grpc) { PHP_MSHUTDOWN_FUNCTION(grpc) {
/* uncomment this line if you have INI entries UNREGISTER_INI_ENTRIES();
UNREGISTER_INI_ENTRIES();
*/
// WARNING: This function IS being called by PHP when the extension // WARNING: This function IS being called by PHP when the extension
// is unloaded but the logs were somehow suppressed. // is unloaded but the logs were somehow suppressed.
if (GRPC_G(initialized)) { if (GRPC_G(initialized)) {
@ -375,9 +378,7 @@ PHP_MINFO_FUNCTION(grpc) {
php_info_print_table_row(2, "grpc support", "enabled"); php_info_print_table_row(2, "grpc support", "enabled");
php_info_print_table_row(2, "grpc module version", PHP_GRPC_VERSION); php_info_print_table_row(2, "grpc module version", PHP_GRPC_VERSION);
php_info_print_table_end(); php_info_print_table_end();
/* Remove comments if you have entries in php.ini DISPLAY_INI_ENTRIES();
DISPLAY_INI_ENTRIES();
*/
} }
/* }}} */ /* }}} */
@ -385,6 +386,7 @@ PHP_MINFO_FUNCTION(grpc) {
*/ */
PHP_RINIT_FUNCTION(grpc) { PHP_RINIT_FUNCTION(grpc) {
if (!GRPC_G(initialized)) { if (!GRPC_G(initialized)) {
apply_ini_settings();
grpc_init(); grpc_init();
register_fork_handlers(); register_fork_handlers();
grpc_php_init_completion_queue(TSRMLS_C); grpc_php_init_completion_queue(TSRMLS_C);

@ -66,6 +66,8 @@ PHP_RINIT_FUNCTION(grpc);
*/ */
ZEND_BEGIN_MODULE_GLOBALS(grpc) ZEND_BEGIN_MODULE_GLOBALS(grpc)
zend_bool initialized; zend_bool initialized;
zend_bool enable_fork_support;
char *poll_strategy;
ZEND_END_MODULE_GLOBALS(grpc) ZEND_END_MODULE_GLOBALS(grpc)
/* In every utility function you add that needs to use variables /* In every utility function you add that needs to use variables

@ -0,0 +1,15 @@
--TEST--
Ensure default ini settings
--SKIPIF--
<?php if (!extension_loaded("grpc")) print "skip"; ?>
--FILE--
<?php
if (ini_get('grpc.enable_fork_support')) {
die('grpc.enable_fork_support not off by default');
}
if (ini_get('grpc.poll_strategy') !== "") {
die('grpc.poll_strategy not empty by default');
}
echo 'ok';
--EXPECT--
ok

@ -0,0 +1,24 @@
--TEST--
Ensure ini settings are handled
--SKIPIF--
<?php if (!extension_loaded("grpc")) print "skip"; ?>
--INI--
grpc.enable_fork_support = 1
grpc.poll_strategy = epoll1
--FILE--
<?php
if (!ini_get('grpc.enable_fork_support')) {
die('grpc.enable_fork_support not set');
}
if (!getenv('GRPC_ENABLE_FORK_SUPPORT')) {
die('env GRPC_ENABLE_FORK_SUPPORT not set');
}
if (ini_get('grpc.poll_strategy') !== 'epoll1') {
die('grpc.poll_strategy !== epoll1');
}
if (getenv('GRPC_POLL_STRATEGY') !== 'epoll1') {
die('env GRPC_POLL_STRATEGY not epoll1');
}
echo 'ok';
--EXPECT--
ok

@ -4,5 +4,6 @@ py_library(
visibility = [ visibility = [
"//src/python/grpcio_tests/tests/status:__subpackages__", "//src/python/grpcio_tests/tests/status:__subpackages__",
"//src/python/grpcio_tests/tests/interop:__subpackages__", "//src/python/grpcio_tests/tests/interop:__subpackages__",
"//examples/python/errors:__subpackages__",
], ],
) )

@ -29,4 +29,5 @@ grpc_cc_binary(
"//:grpc", "//:grpc",
"//test/core/util:grpc_test_util", "//test/core/util:grpc_test_util",
], ],
tags = ["no_windows"],
) )

@ -52,6 +52,7 @@ grpc_cc_test(
"//:grpc", "//:grpc",
"//test/core/util:grpc_test_util", "//test/core/util:grpc_test_util",
], ],
tags = ["no_windows"],
) )
grpc_cc_test( grpc_cc_test(

@ -31,7 +31,8 @@ def _fixture_options(
is_http2 = True, is_http2 = True,
supports_proxy_auth = False, supports_proxy_auth = False,
supports_write_buffering = True, supports_write_buffering = True,
client_channel = True): client_channel = True,
supports_msvc = True):
return struct( return struct(
fullstack = fullstack, fullstack = fullstack,
includes_proxy = includes_proxy, includes_proxy = includes_proxy,
@ -44,6 +45,7 @@ def _fixture_options(
supports_proxy_auth = supports_proxy_auth, supports_proxy_auth = supports_proxy_auth,
supports_write_buffering = supports_write_buffering, supports_write_buffering = supports_write_buffering,
client_channel = client_channel, client_channel = client_channel,
supports_msvc = supports_msvc,
#_platforms=_platforms, #_platforms=_platforms,
) )
@ -120,10 +122,11 @@ END2END_NOSEC_FIXTURES = {
client_channel = False, client_channel = False,
secure = False, secure = False,
_platforms = ["linux", "mac", "posix"], _platforms = ["linux", "mac", "posix"],
supports_msvc = False,
), ),
"h2_full": _fixture_options(secure = False), "h2_full": _fixture_options(secure = False),
"h2_full+pipe": _fixture_options(secure = False, _platforms = ["linux"]), "h2_full+pipe": _fixture_options(secure = False, _platforms = ["linux"], supports_msvc = False),
"h2_full+trace": _fixture_options(secure = False, tracing = True), "h2_full+trace": _fixture_options(secure = False, tracing = True, supports_msvc = False),
"h2_full+workarounds": _fixture_options(secure = False), "h2_full+workarounds": _fixture_options(secure = False),
"h2_http_proxy": _fixture_options(secure = False, supports_proxy_auth = True), "h2_http_proxy": _fixture_options(secure = False, supports_proxy_auth = True),
"h2_proxy": _fixture_options(secure = False, includes_proxy = True), "h2_proxy": _fixture_options(secure = False, includes_proxy = True),
@ -152,6 +155,7 @@ END2END_NOSEC_FIXTURES = {
dns_resolver = False, dns_resolver = False,
_platforms = ["linux", "mac", "posix"], _platforms = ["linux", "mac", "posix"],
secure = False, secure = False,
supports_msvc = False,
), ),
} }
@ -463,4 +467,5 @@ def grpc_end2end_nosec_tests():
t, t,
poller, poller,
], ],
tags = ["no_windows"],
) )

@ -81,6 +81,7 @@ grpc_cc_test(
"//:grpc", "//:grpc",
"//test/core/util:grpc_test_util", "//test/core/util:grpc_test_util",
], ],
tags = ["no_windows"],
) )
grpc_cc_test( grpc_cc_test(
@ -92,6 +93,7 @@ grpc_cc_test(
"//:grpc", "//:grpc",
"//test/core/util:grpc_test_util", "//test/core/util:grpc_test_util",
], ],
tags = ["no_windows"],
) )
grpc_cc_test( grpc_cc_test(
@ -103,6 +105,7 @@ grpc_cc_test(
"//:grpc", "//:grpc",
"//test/core/util:grpc_test_util", "//test/core/util:grpc_test_util",
], ],
tags = ["no_windows"],
) )
grpc_cc_test( grpc_cc_test(
@ -139,6 +142,7 @@ grpc_cc_test(
"//:grpc", "//:grpc",
"//test/core/util:grpc_test_util", "//test/core/util:grpc_test_util",
], ],
tags = ["no_windows"],
) )
grpc_cc_test( grpc_cc_test(
@ -153,6 +157,7 @@ grpc_cc_test(
"//:grpc", "//:grpc",
"//test/core/util:grpc_test_util", "//test/core/util:grpc_test_util",
], ],
tags = ["no_windows"],
) )
grpc_cc_test( grpc_cc_test(
@ -214,6 +219,7 @@ grpc_cc_test(
"//:grpc", "//:grpc",
"//test/core/util:grpc_test_util", "//test/core/util:grpc_test_util",
], ],
tags = ["no_windows"],
) )
grpc_cc_test( grpc_cc_test(
@ -225,6 +231,7 @@ grpc_cc_test(
"//:grpc", "//:grpc",
"//test/core/util:grpc_test_util", "//test/core/util:grpc_test_util",
], ],
tags = ["no_windows"],
) )
grpc_cc_test( grpc_cc_test(
@ -237,6 +244,7 @@ grpc_cc_test(
"//:grpc", "//:grpc",
"//test/core/util:grpc_test_util", "//test/core/util:grpc_test_util",
], ],
tags = ["no_windows"],
) )
grpc_cc_test( grpc_cc_test(
@ -259,6 +267,7 @@ grpc_cc_test(
"//:grpc", "//:grpc",
"//test/core/util:grpc_test_util", "//test/core/util:grpc_test_util",
], ],
tags = ["no_windows"],
) )
grpc_cc_test( grpc_cc_test(
@ -303,4 +312,5 @@ grpc_cc_test(
"//:grpc", "//:grpc",
"//test/core/util:grpc_test_util", "//test/core/util:grpc_test_util",
], ],
tags = ["no_windows"],
) )

@ -28,6 +28,7 @@ grpc_cc_test(
"//:grpc++_unsecure", "//:grpc++_unsecure",
"//test/core/util:grpc_test_util_unsecure", "//test/core/util:grpc_test_util_unsecure",
], ],
tags = ["no_windows"],
) )
grpc_cc_test( grpc_cc_test(

@ -99,6 +99,7 @@ grpc_cc_test(
"//test/core/util:grpc_test_util", "//test/core/util:grpc_test_util",
"//test/cpp/util:test_util", "//test/cpp/util:test_util",
], ],
tags = ["no_windows"],
) )
grpc_cc_test( grpc_cc_test(
@ -633,6 +634,7 @@ grpc_cc_test(
"//test/core/util:grpc_test_util", "//test/core/util:grpc_test_util",
"//test/cpp/util:test_util", "//test/cpp/util:test_util",
], ],
tags = ["no_windows"],
) )
grpc_cc_test( grpc_cc_test(

@ -47,8 +47,10 @@
#include "test/cpp/end2end/test_service_impl.h" #include "test/cpp/end2end/test_service_impl.h"
#ifdef GRPC_CFSTREAM #ifdef GRPC_CFSTREAM
using grpc::ClientAsyncResponseReader;
using grpc::testing::EchoRequest; using grpc::testing::EchoRequest;
using grpc::testing::EchoResponse; using grpc::testing::EchoResponse;
using grpc::testing::RequestParams;
using std::chrono::system_clock; using std::chrono::system_clock;
namespace grpc { namespace grpc {
@ -60,8 +62,7 @@ class CFStreamTest : public ::testing::Test {
CFStreamTest() CFStreamTest()
: server_host_("grpctest"), : server_host_("grpctest"),
interface_("lo0"), interface_("lo0"),
ipv4_address_("10.0.0.1"), ipv4_address_("127.0.0.2"),
netmask_("/32"),
kRequestMessage_("🖖") {} kRequestMessage_("🖖") {}
void DNSUp() { void DNSUp() {
@ -92,11 +93,13 @@ class CFStreamTest : public ::testing::Test {
} }
void NetworkUp() { void NetworkUp() {
gpr_log(GPR_DEBUG, "Bringing network up");
InterfaceUp(); InterfaceUp();
DNSUp(); DNSUp();
} }
void NetworkDown() { void NetworkDown() {
gpr_log(GPR_DEBUG, "Bringing network down");
InterfaceDown(); InterfaceDown();
DNSDown(); DNSDown();
} }
@ -149,6 +152,27 @@ class CFStreamTest : public ::testing::Test {
EXPECT_TRUE(status.ok()); EXPECT_TRUE(status.ok());
} }
} }
void SendAsyncRpc(
const std::unique_ptr<grpc::testing::EchoTestService::Stub>& stub,
RequestParams param = RequestParams()) {
EchoRequest request;
auto msg = std::to_string(ctr.load());
request.set_message(msg);
ctr++;
*request.mutable_param() = std::move(param);
AsyncClientCall* call = new AsyncClientCall;
call->response_reader =
stub->PrepareAsyncEcho(&call->context, request, &cq_);
call->response_reader->StartCall();
gpr_log(GPR_DEBUG, "Sending request: %s", msg.c_str());
call->response_reader->Finish(&call->reply, &call->status, (void*)call);
}
void ShutdownCQ() { cq_.Shutdown(); }
bool CQNext(void** tag, bool* ok) { return cq_.Next(tag, ok); }
bool WaitForChannelNotReady(Channel* channel, int timeout_seconds = 5) { bool WaitForChannelNotReady(Channel* channel, int timeout_seconds = 5) {
const gpr_timespec deadline = const gpr_timespec deadline =
@ -172,6 +196,13 @@ class CFStreamTest : public ::testing::Test {
return true; return true;
} }
struct AsyncClientCall {
EchoResponse reply;
ClientContext context;
Status status;
std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader;
};
private: private:
struct ServerData { struct ServerData {
int port_; int port_;
@ -214,14 +245,14 @@ class CFStreamTest : public ::testing::Test {
} }
}; };
CompletionQueue cq_;
const grpc::string server_host_; const grpc::string server_host_;
const grpc::string interface_; const grpc::string interface_;
const grpc::string ipv4_address_; const grpc::string ipv4_address_;
const grpc::string netmask_;
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
std::unique_ptr<ServerData> server_; std::unique_ptr<ServerData> server_;
int port_; int port_;
const grpc::string kRequestMessage_; const grpc::string kRequestMessage_;
std::atomic_int ctr{0};
}; };
// gRPC should automatically detech network flaps (without enabling keepalives) // gRPC should automatically detech network flaps (without enabling keepalives)
@ -261,6 +292,117 @@ TEST_F(CFStreamTest, NetworkTransition) {
sender.join(); sender.join();
} }
// Network flaps while RPCs are in flight
TEST_F(CFStreamTest, NetworkFlapRpcsInFlight) {
auto channel = BuildChannel();
auto stub = BuildStub(channel);
std::atomic_int rpcs_sent{0};
// Channel should be in READY state after we send some RPCs
for (int i = 0; i < 10; ++i) {
SendAsyncRpc(stub);
++rpcs_sent;
}
EXPECT_TRUE(WaitForChannelReady(channel.get()));
// Bring down the network
NetworkDown();
std::thread thd = std::thread([this, &rpcs_sent]() {
void* got_tag;
bool ok = false;
bool network_down = true;
int total_completions = 0;
while (CQNext(&got_tag, &ok)) {
++total_completions;
GPR_ASSERT(ok);
AsyncClientCall* call = static_cast<AsyncClientCall*>(got_tag);
if (call->status.ok()) {
gpr_log(GPR_DEBUG, "RPC response: %s", call->reply.message().c_str());
} else {
gpr_log(GPR_DEBUG, "RPC failed with error: %s",
call->status.error_message().c_str());
// Bring network up when RPCs start failing
if (network_down) {
NetworkUp();
network_down = false;
}
}
delete call;
}
EXPECT_EQ(total_completions, rpcs_sent);
});
for (int i = 0; i < 100; ++i) {
SendAsyncRpc(stub);
std::this_thread::sleep_for(std::chrono::milliseconds(10));
++rpcs_sent;
}
ShutdownCQ();
thd.join();
}
// Send a bunch of RPCs, some of which are expected to fail.
// We should get back a response for all RPCs
TEST_F(CFStreamTest, ConcurrentRpc) {
auto channel = BuildChannel();
auto stub = BuildStub(channel);
std::atomic_int rpcs_sent{0};
std::thread thd = std::thread([this, &rpcs_sent]() {
void* got_tag;
bool ok = false;
bool network_down = true;
int total_completions = 0;
while (CQNext(&got_tag, &ok)) {
++total_completions;
GPR_ASSERT(ok);
AsyncClientCall* call = static_cast<AsyncClientCall*>(got_tag);
if (call->status.ok()) {
gpr_log(GPR_DEBUG, "RPC response: %s", call->reply.message().c_str());
} else {
gpr_log(GPR_DEBUG, "RPC failed: %s",
call->status.error_message().c_str());
// Bring network up when RPCs start failing
if (network_down) {
NetworkUp();
network_down = false;
}
}
delete call;
}
EXPECT_EQ(total_completions, rpcs_sent);
});
for (int i = 0; i < 10; ++i) {
if (i % 3 == 0) {
RequestParams param;
ErrorStatus* error = param.mutable_expected_error();
error->set_code(StatusCode::INTERNAL);
error->set_error_message("internal error");
SendAsyncRpc(stub, param);
} else if (i % 5 == 0) {
RequestParams param;
param.set_echo_metadata(true);
DebugInfo* info = param.mutable_debug_info();
info->add_stack_entries("stack_entry1");
info->add_stack_entries("stack_entry2");
info->set_detail("detailed debug info");
SendAsyncRpc(stub, param);
} else {
SendAsyncRpc(stub);
}
++rpcs_sent;
}
ShutdownCQ();
thd.join();
}
} // namespace } // namespace
} // namespace testing } // namespace testing
} // namespace grpc } // namespace grpc

@ -143,6 +143,7 @@ void LoopUntilCancelled(Alarm* alarm, ServerContext* context,
Status TestServiceImpl::Echo(ServerContext* context, const EchoRequest* request, Status TestServiceImpl::Echo(ServerContext* context, const EchoRequest* request,
EchoResponse* response) { EchoResponse* response) {
gpr_log(GPR_DEBUG, "Request message was %s", request->message().c_str());
// A bit of sleep to make sure that short deadline tests fail // A bit of sleep to make sure that short deadline tests fail
if (request->has_param() && request->param().server_sleep_us() > 0) { if (request->has_param() && request->param().server_sleep_us() > 0) {
gpr_sleep_until( gpr_sleep_until(

@ -161,4 +161,5 @@ grpc_cc_test(
"//test/cpp/util:test_config", "//test/cpp/util:test_config",
"//test/cpp/util:test_util", "//test/cpp/util:test_util",
], ],
tags = ["no_windows"],
) )

@ -45,6 +45,7 @@ grpc_cc_library(
"//test/core/util:grpc_test_util_unsecure", "//test/core/util:grpc_test_util_unsecure",
"//test/cpp/util:test_config", "//test/cpp/util:test_config",
], ],
tags = ["no_windows"],
) )
grpc_cc_binary( grpc_cc_binary(
@ -52,6 +53,7 @@ grpc_cc_binary(
testonly = 1, testonly = 1,
srcs = ["bm_closure.cc"], srcs = ["bm_closure.cc"],
deps = [":helpers"], deps = [":helpers"],
tags = ["no_windows"],
) )
grpc_cc_binary( grpc_cc_binary(
@ -59,6 +61,7 @@ grpc_cc_binary(
testonly = 1, testonly = 1,
srcs = ["bm_alarm.cc"], srcs = ["bm_alarm.cc"],
deps = [":helpers"], deps = [":helpers"],
tags = ["no_windows"],
) )
grpc_cc_binary( grpc_cc_binary(
@ -66,6 +69,7 @@ grpc_cc_binary(
testonly = 1, testonly = 1,
srcs = ["bm_arena.cc"], srcs = ["bm_arena.cc"],
deps = [":helpers"], deps = [":helpers"],
tags = ["no_windows"],
) )
grpc_cc_binary( grpc_cc_binary(
@ -73,6 +77,7 @@ grpc_cc_binary(
testonly = 1, testonly = 1,
srcs = ["bm_byte_buffer.cc"], srcs = ["bm_byte_buffer.cc"],
deps = [":helpers"], deps = [":helpers"],
tags = ["no_windows"],
) )
grpc_cc_binary( grpc_cc_binary(
@ -80,6 +85,7 @@ grpc_cc_binary(
testonly = 1, testonly = 1,
srcs = ["bm_channel.cc"], srcs = ["bm_channel.cc"],
deps = [":helpers"], deps = [":helpers"],
tags = ["no_windows"],
) )
grpc_cc_binary( grpc_cc_binary(
@ -87,6 +93,7 @@ grpc_cc_binary(
testonly = 1, testonly = 1,
srcs = ["bm_call_create.cc"], srcs = ["bm_call_create.cc"],
deps = [":helpers"], deps = [":helpers"],
tags = ["no_windows"],
) )
grpc_cc_binary( grpc_cc_binary(
@ -94,6 +101,7 @@ grpc_cc_binary(
testonly = 1, testonly = 1,
srcs = ["bm_cq.cc"], srcs = ["bm_cq.cc"],
deps = [":helpers"], deps = [":helpers"],
tags = ["no_windows"],
) )
grpc_cc_binary( grpc_cc_binary(
@ -101,6 +109,7 @@ grpc_cc_binary(
testonly = 1, testonly = 1,
srcs = ["bm_cq_multiple_threads.cc"], srcs = ["bm_cq_multiple_threads.cc"],
deps = [":helpers"], deps = [":helpers"],
tags = ["no_windows"],
) )
grpc_cc_binary( grpc_cc_binary(
@ -108,6 +117,7 @@ grpc_cc_binary(
testonly = 1, testonly = 1,
srcs = ["bm_error.cc"], srcs = ["bm_error.cc"],
deps = [":helpers"], deps = [":helpers"],
tags = ["no_windows"],
) )
grpc_cc_library( grpc_cc_library(
@ -117,6 +127,7 @@ grpc_cc_library(
"fullstack_streaming_ping_pong.h", "fullstack_streaming_ping_pong.h",
], ],
deps = [":helpers"], deps = [":helpers"],
tags = ["no_windows"],
) )
grpc_cc_binary( grpc_cc_binary(
@ -126,6 +137,7 @@ grpc_cc_binary(
"bm_fullstack_streaming_ping_pong.cc", "bm_fullstack_streaming_ping_pong.cc",
], ],
deps = [":fullstack_streaming_ping_pong_h"], deps = [":fullstack_streaming_ping_pong_h"],
tags = ["no_windows"],
) )
grpc_cc_library( grpc_cc_library(
@ -144,6 +156,7 @@ grpc_cc_binary(
"bm_fullstack_streaming_pump.cc", "bm_fullstack_streaming_pump.cc",
], ],
deps = [":fullstack_streaming_pump_h"], deps = [":fullstack_streaming_pump_h"],
tags = ["no_windows"],
) )
grpc_cc_binary( grpc_cc_binary(
@ -151,6 +164,7 @@ grpc_cc_binary(
testonly = 1, testonly = 1,
srcs = ["bm_fullstack_trickle.cc"], srcs = ["bm_fullstack_trickle.cc"],
deps = [":helpers"], deps = [":helpers"],
tags = ["no_windows"],
) )
grpc_cc_library( grpc_cc_library(
@ -169,6 +183,7 @@ grpc_cc_binary(
"bm_fullstack_unary_ping_pong.cc", "bm_fullstack_unary_ping_pong.cc",
], ],
deps = [":fullstack_unary_ping_pong_h"], deps = [":fullstack_unary_ping_pong_h"],
tags = ["no_windows"],
) )
grpc_cc_binary( grpc_cc_binary(
@ -176,6 +191,7 @@ grpc_cc_binary(
testonly = 1, testonly = 1,
srcs = ["bm_metadata.cc"], srcs = ["bm_metadata.cc"],
deps = [":helpers"], deps = [":helpers"],
tags = ["no_windows"],
) )
grpc_cc_binary( grpc_cc_binary(
@ -183,6 +199,7 @@ grpc_cc_binary(
testonly = 1, testonly = 1,
srcs = ["bm_chttp2_hpack.cc"], srcs = ["bm_chttp2_hpack.cc"],
deps = [":helpers"], deps = [":helpers"],
tags = ["no_windows"],
) )
grpc_cc_binary( grpc_cc_binary(
@ -202,4 +219,5 @@ grpc_cc_binary(
testonly = 1, testonly = 1,
srcs = ["bm_timer.cc"], srcs = ["bm_timer.cc"],
deps = [":helpers"], deps = [":helpers"],
tags = ["no_windows"],
) )

@ -33,6 +33,7 @@ def generate_resolver_component_tests():
"//:gpr", "//:gpr",
"//test/cpp/util:test_config", "//test/cpp/util:test_config",
], ],
tags = ["no_windows"],
) )
# meant to be invoked only through the top-level shell script driver # meant to be invoked only through the top-level shell script driver
grpc_cc_binary( grpc_cc_binary(
@ -52,6 +53,7 @@ def generate_resolver_component_tests():
"//:gpr", "//:gpr",
"//test/cpp/util:test_config", "//test/cpp/util:test_config",
], ],
tags = ["no_windows"],
) )
grpc_cc_test( grpc_cc_test(
name = "resolver_component_tests_runner_invoker%s" % unsecure_build_config_suffix, name = "resolver_component_tests_runner_invoker%s" % unsecure_build_config_suffix,
@ -77,5 +79,6 @@ def generate_resolver_component_tests():
args = [ args = [
"--test_bin_name=resolver_component_test%s" % unsecure_build_config_suffix, "--test_bin_name=resolver_component_test%s" % unsecure_build_config_suffix,
"--running_under_bazel=true", "--running_under_bazel=true",
] ],
tags = ["no_windows"],
) )

@ -31,4 +31,5 @@ grpc_cc_test(
"//src/proto/grpc/testing:echo_proto", "//src/proto/grpc/testing:echo_proto",
"//test/core/util:grpc_test_util_base", "//test/core/util:grpc_test_util_base",
], ],
tags = ["no_windows"],
) )

@ -75,5 +75,6 @@ def json_run_localhost_batch():
], ],
tags = [ tags = [
"json_run_localhost", "json_run_localhost",
"no_windows",
], ],
) )

@ -29,6 +29,7 @@ grpc_cc_test(
"//src/proto/grpc/testing:echo_proto", "//src/proto/grpc/testing:echo_proto",
"//test/core/util:grpc_test_util_unsecure", "//test/core/util:grpc_test_util_unsecure",
], ],
tags = ["no_windows"],
) )
grpc_cc_test( grpc_cc_test(
@ -42,6 +43,7 @@ grpc_cc_test(
"//src/proto/grpc/testing:echo_proto", "//src/proto/grpc/testing:echo_proto",
"//test/core/util:grpc_test_util_unsecure", "//test/core/util:grpc_test_util_unsecure",
], ],
tags = ["no_windows"],
) )
grpc_cc_test( grpc_cc_test(
@ -55,4 +57,5 @@ grpc_cc_test(
"//src/proto/grpc/testing:echo_proto", "//src/proto/grpc/testing:echo_proto",
"//test/core/util:grpc_test_util_unsecure", "//test/core/util:grpc_test_util_unsecure",
], ],
tags = ["no_windows"],
) )

@ -45,6 +45,7 @@ grpc_cc_test(
"//:lb_server_load_reporting_filter", "//:lb_server_load_reporting_filter",
"//test/core/util:grpc_test_util", "//test/core/util:grpc_test_util",
], ],
tags = ["no_windows"],
) )
grpc_cc_test( grpc_cc_test(

@ -44,14 +44,17 @@ ProtoReflectionDescriptorDatabase::~ProtoReflectionDescriptorDatabase() {
Status status = stream_->Finish(); Status status = stream_->Finish();
if (!status.ok()) { if (!status.ok()) {
if (status.error_code() == StatusCode::UNIMPLEMENTED) { if (status.error_code() == StatusCode::UNIMPLEMENTED) {
gpr_log(GPR_INFO, fprintf(stderr,
"Reflection request not implemented; " "Reflection request not implemented; "
"is the ServerReflection service enabled?"); "is the ServerReflection service enabled?\n");
} else {
fprintf(stderr,
"ServerReflectionInfo rpc failed. Error code: %d, message: %s, "
"debug info: %s\n",
static_cast<int>(status.error_code()),
status.error_message().c_str(),
ctx_.debug_error_string().c_str());
} }
gpr_log(GPR_INFO,
"ServerReflectionInfo rpc failed. Error code: %d, details: %s",
static_cast<int>(status.error_code()),
status.error_message().c_str());
} }
} }
} }

@ -12,7 +12,7 @@ and tests run by Kokoro CI.
- See [Installing Bazel](https://docs.bazel.build/versions/master/install.html) for instructions how to install bazel on your system. - See [Installing Bazel](https://docs.bazel.build/versions/master/install.html) for instructions how to install bazel on your system.
- Setup application default credentials for running remote builds by following [RBE Credentials Setup](https://cloud.google.com/remote-build-execution/docs/getting-started#set_credentials) - Setup application default credentials for running remote builds by following ["Set credentials" section.](https://cloud.google.com/remote-build-execution/docs/set-up/first-remote-build)
## Running remote build manually from dev workstation ## Running remote build manually from dev workstation
@ -29,5 +29,11 @@ Sanitizer runs (asan, msan, tsan, ubsan):
bazel --bazelrc=tools/remote_build/manual.bazelrc test --config=asan //test/... bazel --bazelrc=tools/remote_build/manual.bazelrc test --config=asan //test/...
``` ```
Run on Windows MSVC:
```
# local manual run only for C++ targets (RBE to be supported)
bazel --bazelrc=tools/remote_build/windows.bazelrc test //test/cpp/...
```
Available command line options can be found in Available command line options can be found in
[Bazel command line reference](https://docs.bazel.build/versions/master/command-line-reference.html) [Bazel command line reference](https://docs.bazel.build/versions/master/command-line-reference.html)

@ -0,0 +1,3 @@
# TODO(yfen): Merge with rbe_common.bazelrc and enable Windows RBE
build --test_tag_filters=-no_windows
build --build_tag_filters=-no_windows
Loading…
Cancel
Save