aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--examples/python/README.md11
-rw-r--r--grpc.def1
-rw-r--r--include/grpc/grpc.h3
-rw-r--r--src/compiler/csharp_generator.cc89
-rw-r--r--src/compiler/objective_c_generator.cc6
-rw-r--r--src/compiler/objective_c_plugin.cc6
-rw-r--r--src/compiler/python_generator.cc10
-rw-r--r--src/core/ext/census/grpc_filter.c4
-rw-r--r--src/core/ext/client_config/client_channel.c5
-rw-r--r--src/core/ext/client_config/subchannel.c6
-rw-r--r--src/core/ext/transport/chttp2/transport/chttp2_transport.c729
-rw-r--r--src/core/ext/transport/chttp2/transport/internal.h65
-rw-r--r--src/core/ext/transport/chttp2/transport/stream_lists.c8
-rw-r--r--src/core/lib/channel/channel_stack.c6
-rw-r--r--src/core/lib/channel/channel_stack.h11
-rw-r--r--src/core/lib/channel/compress_filter.c4
-rw-r--r--src/core/lib/channel/connected_channel.c7
-rw-r--r--src/core/lib/channel/http_client_filter.c4
-rw-r--r--src/core/lib/channel/http_server_filter.c4
-rw-r--r--src/core/lib/iomgr/iomgr.c6
-rw-r--r--src/core/lib/security/client_auth_filter.c4
-rw-r--r--src/core/lib/security/server_auth_filter.c4
-rw-r--r--src/core/lib/surface/call.c42
-rw-r--r--src/core/lib/surface/completion_queue.c4
-rw-r--r--src/core/lib/surface/init.c2
-rw-r--r--src/core/lib/surface/lame_client.c6
-rw-r--r--src/core/lib/surface/server.c4
-rw-r--r--src/core/lib/transport/transport.c5
-rw-r--r--src/core/lib/transport/transport.h12
-rw-r--r--src/core/lib/transport/transport_impl.h2
-rw-r--r--src/csharp/Grpc.Examples/MathGrpc.cs176
-rw-r--r--src/csharp/Grpc.HealthCheck/HealthGrpc.cs46
-rw-r--r--src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs106
-rw-r--r--src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs284
-rw-r--r--src/csharp/Grpc.IntegrationTesting/TestGrpc.cs296
-rw-r--r--src/node/ext/node_grpc.cc35
-rw-r--r--src/node/ext/server_credentials.cc4
-rw-r--r--src/node/index.js7
-rw-r--r--src/node/src/server.js34
-rw-r--r--src/node/test/surface_test.js56
-rw-r--r--src/python/grpcio/README.rst13
-rw-r--r--src/python/grpcio/grpc/_cython/imports.generated.c2
-rw-r--r--src/python/grpcio/grpc/_cython/imports.generated.h3
-rw-r--r--src/python/grpcio/tests/protoc_plugin/beta_python_plugin_test.py41
-rw-r--r--src/python/grpcio/tests/qps/__init__.py28
-rw-r--r--src/python/grpcio/tests/qps/benchmark_client.py186
-rw-r--r--src/python/grpcio/tests/qps/benchmark_server.py58
-rw-r--r--src/python/grpcio/tests/qps/client_runner.py104
-rw-r--r--src/python/grpcio/tests/qps/histogram.py85
-rw-r--r--src/python/grpcio/tests/qps/qps_worker.py60
-rw-r--r--src/python/grpcio/tests/qps/worker_server.py184
-rw-r--r--src/ruby/ext/grpc/rb_channel_credentials.c29
-rw-r--r--src/ruby/ext/grpc/rb_grpc_imports.generated.c2
-rw-r--r--src/ruby/ext/grpc/rb_grpc_imports.generated.h3
-rw-r--r--src/ruby/lib/grpc.rb11
-rw-r--r--templates/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile.template39
-rw-r--r--templates/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile.template39
-rw-r--r--templates/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile.template37
-rw-r--r--templates/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile.template37
-rw-r--r--templates/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile.template44
-rw-r--r--templates/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile.template39
-rw-r--r--templates/tools/dockerfile/interoptest/grpc_interop_php/Dockerfile.template64
-rw-r--r--templates/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile.template39
-rw-r--r--templates/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile.template39
-rw-r--r--test/core/channel/channel_stack_test.c6
-rw-r--r--test/core/end2end/tests/filter_causes_close.c4
-rw-r--r--test/cpp/interop/stress_interop_client.cc40
-rw-r--r--test/cpp/interop/stress_interop_client.h8
-rw-r--r--test/cpp/interop/stress_test.cc13
-rw-r--r--test/cpp/util/metrics_server.cc45
-rw-r--r--test/cpp/util/metrics_server.h40
-rwxr-xr-xtools/buildgen/plugins/expand_version.py4
-rw-r--r--tools/dockerfile/grpc_base/README.md11
-rw-r--r--tools/dockerfile/grpc_linuxbrew/Dockerfile62
-rw-r--r--tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile (renamed from tools/dockerfile/grpc_interop_csharp/Dockerfile)35
-rwxr-xr-xtools/dockerfile/interoptest/grpc_interop_csharp/build_interop.sh (renamed from tools/dockerfile/grpc_interop_csharp/build_interop.sh)0
-rw-r--r--tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile (renamed from tools/dockerfile/grpc_interop_cxx/Dockerfile)25
-rwxr-xr-xtools/dockerfile/interoptest/grpc_interop_cxx/build_interop.sh (renamed from tools/dockerfile/grpc_interop_cxx/build_interop.sh)0
-rw-r--r--tools/dockerfile/interoptest/grpc_interop_go/Dockerfile (renamed from tools/dockerfile/grpc_interop_go/Dockerfile)0
-rwxr-xr-xtools/dockerfile/interoptest/grpc_interop_go/build_interop.sh (renamed from tools/dockerfile/grpc_interop_go/build_interop.sh)0
-rw-r--r--tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile (renamed from tools/dockerfile/grpc_interop_http2/Dockerfile)0
-rwxr-xr-xtools/dockerfile/interoptest/grpc_interop_http2/build_interop.sh (renamed from tools/dockerfile/grpc_interop_http2/build_interop.sh)0
-rw-r--r--tools/dockerfile/interoptest/grpc_interop_java/Dockerfile (renamed from tools/dockerfile/grpc_interop_java/Dockerfile)12
-rwxr-xr-xtools/dockerfile/interoptest/grpc_interop_java/build_interop.sh (renamed from tools/dockerfile/grpc_interop_java/build_interop.sh)0
-rw-r--r--tools/dockerfile/interoptest/grpc_interop_node/Dockerfile (renamed from tools/dockerfile/grpc_interop_node/Dockerfile)32
-rwxr-xr-xtools/dockerfile/interoptest/grpc_interop_node/build_interop.sh (renamed from tools/dockerfile/grpc_interop_node/build_interop.sh)2
-rw-r--r--tools/dockerfile/interoptest/grpc_interop_php/Dockerfile (renamed from tools/dockerfile/grpc_interop_php/Dockerfile)43
-rwxr-xr-xtools/dockerfile/interoptest/grpc_interop_php/build_interop.sh (renamed from tools/dockerfile/grpc_interop_php/build_interop.sh)0
-rw-r--r--tools/dockerfile/interoptest/grpc_interop_python/Dockerfile (renamed from tools/dockerfile/grpc_interop_python/Dockerfile)41
-rwxr-xr-xtools/dockerfile/interoptest/grpc_interop_python/build_interop.sh (renamed from tools/dockerfile/grpc_interop_python/build_interop.sh)0
-rw-r--r--tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile (renamed from tools/dockerfile/grpc_interop_ruby/Dockerfile)36
-rwxr-xr-xtools/dockerfile/interoptest/grpc_interop_ruby/build_interop.sh (renamed from tools/dockerfile/grpc_interop_ruby/build_interop.sh)2
-rwxr-xr-xtools/gce/linux_performance_worker_init.sh2
-rwxr-xr-xtools/jenkins/build_interop_image.sh6
-rwxr-xr-xtools/jenkins/run_distribution.sh144
-rwxr-xr-xtools/jenkins/run_performance.sh2
-rwxr-xr-x[-rw-r--r--]tools/run_tests/performance/kill_workers.sh (renamed from tools/dockerfile/grpc_base/Dockerfile)53
-rwxr-xr-xtools/run_tests/performance/remote_host_prepare.sh7
-rwxr-xr-xtools/run_tests/performance/run_worker_python.sh35
-rw-r--r--tools/run_tests/performance/scenario_config.py123
-rwxr-xr-xtools/run_tests/run_interop_tests.py3
-rwxr-xr-xtools/run_tests/run_performance_tests.py28
-rw-r--r--tools/run_tests/stress_test/STRESS_CLIENT_SPEC.md4
-rw-r--r--tools/run_tests/stress_test/configs/asan.json3
-rw-r--r--tools/run_tests/stress_test/configs/opt-tsan-asan.json3
-rw-r--r--tools/run_tests/stress_test/configs/opt.json3
-rw-r--r--tools/run_tests/stress_test/configs/tsan.json3
107 files changed, 3309 insertions, 871 deletions
diff --git a/examples/python/README.md b/examples/python/README.md
index b57da8f642..9992baa842 100644
--- a/examples/python/README.md
+++ b/examples/python/README.md
@@ -8,12 +8,19 @@ For this sample, we've already generated the server and client stubs from
Install gRPC:
- ```sh
+```sh
$ pip install grpcio
```
Or, to install it system wide:
```sh
- $ sudo pip install grpcio
+ $ sudo pip install grpcio
+```
+
+If you're on Windows, make sure you installed the `pip.exe` component when you
+installed Python. Invoke as above but with `pip.exe` instead of `pip` (you may
+also need to invoke from a `cmd.exe` ran as administrator):
+```sh
+ $ pip.exe install grpcio
```
Download the example
diff --git a/grpc.def b/grpc.def
index 6542c06a4b..61948ed1b8 100644
--- a/grpc.def
+++ b/grpc.def
@@ -86,6 +86,7 @@ EXPORTS
grpc_header_key_is_legal
grpc_header_nonbin_value_is_legal
grpc_is_binary_header
+ grpc_call_error_to_string
grpc_auth_property_iterator_next
grpc_auth_context_property_iterator
grpc_auth_context_peer_identity
diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h
index 5c868aece3..0ca28c0fef 100644
--- a/include/grpc/grpc.h
+++ b/include/grpc/grpc.h
@@ -384,6 +384,9 @@ GRPCAPI int grpc_header_nonbin_value_is_legal(const char *value, size_t length);
/** Check whether a metadata key corresponds to a binary value */
GRPCAPI int grpc_is_binary_header(const char *key, size_t length);
+/** Convert grpc_call_error values to a string */
+GRPCAPI const char *grpc_call_error_to_string(grpc_call_error error);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/compiler/csharp_generator.cc b/src/compiler/csharp_generator.cc
index 0d1404341d..ac0fee1ec4 100644
--- a/src/compiler/csharp_generator.cc
+++ b/src/compiler/csharp_generator.cc
@@ -52,6 +52,7 @@ using grpc::protobuf::MethodDescriptor;
using grpc::protobuf::io::Printer;
using grpc::protobuf::io::StringOutputStream;
using grpc_generator::MethodType;
+using grpc_generator::GetCppComments;
using grpc_generator::GetMethodType;
using grpc_generator::METHODTYPE_NO_STREAMING;
using grpc_generator::METHODTYPE_CLIENT_STREAMING;
@@ -65,6 +66,56 @@ using std::vector;
namespace grpc_csharp_generator {
namespace {
+// This function is a massaged version of
+// https://github.com/google/protobuf/blob/master/src/google/protobuf/compiler/csharp/csharp_doc_comment.cc
+// Currently, we cannot easily reuse the functionality as
+// google/protobuf/compiler/csharp/csharp_doc_comment.h is not a public header.
+// TODO(jtattermusch): reuse the functionality from google/protobuf.
+void GenerateDocCommentBodyImpl(grpc::protobuf::io::Printer* printer, grpc::protobuf::SourceLocation location) {
+ grpc::string comments = location.leading_comments.empty() ?
+ location.trailing_comments : location.leading_comments;
+ if (comments.empty()) {
+ return;
+ }
+ // XML escaping... no need for apostrophes etc as the whole text is going to be a child
+ // node of a summary element, not part of an attribute.
+ comments = grpc_generator::StringReplace(comments, "&", "&", true);
+ comments = grpc_generator::StringReplace(comments, "<", "&lt;", true);
+
+ std::vector<grpc::string> lines;
+ grpc_generator::Split(comments, '\n', &lines);
+ // TODO: We really should work out which part to put in the summary and which to put in the remarks...
+ // but that needs to be part of a bigger effort to understand the markdown better anyway.
+ printer->Print("/// <summary>\n");
+ bool last_was_empty = false;
+ // We squash multiple blank lines down to one, and remove any trailing blank lines. We need
+ // to preserve the blank lines themselves, as this is relevant in the markdown.
+ // Note that we can't remove leading or trailing whitespace as *that's* relevant in markdown too.
+ // (We don't skip "just whitespace" lines, either.)
+ for (std::vector<grpc::string>::iterator it = lines.begin(); it != lines.end(); ++it) {
+ grpc::string line = *it;
+ if (line.empty()) {
+ last_was_empty = true;
+ } else {
+ if (last_was_empty) {
+ printer->Print("///\n");
+ }
+ last_was_empty = false;
+ printer->Print("/// $line$\n", "line", *it);
+ }
+ }
+ printer->Print("/// </summary>\n");
+}
+
+template <typename DescriptorType>
+void GenerateDocCommentBody(
+ grpc::protobuf::io::Printer* printer, const DescriptorType* descriptor) {
+ grpc::protobuf::SourceLocation location;
+ if (descriptor->GetSourceLocation(&location)) {
+ GenerateDocCommentBodyImpl(printer, location);
+ }
+}
+
std::string GetServiceClassName(const ServiceDescriptor* service) {
return service->name();
}
@@ -242,7 +293,7 @@ void GenerateStaticMethodField(Printer* out, const MethodDescriptor *method) {
void GenerateServiceDescriptorProperty(Printer* out, const ServiceDescriptor *service) {
std::ostringstream index;
index << service->index();
- out->Print("// service descriptor\n");
+ out->Print("/// <summary>Service descriptor</summary>\n");
out->Print("public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor\n");
out->Print("{\n");
out->Print(" get { return $umbrella$.Descriptor.Services[$index$]; }\n",
@@ -253,7 +304,8 @@ void GenerateServiceDescriptorProperty(Printer* out, const ServiceDescriptor *se
}
void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
- out->Print("// client interface\n");
+ out->Print("/// <summary>Client for $servicename$</summary>\n",
+ "servicename", GetServiceClassName(service));
out->Print("[System.Obsolete(\"Client side interfaced will be removed "
"in the next release. Use client class directly.\")]\n");
out->Print("public interface $name$\n", "name",
@@ -266,6 +318,7 @@ void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
if (method_type == METHODTYPE_NO_STREAMING) {
// unary calls have an extra synchronous stub method
+ GenerateDocCommentBody(out, method);
out->Print(
"$response$ $methodname$($request$ request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));\n",
"methodname", method->name(), "request",
@@ -273,6 +326,7 @@ void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
GetClassName(method->output_type()));
// overload taking CallOptions as a param
+ GenerateDocCommentBody(out, method);
out->Print(
"$response$ $methodname$($request$ request, CallOptions options);\n",
"methodname", method->name(), "request",
@@ -284,6 +338,7 @@ void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
if (method_type == METHODTYPE_NO_STREAMING) {
method_name += "Async"; // prevent name clash with synchronous method.
}
+ GenerateDocCommentBody(out, method);
out->Print(
"$returntype$ $methodname$($request_maybe$Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));\n",
"methodname", method_name, "request_maybe",
@@ -291,6 +346,7 @@ void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
GetMethodReturnTypeClient(method));
// overload taking CallOptions as a param
+ GenerateDocCommentBody(out, method);
out->Print(
"$returntype$ $methodname$($request_maybe$CallOptions options);\n",
"methodname", method_name, "request_maybe",
@@ -303,7 +359,8 @@ void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
}
void GenerateServerInterface(Printer* out, const ServiceDescriptor *service) {
- out->Print("// server-side interface\n");
+ out->Print("/// <summary>Interface of server-side implementations of $servicename$</summary>\n",
+ "servicename", GetServiceClassName(service));
out->Print("[System.Obsolete(\"Service implementations should inherit"
" from the generated abstract base class instead.\")]\n");
out->Print("public interface $name$\n", "name",
@@ -312,6 +369,7 @@ void GenerateServerInterface(Printer* out, const ServiceDescriptor *service) {
out->Indent();
for (int i = 0; i < service->method_count(); i++) {
const MethodDescriptor *method = service->method(i);
+ GenerateDocCommentBody(out, method);
out->Print(
"$returntype$ $methodname$($request$$response_stream_maybe$, "
"ServerCallContext context);\n",
@@ -326,13 +384,15 @@ void GenerateServerInterface(Printer* out, const ServiceDescriptor *service) {
}
void GenerateServerClass(Printer* out, const ServiceDescriptor *service) {
- out->Print("// server-side abstract class\n");
+ out->Print("/// <summary>Base class for server-side implementations of $servicename$</summary>\n",
+ "servicename", GetServiceClassName(service));
out->Print("public abstract class $name$\n", "name",
GetServerClassName(service));
out->Print("{\n");
out->Indent();
for (int i = 0; i < service->method_count(); i++) {
const MethodDescriptor *method = service->method(i);
+ GenerateDocCommentBody(out, method);
out->Print(
"public virtual $returntype$ $methodname$($request$$response_stream_maybe$, "
"ServerCallContext context)\n",
@@ -353,7 +413,8 @@ void GenerateServerClass(Printer* out, const ServiceDescriptor *service) {
}
void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
- out->Print("// client stub\n");
+ out->Print("/// <summary>Client for $servicename$</summary>\n",
+ "servicename", GetServiceClassName(service));
out->Print("#pragma warning disable 0618\n");
out->Print(
"public class $name$ : ClientBase<$name$>, $interface$\n",
@@ -392,6 +453,7 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
if (method_type == METHODTYPE_NO_STREAMING) {
// unary calls have an extra synchronous stub method
+ GenerateDocCommentBody(out, method);
out->Print("public virtual $response$ $methodname$($request$ request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))\n",
"methodname", method->name(), "request",
GetClassName(method->input_type()), "response",
@@ -404,6 +466,7 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
out->Print("}\n");
// overload taking CallOptions as a param
+ GenerateDocCommentBody(out, method);
out->Print("public virtual $response$ $methodname$($request$ request, CallOptions options)\n",
"methodname", method->name(), "request",
GetClassName(method->input_type()), "response",
@@ -420,6 +483,7 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
if (method_type == METHODTYPE_NO_STREAMING) {
method_name += "Async"; // prevent name clash with synchronous method.
}
+ GenerateDocCommentBody(out, method);
out->Print(
"public virtual $returntype$ $methodname$($request_maybe$Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))\n",
"methodname", method_name, "request_maybe",
@@ -435,6 +499,7 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
out->Print("}\n");
// overload taking CallOptions as a param
+ GenerateDocCommentBody(out, method);
out->Print(
"public virtual $returntype$ $methodname$($request_maybe$CallOptions options)\n",
"methodname", method_name, "request_maybe",
@@ -485,7 +550,7 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
void GenerateBindServiceMethod(Printer* out, const ServiceDescriptor *service,
bool use_server_class) {
out->Print(
- "// creates service definition that can be registered with a server\n");
+ "/// <summary>Creates service definition that can be registered with a server</summary>\n");
out->Print("#pragma warning disable 0618\n");
out->Print(
"public static ServerServiceDefinition BindService($interface$ serviceImpl)\n",
@@ -519,7 +584,8 @@ void GenerateBindServiceMethod(Printer* out, const ServiceDescriptor *service,
}
void GenerateNewStubMethods(Printer* out, const ServiceDescriptor *service) {
- out->Print("// creates a new client\n");
+ out->Print("/// <summary>Creates a new client for $servicename$</summary>\n",
+ "servicename", GetServiceClassName(service));
out->Print("public static $classname$ NewClient(Channel channel)\n",
"classname", GetClientClassName(service));
out->Print("{\n");
@@ -534,6 +600,7 @@ void GenerateNewStubMethods(Printer* out, const ServiceDescriptor *service) {
void GenerateService(Printer* out, const ServiceDescriptor *service,
bool generate_client, bool generate_server,
bool internal_access) {
+ GenerateDocCommentBody(out, service);
out->Print("$access_level$ static class $classname$\n", "access_level",
GetAccessLevel(internal_access), "classname",
GetServiceClassName(service));
@@ -590,6 +657,14 @@ grpc::string GetServices(const FileDescriptor *file, bool generate_client,
// Write out a file header.
out.Print("// Generated by the protocol buffer compiler. DO NOT EDIT!\n");
out.Print("// source: $filename$\n", "filename", file->name());
+
+ // use C++ style as there are no file-level XML comments in .NET
+ grpc::string leading_comments = GetCppComments(file, true);
+ if (!leading_comments.empty()) {
+ out.Print("// Original file comments:\n");
+ out.Print(leading_comments.c_str());
+ }
+
out.Print("#region Designer generated code\n");
out.Print("\n");
out.Print("using System;\n");
diff --git a/src/compiler/objective_c_generator.cc b/src/compiler/objective_c_generator.cc
index ff092053ad..465491e385 100644
--- a/src/compiler/objective_c_generator.cc
+++ b/src/compiler/objective_c_generator.cc
@@ -75,11 +75,11 @@ void PrintMethodSignature(Printer *printer, const MethodDescriptor *method,
if (method->server_streaming()) {
printer->Print(vars,
" eventHandler:(void(^)(BOOL done, "
- "$response_class$ *response, NSError *error))eventHandler");
+ "$response_class$ *_Nullable response, NSError *_Nullable error))eventHandler");
} else {
printer->Print(vars,
- " handler:(void(^)($response_class$ *response, "
- "NSError *error))handler");
+ " handler:(void(^)($response_class$ *_Nullable response, "
+ "NSError *_Nullable error))handler");
}
}
diff --git a/src/compiler/objective_c_plugin.cc b/src/compiler/objective_c_plugin.cc
index 17440358bb..3ccfd5b037 100644
--- a/src/compiler/objective_c_plugin.cc
+++ b/src/compiler/objective_c_plugin.cc
@@ -81,8 +81,12 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
declarations += grpc_objective_c_generator::GetHeader(service);
}
+ static const ::grpc::string kNonNullBegin = "\nNS_ASSUME_NONNULL_BEGIN\n\n";
+ static const ::grpc::string kNonNullEnd = "\nNS_ASSUME_NONNULL_END\n";
+
Write(context, file_name + ".pbrpc.h",
- imports + '\n' + proto_imports + '\n' + declarations);
+ imports + '\n' + proto_imports + '\n' + kNonNullBegin +
+ declarations + kNonNullEnd);
}
{
diff --git a/src/compiler/python_generator.cc b/src/compiler/python_generator.cc
index 02c032800b..59137e1c92 100644
--- a/src/compiler/python_generator.cc
+++ b/src/compiler/python_generator.cc
@@ -190,7 +190,7 @@ bool PrintBetaServicer(const ServiceDescriptor* service,
"Documentation", doc,
});
out->Print("\n");
- out->Print(dict, "class Beta$Service$Servicer(six.with_metaclass(abc.ABCMeta, object)):\n");
+ out->Print(dict, "class Beta$Service$Servicer(object):\n");
{
IndentScope raii_class_indent(out);
out->Print(dict, "\"\"\"$Documentation$\"\"\"\n");
@@ -198,12 +198,11 @@ bool PrintBetaServicer(const ServiceDescriptor* service,
auto meth = service->method(i);
grpc::string arg_name = meth->client_streaming() ?
"request_iterator" : "request";
- out->Print("@abc.abstractmethod\n");
out->Print("def $Method$(self, $ArgName$, context):\n",
"Method", meth->name(), "ArgName", arg_name);
{
IndentScope raii_method_indent(out);
- out->Print("raise NotImplementedError()\n");
+ out->Print("context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)\n");
}
}
}
@@ -218,7 +217,7 @@ bool PrintBetaStub(const ServiceDescriptor* service,
"Documentation", doc,
});
out->Print("\n");
- out->Print(dict, "class Beta$Service$Stub(six.with_metaclass(abc.ABCMeta, object)):\n");
+ out->Print(dict, "class Beta$Service$Stub(object):\n");
{
IndentScope raii_class_indent(out);
out->Print(dict, "\"\"\"$Documentation$\"\"\"\n");
@@ -227,7 +226,6 @@ bool PrintBetaStub(const ServiceDescriptor* service,
grpc::string arg_name = meth->client_streaming() ?
"request_iterator" : "request";
auto methdict = ListToDict({"Method", meth->name(), "ArgName", arg_name});
- out->Print("@abc.abstractmethod\n");
out->Print(methdict, "def $Method$(self, $ArgName$, timeout):\n");
{
IndentScope raii_method_indent(out);
@@ -450,6 +448,8 @@ bool PrintPreamble(const FileDescriptor* file,
out->Print("import six\n");
out->Print("from $Package$ import implementations as beta_implementations\n",
"Package", config.beta_package_root);
+ out->Print("from $Package$ import interfaces as beta_interfaces\n",
+ "Package", config.beta_package_root);
out->Print("from grpc.framework.common import cardinality\n");
out->Print("from grpc.framework.interfaces.face import utilities as face_utilities\n");
return true;
diff --git a/src/core/ext/census/grpc_filter.c b/src/core/ext/census/grpc_filter.c
index abfb3bb5f0..5e278ef127 100644
--- a/src/core/ext/census/grpc_filter.c
+++ b/src/core/ext/census/grpc_filter.c
@@ -134,7 +134,7 @@ static void client_init_call_elem(grpc_exec_ctx *exec_ctx,
}
static void client_destroy_call_elem(grpc_exec_ctx *exec_ctx,
- grpc_call_element *elem) {
+ grpc_call_element *elem, void *ignored) {
call_data *d = elem->call_data;
GPR_ASSERT(d != NULL);
/* TODO(hongyu): record rpc client stats and census_rpc_end_op here */
@@ -152,7 +152,7 @@ static void server_init_call_elem(grpc_exec_ctx *exec_ctx,
}
static void server_destroy_call_elem(grpc_exec_ctx *exec_ctx,
- grpc_call_element *elem) {
+ grpc_call_element *elem, void *ignored) {
call_data *d = elem->call_data;
GPR_ASSERT(d != NULL);
/* TODO(hongyu): record rpc server stats and census_tracing_end_op here */
diff --git a/src/core/ext/client_config/client_channel.c b/src/core/ext/client_config/client_channel.c
index 8a98a6bcbe..9b5a078aec 100644
--- a/src/core/ext/client_config/client_channel.c
+++ b/src/core/ext/client_config/client_channel.c
@@ -415,9 +415,10 @@ static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
}
/* Destructor for call_data */
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
- grpc_call_element *elem) {
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+ void *and_free_memory) {
grpc_subchannel_call_holder_destroy(exec_ctx, elem->call_data);
+ gpr_free(and_free_memory);
}
/* Constructor for channel_data */
diff --git a/src/core/ext/client_config/subchannel.c b/src/core/ext/client_config/subchannel.c
index c925c28c67..3a5af9f53d 100644
--- a/src/core/ext/client_config/subchannel.c
+++ b/src/core/ext/client_config/subchannel.c
@@ -644,9 +644,9 @@ static void subchannel_call_destroy(grpc_exec_ctx *exec_ctx, void *call,
bool success) {
grpc_subchannel_call *c = call;
GPR_TIMER_BEGIN("grpc_subchannel_call_unref.destroy", 0);
- grpc_call_stack_destroy(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c));
- GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, c->connection, "subchannel_call");
- gpr_free(c);
+ grpc_connected_subchannel *connection = c->connection;
+ grpc_call_stack_destroy(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c), c);
+ GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, connection, "subchannel_call");
GPR_TIMER_END("grpc_subchannel_call_unref.destroy", 0);
}
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
index 01507f5ca6..fcf2abfe66 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
@@ -81,27 +81,25 @@ int grpc_flowctl_trace = 0;
static const grpc_transport_vtable vtable;
-static void lock(grpc_chttp2_transport *t);
-static void unlock(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t);
-
/* forward declarations of various callbacks that we'll build closures around */
static void writing_action(grpc_exec_ctx *exec_ctx, void *t,
bool iomgr_success_ignored);
+static void reading_action(grpc_exec_ctx *exec_ctx, void *t,
+ bool iomgr_success_ignored);
+static void parsing_action(grpc_exec_ctx *exec_ctx, void *t,
+ bool iomgr_success_ignored);
/** Set a transport level setting, and push it to our peer */
static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
uint32_t value);
-/** Endpoint callback to process incoming data */
-static void recv_data(grpc_exec_ctx *exec_ctx, void *tp, bool success);
-
/** Start disconnection chain */
static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t);
/** Perform a transport_op */
-static void perform_stream_op_locked(
- grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
- grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op);
+static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t,
+ grpc_chttp2_stream *s, void *transport_op);
/** Cancel a stream: coming from the transport API */
static void cancel_from_api(grpc_exec_ctx *exec_ctx,
@@ -118,15 +116,19 @@ static void close_from_api(grpc_exec_ctx *exec_ctx,
/** Add endpoint from this transport to pollset */
static void add_to_pollset_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
- grpc_pollset *pollset);
+ grpc_chttp2_stream *s_ignored, void *pollset);
static void add_to_pollset_set_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
- grpc_pollset_set *pollset_set);
+ grpc_chttp2_stream *s_ignored,
+ void *pollset_set);
/** Start new streams that have been created if we can */
static void maybe_start_some_streams(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global);
+static void finish_global_actions(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t);
+
static void connectivity_state_set(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
grpc_connectivity_state state, const char *reason);
@@ -138,7 +140,10 @@ static void incoming_byte_stream_update_flow_control(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global, size_t max_size_hint,
size_t have_already);
-
+static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t,
+ grpc_chttp2_stream *s,
+ void *byte_stream);
static void fail_pending_writes(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream_global *stream_global);
@@ -150,7 +155,7 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t) {
size_t i;
- gpr_mu_lock(&t->mu);
+ gpr_mu_lock(&t->executor.mu);
GPR_ASSERT(t->ep == NULL);
@@ -176,8 +181,8 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream_map_destroy(&t->new_stream_map);
grpc_connectivity_state_destroy(exec_ctx, &t->channel_callback.state_tracker);
- gpr_mu_unlock(&t->mu);
- gpr_mu_destroy(&t->mu);
+ gpr_mu_unlock(&t->executor.mu);
+ gpr_mu_destroy(&t->executor.mu);
/* callback remaining pings: they're not allowed to call into the transpot,
and maybe they hold resources that need to be freed */
@@ -238,7 +243,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
gpr_ref_init(&t->refs, 2);
/* ref is dropped at transport close() */
gpr_ref_init(&t->shutdown_ep_refs, 1);
- gpr_mu_init(&t->mu);
+ gpr_mu_init(&t->executor.mu);
t->peer_string = grpc_endpoint_get_peer(ep);
t->endpoint_reading = 1;
t->global.next_stream_id = is_client ? 1 : 2;
@@ -262,6 +267,8 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
gpr_slice_buffer_init(&t->writing.outbuf);
grpc_chttp2_hpack_compressor_init(&t->writing.hpack_compressor);
grpc_closure_init(&t->writing_action, writing_action, t);
+ grpc_closure_init(&t->reading_action, reading_action, t);
+ grpc_closure_init(&t->parsing_action, parsing_action, t);
gpr_slice_buffer_init(&t->parsing.qbuf);
grpc_chttp2_goaway_parser_init(&t->parsing.goaway_parser);
@@ -269,7 +276,6 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_closure_init(&t->writing.done_cb, grpc_chttp2_terminate_writing,
&t->writing);
- grpc_closure_init(&t->recv_data, recv_data, t);
gpr_slice_buffer_init(&t->read_buffer);
if (is_client) {
@@ -377,14 +383,18 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
}
}
-static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) {
- grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
-
- lock(t);
+static void destroy_transport_locked(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t,
+ grpc_chttp2_stream *s_ignored,
+ void *arg_ignored) {
t->destroying = 1;
drop_connection(exec_ctx, t);
- unlock(exec_ctx, t);
+}
+static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) {
+ grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
+ grpc_chttp2_run_with_global_lock(exec_ctx, t, NULL, destroy_transport_locked,
+ NULL, 0);
UNREF_TRANSPORT(exec_ctx, t, "destroy");
}
@@ -404,17 +414,6 @@ static void allow_endpoint_shutdown_locked(grpc_exec_ctx *exec_ctx,
}
}
-static void allow_endpoint_shutdown_unlocked(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t) {
- if (gpr_unref(&t->shutdown_ep_refs)) {
- gpr_mu_lock(&t->mu);
- if (t->ep) {
- grpc_endpoint_shutdown(exec_ctx, t->ep);
- }
- gpr_mu_unlock(&t->mu);
- }
-}
-
static void destroy_endpoint(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t) {
grpc_endpoint_destroy(exec_ctx, t->ep);
@@ -424,7 +423,9 @@ static void destroy_endpoint(grpc_exec_ctx *exec_ctx,
}
static void close_transport_locked(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t) {
+ grpc_chttp2_transport *t,
+ grpc_chttp2_stream *s_ignored,
+ void *arg_ignored) {
if (!t->closed) {
t->closed = 1;
connectivity_state_set(exec_ctx, &t->global, GRPC_CHANNEL_FATAL_FAILURE,
@@ -464,6 +465,13 @@ void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx,
}
#endif
+static void finish_init_stream_locked(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t,
+ grpc_chttp2_stream *s,
+ void *arg_ignored) {
+ grpc_chttp2_register_stream(t, s);
+}
+
static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
grpc_stream *gs, grpc_stream_refcount *refcount,
const void *server_data) {
@@ -473,6 +481,10 @@ static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
memset(s, 0, sizeof(*s));
s->refcount = refcount;
+ /* We reserve one 'active stream' that's dropped when the stream is
+ read-closed. The others are for incoming_byte_streams that are actively
+ reading */
+ gpr_ref_init(&s->global.active_streams, 1);
GRPC_CHTTP2_STREAM_REF(&s->global, "chttp2");
grpc_chttp2_incoming_metadata_buffer_init(&s->parsing.metadata_buffer[0]);
@@ -486,10 +498,8 @@ static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
REF_TRANSPORT(t, "stream");
- lock(t);
- grpc_chttp2_register_stream(t, s);
if (server_data) {
- GPR_ASSERT(t->parsing_active);
+ GPR_ASSERT(t->executor.parsing_active);
s->global.id = (uint32_t)(uintptr_t)server_data;
s->parsing.id = s->global.id;
s->global.outgoing_window =
@@ -502,40 +512,42 @@ static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
grpc_chttp2_stream_map_add(&t->parsing_stream_map, s->global.id, s);
s->global.in_stream_map = 1;
}
- unlock(exec_ctx, t);
+
+ grpc_chttp2_run_with_global_lock(exec_ctx, t, s, finish_init_stream_locked,
+ NULL, 0);
return 0;
}
-static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
- grpc_stream *gs) {
- grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
- grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
- int i;
+static void destroy_stream_locked(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t,
+ grpc_chttp2_stream *s, void *arg) {
grpc_byte_stream *bs;
GPR_TIMER_BEGIN("destroy_stream", 0);
- gpr_mu_lock(&t->mu);
-
GPR_ASSERT((s->global.write_closed && s->global.read_closed) ||
s->global.id == 0);
GPR_ASSERT(!s->global.in_stream_map);
if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) {
- close_transport_locked(exec_ctx, t);
+ close_transport_locked(exec_ctx, t, NULL, NULL);
}
- if (!t->parsing_active && s->global.id) {
+ if (!t->executor.parsing_active && s->global.id) {
GPR_ASSERT(grpc_chttp2_stream_map_find(&t->parsing_stream_map,
s->global.id) == NULL);
}
+ while (
+ (bs = grpc_chttp2_incoming_frame_queue_pop(&s->global.incoming_frames))) {
+ incoming_byte_stream_destroy_locked(exec_ctx, NULL, NULL, bs);
+ }
+
grpc_chttp2_list_remove_unannounced_incoming_window_available(&t->global,
&s->global);
grpc_chttp2_list_remove_stalled_by_transport(&t->global, &s->global);
+ grpc_chttp2_list_remove_check_read_ops(&t->global, &s->global);
- gpr_mu_unlock(&t->mu);
-
- for (i = 0; i < STREAM_LIST_COUNT; i++) {
+ for (int i = 0; i < STREAM_LIST_COUNT; i++) {
if (s->included[i]) {
gpr_log(GPR_ERROR, "%s stream %d still included in list %d",
t->global.is_client ? "client" : "server", s->global.id, i);
@@ -543,11 +555,6 @@ static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
}
}
- while (
- (bs = grpc_chttp2_incoming_frame_queue_pop(&s->global.incoming_frames))) {
- grpc_byte_stream_destroy(exec_ctx, bs);
- }
-
GPR_ASSERT(s->global.send_initial_metadata_finished == NULL);
GPR_ASSERT(s->global.send_message_finished == NULL);
GPR_ASSERT(s->global.send_trailing_metadata_finished == NULL);
@@ -566,6 +573,17 @@ static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
UNREF_TRANSPORT(exec_ctx, t, "stream");
GPR_TIMER_END("destroy_stream", 0);
+
+ gpr_free(arg);
+}
+
+static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
+ grpc_stream *gs, void *and_free_memory) {
+ grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
+ grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
+
+ grpc_chttp2_run_with_global_lock(exec_ctx, t, s, destroy_stream_locked,
+ and_free_memory, 0);
}
grpc_chttp2_stream_parsing *grpc_chttp2_parsing_lookup_stream(
@@ -594,28 +612,89 @@ grpc_chttp2_stream_parsing *grpc_chttp2_parsing_accept_stream(
* LOCK MANAGEMENT
*/
-/* We take a grpc_chttp2_transport-global lock in response to calls coming in
- from above,
- and in response to data being received from below. New data to be written
- is always queued, as are callbacks to process data. During unlock() we
- check our todo lists and initiate callbacks and flush writes. */
-
-static void lock(grpc_chttp2_transport *t) { gpr_mu_lock(&t->mu); }
-
-static void unlock(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) {
- GPR_TIMER_BEGIN("unlock", 0);
- if (!t->writing_active && !t->closed &&
- grpc_chttp2_unlocking_check_writes(exec_ctx, &t->global, &t->writing,
- t->parsing_active)) {
- t->writing_active = 1;
- REF_TRANSPORT(t, "writing");
- grpc_exec_ctx_enqueue(exec_ctx, &t->writing_action, true, NULL);
- prevent_endpoint_shutdown(t);
+static void finish_global_actions(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t) {
+ grpc_chttp2_executor_action_header *hdr;
+ grpc_chttp2_executor_action_header *next;
+
+ for (;;) {
+ if (!t->executor.writing_active && !t->closed &&
+ grpc_chttp2_unlocking_check_writes(exec_ctx, &t->global, &t->writing,
+ t->executor.parsing_active)) {
+ t->executor.writing_active = 1;
+ REF_TRANSPORT(t, "writing");
+ prevent_endpoint_shutdown(t);
+ grpc_exec_ctx_enqueue(exec_ctx, &t->writing_action, true, NULL);
+ }
+ check_read_ops(exec_ctx, &t->global);
+
+ gpr_mu_lock(&t->executor.mu);
+ if (t->executor.pending_actions != NULL) {
+ hdr = t->executor.pending_actions;
+ t->executor.pending_actions = NULL;
+ gpr_mu_unlock(&t->executor.mu);
+ while (hdr != NULL) {
+ hdr->action(exec_ctx, t, hdr->stream, hdr->arg);
+ next = hdr->next;
+ gpr_free(hdr);
+ UNREF_TRANSPORT(exec_ctx, t, "pending_action");
+ hdr = next;
+ }
+ continue;
+ } else {
+ t->executor.global_active = false;
+ }
+ gpr_mu_unlock(&t->executor.mu);
+ break;
+ }
+}
+
+void grpc_chttp2_run_with_global_lock(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t,
+ grpc_chttp2_stream *optional_stream,
+ grpc_chttp2_locked_action action,
+ void *arg, size_t sizeof_arg) {
+ grpc_chttp2_executor_action_header *hdr;
+
+ REF_TRANSPORT(t, "run_global");
+ gpr_mu_lock(&t->executor.mu);
+
+ for (;;) {
+ if (!t->executor.global_active) {
+ t->executor.global_active = 1;
+ gpr_mu_unlock(&t->executor.mu);
+
+ action(exec_ctx, t, optional_stream, arg);
+
+ finish_global_actions(exec_ctx, t);
+ } else {
+ gpr_mu_unlock(&t->executor.mu);
+
+ hdr = gpr_malloc(sizeof(*hdr) + sizeof_arg);
+ hdr->stream = optional_stream;
+ hdr->action = action;
+ if (sizeof_arg == 0) {
+ hdr->arg = arg;
+ } else {
+ hdr->arg = hdr + 1;
+ memcpy(hdr->arg, arg, sizeof_arg);
+ }
+
+ gpr_mu_lock(&t->executor.mu);
+ if (!t->executor.global_active) {
+ /* global lock was released while allocating memory: release & retry */
+ gpr_free(hdr);
+ continue;
+ }
+ hdr->next = t->executor.pending_actions;
+ t->executor.pending_actions = hdr;
+ REF_TRANSPORT(t, "pending_action");
+ gpr_mu_unlock(&t->executor.mu);
+ }
+ break;
}
- check_read_ops(exec_ctx, &t->global);
- gpr_mu_unlock(&t->mu);
- GPR_TIMER_END("unlock", 0);
+ UNREF_TRANSPORT(exec_ctx, t, "run_global");
}
/*******************************************************************************
@@ -645,15 +724,11 @@ static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
}
}
-void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx,
- void *transport_writing_ptr, bool success) {
- grpc_chttp2_transport_writing *transport_writing = transport_writing_ptr;
- grpc_chttp2_transport *t = TRANSPORT_FROM_WRITING(transport_writing);
- grpc_chttp2_stream_global *stream_global;
-
- GPR_TIMER_BEGIN("grpc_chttp2_terminate_writing", 0);
-
- lock(t);
+static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t,
+ grpc_chttp2_stream *s_ignored,
+ void *a) {
+ bool success = (bool)(uintptr_t)a;
allow_endpoint_shutdown_locked(exec_ctx, t);
@@ -663,24 +738,30 @@ void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx,
grpc_chttp2_cleanup_writing(exec_ctx, &t->global, &t->writing);
+ grpc_chttp2_stream_global *stream_global;
while (grpc_chttp2_list_pop_closed_waiting_for_writing(&t->global,
&stream_global)) {
fail_pending_writes(exec_ctx, stream_global);
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "finish_writes");
}
- /* leave the writing flag up on shutdown to prevent further writes in unlock()
+ /* leave the writing flag up on shutdown to prevent further writes in
+ unlock()
from starting */
- t->writing_active = 0;
+ t->executor.writing_active = 0;
if (t->ep && !t->endpoint_reading) {
destroy_endpoint(exec_ctx, t);
}
- unlock(exec_ctx, t);
-
UNREF_TRANSPORT(exec_ctx, t, "writing");
+}
- GPR_TIMER_END("grpc_chttp2_terminate_writing", 0);
+void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx,
+ void *transport_writing, bool success) {
+ grpc_chttp2_transport *t = TRANSPORT_FROM_WRITING(transport_writing);
+ grpc_chttp2_run_with_global_lock(exec_ctx, t, NULL,
+ terminate_writing_with_lock,
+ (void *)(uintptr_t)success, 0);
}
static void writing_action(grpc_exec_ctx *exec_ctx, void *gt,
@@ -806,14 +887,16 @@ static int contains_non_ok_status(
static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, bool success) {}
-static void perform_stream_op_locked(
- grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
- grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op) {
- grpc_closure *on_complete;
-
+static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t,
+ grpc_chttp2_stream *s, void *stream_op) {
GPR_TIMER_BEGIN("perform_stream_op_locked", 0);
- on_complete = op->on_complete;
+ grpc_transport_stream_op *op = stream_op;
+ grpc_chttp2_transport_global *transport_global = &t->global;
+ grpc_chttp2_stream_global *stream_global = &s->global;
+
+ grpc_closure *on_complete = op->on_complete;
if (on_complete == NULL) {
on_complete = grpc_closure_create(do_nothing, NULL);
}
@@ -938,10 +1021,8 @@ static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
grpc_stream *gs, grpc_transport_stream_op *op) {
grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
-
- lock(t);
- perform_stream_op_locked(exec_ctx, &t->global, &s->global, op);
- unlock(exec_ctx, t);
+ grpc_chttp2_run_with_global_lock(exec_ctx, t, s, perform_stream_op_locked, op,
+ sizeof(*op));
}
static void send_ping_locked(grpc_chttp2_transport *t, grpc_closure *on_recv) {
@@ -961,13 +1042,10 @@ static void send_ping_locked(grpc_chttp2_transport *t, grpc_closure *on_recv) {
gpr_slice_buffer_add(&t->global.qbuf, grpc_chttp2_ping_create(0, p->id));
}
-void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport_parsing *transport_parsing,
- const uint8_t *opaque_8bytes) {
+static void ack_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
+ grpc_chttp2_stream *s, void *opaque_8bytes) {
grpc_chttp2_outstanding_ping *ping;
- grpc_chttp2_transport *t = TRANSPORT_FROM_PARSING(transport_parsing);
grpc_chttp2_transport_global *transport_global = &t->global;
- lock(t);
for (ping = transport_global->pings.next; ping != &transport_global->pings;
ping = ping->next) {
if (0 == memcmp(opaque_8bytes, ping->id, 8)) {
@@ -978,13 +1056,31 @@ void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx,
break;
}
}
- unlock(exec_ctx, t);
+}
+
+void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport_parsing *transport_parsing,
+ const uint8_t *opaque_8bytes) {
+ grpc_chttp2_run_with_global_lock(
+ exec_ctx, TRANSPORT_FROM_PARSING(transport_parsing), NULL,
+ ack_ping_locked, (void *)opaque_8bytes, 8);
}
static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
- grpc_transport_op *op) {
- bool close_transport = false;
+ grpc_chttp2_stream *s_unused,
+ void *stream_op) {
+ grpc_transport_op *op = stream_op;
+ bool close_transport = op->disconnect;
+
+ /* If there's a set_accept_stream ensure that we're not parsing
+ to avoid changing things out from underneath */
+ if (t->executor.parsing_active && op->set_accept_stream) {
+ GPR_ASSERT(t->post_parsing_op == NULL);
+ t->post_parsing_op = gpr_malloc(sizeof(*op));
+ memcpy(t->post_parsing_op, op, sizeof(*op));
+ return;
+ }
grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, true, NULL);
@@ -1010,47 +1106,31 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
}
if (op->bind_pollset) {
- add_to_pollset_locked(exec_ctx, t, op->bind_pollset);
+ add_to_pollset_locked(exec_ctx, t, NULL, op->bind_pollset);
}
if (op->bind_pollset_set) {
- add_to_pollset_set_locked(exec_ctx, t, op->bind_pollset_set);
+ add_to_pollset_set_locked(exec_ctx, t, NULL, op->bind_pollset_set);
}
if (op->send_ping) {
send_ping_locked(t, op->send_ping);
}
- if (op->disconnect) {
- close_transport_locked(exec_ctx, t);
- }
-
if (close_transport) {
- close_transport_locked(exec_ctx, t);
+ close_transport_locked(exec_ctx, t, NULL, NULL);
}
}
static void perform_transport_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
grpc_transport_op *op) {
grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
-
- lock(t);
-
- /* If there's a set_accept_stream ensure that we're not parsing
- to avoid changing things out from underneath */
- if (t->parsing_active && op->set_accept_stream) {
- GPR_ASSERT(t->post_parsing_op == NULL);
- t->post_parsing_op = gpr_malloc(sizeof(*op));
- memcpy(t->post_parsing_op, op, sizeof(*op));
- } else {
- perform_transport_op_locked(exec_ctx, t, op);
- }
-
- unlock(exec_ctx, t);
+ grpc_chttp2_run_with_global_lock(
+ exec_ctx, t, NULL, perform_transport_op_locked, op, sizeof(*op));
}
/*******************************************************************************
- * INPUT PROCESSING
+ * INPUT PROCESSING - GENERAL
*/
static void check_read_ops(grpc_exec_ctx *exec_ctx,
@@ -1072,7 +1152,7 @@ static void check_read_ops(grpc_exec_ctx *exec_ctx,
while (stream_global->seen_error &&
(bs = grpc_chttp2_incoming_frame_queue_pop(
&stream_global->incoming_frames)) != NULL) {
- grpc_byte_stream_destroy(exec_ctx, bs);
+ incoming_byte_stream_destroy_locked(exec_ctx, NULL, NULL, bs);
}
if (stream_global->incoming_frames.head != NULL) {
*stream_global->recv_message = grpc_chttp2_incoming_frame_queue_pop(
@@ -1093,9 +1173,9 @@ static void check_read_ops(grpc_exec_ctx *exec_ctx,
while (stream_global->seen_error &&
(bs = grpc_chttp2_incoming_frame_queue_pop(
&stream_global->incoming_frames)) != NULL) {
- grpc_byte_stream_destroy(exec_ctx, bs);
+ incoming_byte_stream_destroy_locked(exec_ctx, NULL, NULL, bs);
}
- if (stream_global->incoming_frames.head == NULL) {
+ if (stream_global->all_incoming_byte_streams_finished) {
grpc_chttp2_incoming_metadata_buffer_publish(
&stream_global->received_trailing_metadata,
stream_global->recv_trailing_metadata);
@@ -1107,6 +1187,15 @@ static void check_read_ops(grpc_exec_ctx *exec_ctx,
}
}
+static void decrement_active_streams_locked(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
+ grpc_chttp2_stream_global *stream_global) {
+ if ((stream_global->all_incoming_byte_streams_finished =
+ gpr_unref(&stream_global->active_streams))) {
+ grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
+ }
+}
+
static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
uint32_t id) {
size_t new_stream_count;
@@ -1128,7 +1217,7 @@ static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
}
if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) {
- close_transport_locked(exec_ctx, t);
+ close_transport_locked(exec_ctx, t, NULL, NULL);
}
if (grpc_chttp2_list_remove_writable_stream(&t->global, &s->global)) {
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, &s->global, "chttp2_writing");
@@ -1229,10 +1318,11 @@ void grpc_chttp2_mark_stream_closed(
stream_global->read_closed = 1;
stream_global->published_initial_metadata = 1;
stream_global->published_trailing_metadata = 1;
+ decrement_active_streams_locked(exec_ctx, transport_global, stream_global);
}
if (close_writes && !stream_global->write_closed) {
stream_global->write_closed = 1;
- if (TRANSPORT_FROM_GLOBAL(transport_global)->writing_active) {
+ if (TRANSPORT_FROM_GLOBAL(transport_global)->executor.writing_active) {
GRPC_CHTTP2_STREAM_REF(stream_global, "finish_writes");
grpc_chttp2_list_add_closed_waiting_for_writing(transport_global,
stream_global);
@@ -1242,7 +1332,7 @@ void grpc_chttp2_mark_stream_closed(
}
if (stream_global->read_closed && stream_global->write_closed) {
if (stream_global->id != 0 &&
- TRANSPORT_FROM_GLOBAL(transport_global)->parsing_active) {
+ TRANSPORT_FROM_GLOBAL(transport_global)->executor.parsing_active) {
grpc_chttp2_list_add_closed_waiting_for_parsing(transport_global,
stream_global);
} else {
@@ -1374,7 +1464,7 @@ static void end_all_the_calls(grpc_exec_ctx *exec_ctx,
}
static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) {
- close_transport_locked(exec_ctx, t);
+ close_transport_locked(exec_ctx, t, NULL, NULL);
end_all_the_calls(exec_ctx, t);
}
@@ -1398,102 +1488,136 @@ static void update_global_window(void *args, uint32_t id, void *stream) {
}
}
-static void read_error_locked(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t) {
- t->endpoint_reading = 0;
- if (!t->writing_active && t->ep) {
- destroy_endpoint(exec_ctx, t);
- }
-}
+/*******************************************************************************
+ * INPUT PROCESSING - PARSING
+ */
-/* tcp read callback */
-static void recv_data(grpc_exec_ctx *exec_ctx, void *tp, bool success) {
- size_t i;
- int keep_reading = 0;
- grpc_chttp2_transport *t = tp;
+static void reading_action_locked(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t,
+ grpc_chttp2_stream *s_unused, void *arg);
+static void parsing_action(grpc_exec_ctx *exec_ctx, void *arg, bool success);
+static void post_reading_action_locked(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t,
+ grpc_chttp2_stream *s_unused, void *arg);
+static void post_parse_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
+ grpc_chttp2_stream *s_unused, void *arg);
+
+static void reading_action(grpc_exec_ctx *exec_ctx, void *tp, bool success) {
+ /* Control flow:
+ reading_action_locked ->
+ (parse_unlocked -> post_parse_locked)? ->
+ post_reading_action_locked */
+ grpc_chttp2_run_with_global_lock(exec_ctx, tp, NULL, reading_action_locked,
+ (void *)(uintptr_t)success, 0);
+}
+
+static void reading_action_locked(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t,
+ grpc_chttp2_stream *s_unused, void *arg) {
grpc_chttp2_transport_global *transport_global = &t->global;
grpc_chttp2_transport_parsing *transport_parsing = &t->parsing;
- grpc_chttp2_stream_global *stream_global;
+ bool success = (bool)(uintptr_t)arg;
- GPR_TIMER_BEGIN("recv_data", 0);
-
- lock(t);
- i = 0;
- GPR_ASSERT(!t->parsing_active);
+ GPR_ASSERT(!t->executor.parsing_active);
if (!t->closed) {
- t->parsing_active = 1;
+ t->executor.parsing_active = 1;
/* merge stream lists */
grpc_chttp2_stream_map_move_into(&t->new_stream_map,
&t->parsing_stream_map);
grpc_chttp2_prepare_to_read(transport_global, transport_parsing);
- gpr_mu_unlock(&t->mu);
- GPR_TIMER_BEGIN("recv_data.parse", 0);
- for (; i < t->read_buffer.count &&
- grpc_chttp2_perform_read(exec_ctx, transport_parsing,
- t->read_buffer.slices[i]);
- i++)
- ;
- GPR_TIMER_END("recv_data.parse", 0);
- gpr_mu_lock(&t->mu);
- /* copy parsing qbuf to global qbuf */
- gpr_slice_buffer_move_into(&t->parsing.qbuf, &t->global.qbuf);
- if (i != t->read_buffer.count) {
- unlock(exec_ctx, t);
- lock(t);
- drop_connection(exec_ctx, t);
- }
- /* merge stream lists */
- grpc_chttp2_stream_map_move_into(&t->new_stream_map,
- &t->parsing_stream_map);
- transport_global->concurrent_stream_count =
- (uint32_t)grpc_chttp2_stream_map_size(&t->parsing_stream_map);
- if (transport_parsing->initial_window_update != 0) {
- grpc_chttp2_stream_map_for_each(&t->parsing_stream_map,
- update_global_window, t);
- transport_parsing->initial_window_update = 0;
- }
- /* handle higher level things */
- grpc_chttp2_publish_reads(exec_ctx, transport_global, transport_parsing);
- t->parsing_active = 0;
- /* handle delayed transport ops (if there is one) */
- if (t->post_parsing_op) {
- grpc_transport_op *op = t->post_parsing_op;
- t->post_parsing_op = NULL;
- perform_transport_op_locked(exec_ctx, t, op);
- gpr_free(op);
- }
- /* if a stream is in the stream map, and gets cancelled, we need to ensure
- * we are not parsing before continuing the cancellation to keep things in
- * a sane state */
- while (grpc_chttp2_list_pop_closed_waiting_for_parsing(transport_global,
- &stream_global)) {
- GPR_ASSERT(stream_global->in_stream_map);
- GPR_ASSERT(stream_global->write_closed);
- GPR_ASSERT(stream_global->read_closed);
- remove_stream(exec_ctx, t, stream_global->id);
- GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2");
- }
+ grpc_exec_ctx_enqueue(exec_ctx, &t->parsing_action, success, NULL);
+ } else {
+ post_reading_action_locked(exec_ctx, t, s_unused, arg);
+ }
+}
+
+static void parsing_action(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+ grpc_chttp2_transport *t = arg;
+ GPR_TIMER_BEGIN("reading_action.parse", 0);
+ size_t i = 0;
+ for (; i < t->read_buffer.count &&
+ grpc_chttp2_perform_read(exec_ctx, &t->parsing,
+ t->read_buffer.slices[i]);
+ i++)
+ ;
+ if (i != t->read_buffer.count) {
+ success = false;
}
- if (!success || i != t->read_buffer.count || t->closed) {
+ GPR_TIMER_END("reading_action.parse", 0);
+ grpc_chttp2_run_with_global_lock(exec_ctx, t, NULL, post_parse_locked,
+ (void *)(uintptr_t)success, 0);
+}
+
+static void post_parse_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
+ grpc_chttp2_stream *s_unused, void *arg) {
+ grpc_chttp2_transport_global *transport_global = &t->global;
+ grpc_chttp2_transport_parsing *transport_parsing = &t->parsing;
+ /* copy parsing qbuf to global qbuf */
+ gpr_slice_buffer_move_into(&t->parsing.qbuf, &t->global.qbuf);
+ /* merge stream lists */
+ grpc_chttp2_stream_map_move_into(&t->new_stream_map, &t->parsing_stream_map);
+ transport_global->concurrent_stream_count =
+ (uint32_t)grpc_chttp2_stream_map_size(&t->parsing_stream_map);
+ if (transport_parsing->initial_window_update != 0) {
+ grpc_chttp2_stream_map_for_each(&t->parsing_stream_map,
+ update_global_window, t);
+ transport_parsing->initial_window_update = 0;
+ }
+ /* handle higher level things */
+ grpc_chttp2_publish_reads(exec_ctx, transport_global, transport_parsing);
+ t->executor.parsing_active = 0;
+ /* handle delayed transport ops (if there is one) */
+ if (t->post_parsing_op) {
+ grpc_transport_op *op = t->post_parsing_op;
+ t->post_parsing_op = NULL;
+ perform_transport_op_locked(exec_ctx, t, NULL, op);
+ gpr_free(op);
+ }
+ /* if a stream is in the stream map, and gets cancelled, we need to
+ * ensure we are not parsing before continuing the cancellation to keep
+ * things in a sane state */
+ grpc_chttp2_stream_global *stream_global;
+ while (grpc_chttp2_list_pop_closed_waiting_for_parsing(transport_global,
+ &stream_global)) {
+ GPR_ASSERT(stream_global->in_stream_map);
+ GPR_ASSERT(stream_global->write_closed);
+ GPR_ASSERT(stream_global->read_closed);
+ remove_stream(exec_ctx, t, stream_global->id);
+ GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2");
+ }
+
+ post_reading_action_locked(exec_ctx, t, s_unused, arg);
+}
+
+static void post_reading_action_locked(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t,
+ grpc_chttp2_stream *s_unused,
+ void *arg) {
+ bool success = (bool)(uintptr_t)arg;
+ bool keep_reading = false;
+ if (!success || t->closed) {
drop_connection(exec_ctx, t);
- read_error_locked(exec_ctx, t);
+ t->endpoint_reading = 0;
+ if (!t->executor.writing_active && t->ep) {
+ grpc_endpoint_destroy(exec_ctx, t->ep);
+ t->ep = NULL;
+ /* safe as we still have a ref for read */
+ UNREF_TRANSPORT(exec_ctx, t, "disconnect");
+ }
} else if (!t->closed) {
- keep_reading = 1;
+ keep_reading = true;
REF_TRANSPORT(t, "keep_reading");
prevent_endpoint_shutdown(t);
}
gpr_slice_buffer_reset_and_unref(&t->read_buffer);
- unlock(exec_ctx, t);
if (keep_reading) {
- grpc_endpoint_read(exec_ctx, t->ep, &t->read_buffer, &t->recv_data);
- allow_endpoint_shutdown_unlocked(exec_ctx, t);
+ grpc_endpoint_read(exec_ctx, t->ep, &t->read_buffer, &t->reading_action);
+ allow_endpoint_shutdown_locked(exec_ctx, t);
UNREF_TRANSPORT(exec_ctx, t, "keep_reading");
} else {
- UNREF_TRANSPORT(exec_ctx, t, "recv_data");
+ UNREF_TRANSPORT(exec_ctx, t, "reading_action");
}
-
- GPR_TIMER_END("recv_data", 0);
}
/*******************************************************************************
@@ -1517,7 +1641,7 @@ static void connectivity_state_set(
static void add_to_pollset_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
- grpc_pollset *pollset) {
+ grpc_chttp2_stream *s_unused, void *pollset) {
if (t->ep) {
grpc_endpoint_add_to_pollset(exec_ctx, t->ep, pollset);
}
@@ -1525,7 +1649,8 @@ static void add_to_pollset_locked(grpc_exec_ctx *exec_ctx,
static void add_to_pollset_set_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
- grpc_pollset_set *pollset_set) {
+ grpc_chttp2_stream *s_unused,
+ void *pollset_set) {
if (t->ep) {
grpc_endpoint_add_to_pollset_set(exec_ctx, t->ep, pollset_set);
}
@@ -1533,16 +1658,24 @@ static void add_to_pollset_set_locked(grpc_exec_ctx *exec_ctx,
static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
grpc_stream *gs, grpc_pollset *pollset) {
- grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
- lock(t);
- add_to_pollset_locked(exec_ctx, t, pollset);
- unlock(exec_ctx, t);
+ /* TODO(ctiller): keep pollset alive */
+ grpc_chttp2_run_with_global_lock(exec_ctx, (grpc_chttp2_transport *)gt,
+ (grpc_chttp2_stream *)gs,
+ add_to_pollset_locked, pollset, 0);
}
/*******************************************************************************
* BYTE STREAM
*/
+static void incoming_byte_stream_unref(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_incoming_byte_stream *bs) {
+ if (gpr_unref(&bs->refs)) {
+ gpr_slice_buffer_destroy(&bs->slices);
+ gpr_free(bs);
+ }
+}
+
static void incoming_byte_stream_update_flow_control(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global, size_t max_size_hint,
@@ -1583,87 +1716,146 @@ static void incoming_byte_stream_update_flow_control(
}
}
-static int incoming_byte_stream_next(grpc_exec_ctx *exec_ctx,
- grpc_byte_stream *byte_stream,
- gpr_slice *slice, size_t max_size_hint,
- grpc_closure *on_complete) {
+typedef struct {
+ grpc_chttp2_incoming_byte_stream *byte_stream;
+ gpr_slice *slice;
+ size_t max_size_hint;
+ grpc_closure *on_complete;
+} incoming_byte_stream_next_arg;
+
+static void incoming_byte_stream_next_locked(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t,
+ grpc_chttp2_stream *s,
+ void *argp) {
+ incoming_byte_stream_next_arg *arg = argp;
grpc_chttp2_incoming_byte_stream *bs =
- (grpc_chttp2_incoming_byte_stream *)byte_stream;
+ (grpc_chttp2_incoming_byte_stream *)arg->byte_stream;
grpc_chttp2_transport_global *transport_global = &bs->transport->global;
grpc_chttp2_stream_global *stream_global = &bs->stream->global;
- lock(bs->transport);
if (bs->is_tail) {
- incoming_byte_stream_update_flow_control(transport_global, stream_global,
- max_size_hint, bs->slices.length);
+ incoming_byte_stream_update_flow_control(
+ transport_global, stream_global, arg->max_size_hint, bs->slices.length);
}
if (bs->slices.count > 0) {
- *slice = gpr_slice_buffer_take_first(&bs->slices);
- unlock(exec_ctx, bs->transport);
- return 1;
+ *arg->slice = gpr_slice_buffer_take_first(&bs->slices);
+ grpc_exec_ctx_enqueue(exec_ctx, arg->on_complete, true, NULL);
} else if (bs->failed) {
- grpc_exec_ctx_enqueue(exec_ctx, on_complete, false, NULL);
- unlock(exec_ctx, bs->transport);
- return 0;
+ grpc_exec_ctx_enqueue(exec_ctx, arg->on_complete, false, NULL);
} else {
- bs->on_next = on_complete;
- bs->next = slice;
- unlock(exec_ctx, bs->transport);
- return 0;
+ bs->on_next = arg->on_complete;
+ bs->next = arg->slice;
}
+ incoming_byte_stream_unref(exec_ctx, bs);
}
-static void incoming_byte_stream_unref(grpc_chttp2_incoming_byte_stream *bs) {
- if (gpr_unref(&bs->refs)) {
- gpr_slice_buffer_destroy(&bs->slices);
- gpr_free(bs);
- }
+static int incoming_byte_stream_next(grpc_exec_ctx *exec_ctx,
+ grpc_byte_stream *byte_stream,
+ gpr_slice *slice, size_t max_size_hint,
+ grpc_closure *on_complete) {
+ grpc_chttp2_incoming_byte_stream *bs =
+ (grpc_chttp2_incoming_byte_stream *)byte_stream;
+ incoming_byte_stream_next_arg arg = {bs, slice, max_size_hint, on_complete};
+ gpr_ref(&bs->refs);
+ grpc_chttp2_run_with_global_lock(exec_ctx, bs->transport, bs->stream,
+ incoming_byte_stream_next_locked, &arg,
+ sizeof(arg));
+ return 0;
+}
+
+static void incoming_byte_stream_destroy(grpc_exec_ctx *exec_ctx,
+ grpc_byte_stream *byte_stream);
+
+static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t,
+ grpc_chttp2_stream *s,
+ void *byte_stream) {
+ grpc_chttp2_incoming_byte_stream *bs = byte_stream;
+ GPR_ASSERT(bs->base.destroy == incoming_byte_stream_destroy);
+ decrement_active_streams_locked(exec_ctx, &bs->transport->global,
+ &bs->stream->global);
+ incoming_byte_stream_unref(exec_ctx, bs);
}
static void incoming_byte_stream_destroy(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *byte_stream) {
- incoming_byte_stream_unref((grpc_chttp2_incoming_byte_stream *)byte_stream);
+ grpc_chttp2_incoming_byte_stream *bs =
+ (grpc_chttp2_incoming_byte_stream *)byte_stream;
+ grpc_chttp2_run_with_global_lock(exec_ctx, bs->transport, bs->stream,
+ incoming_byte_stream_destroy_locked, bs, 0);
}
-void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_incoming_byte_stream *bs,
- gpr_slice slice) {
- gpr_mu_lock(&bs->transport->mu);
+typedef struct {
+ grpc_chttp2_incoming_byte_stream *byte_stream;
+ gpr_slice slice;
+} incoming_byte_stream_push_arg;
+
+static void incoming_byte_stream_push_locked(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t,
+ grpc_chttp2_stream *s,
+ void *argp) {
+ incoming_byte_stream_push_arg *arg = argp;
+ grpc_chttp2_incoming_byte_stream *bs = arg->byte_stream;
if (bs->on_next != NULL) {
- *bs->next = slice;
+ *bs->next = arg->slice;
grpc_exec_ctx_enqueue(exec_ctx, bs->on_next, true, NULL);
bs->on_next = NULL;
} else {
- gpr_slice_buffer_add(&bs->slices, slice);
+ gpr_slice_buffer_add(&bs->slices, arg->slice);
}
- gpr_mu_unlock(&bs->transport->mu);
+ incoming_byte_stream_unref(exec_ctx, bs);
+}
+
+void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_incoming_byte_stream *bs,
+ gpr_slice slice) {
+ incoming_byte_stream_push_arg arg = {bs, slice};
+ gpr_ref(&bs->refs);
+ grpc_chttp2_run_with_global_lock(exec_ctx, bs->transport, bs->stream,
+ incoming_byte_stream_push_locked, &arg,
+ sizeof(arg));
+}
+
+static void incoming_byte_stream_finished_failed_locked(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s,
+ void *argp) {
+ grpc_chttp2_incoming_byte_stream *bs = argp;
+ grpc_exec_ctx_enqueue(exec_ctx, bs->on_next, false, NULL);
+ bs->on_next = NULL;
+ bs->failed = 1;
+ incoming_byte_stream_unref(exec_ctx, bs);
+}
+
+static void incoming_byte_stream_finished_ok_locked(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t,
+ grpc_chttp2_stream *s,
+ void *argp) {
+ grpc_chttp2_incoming_byte_stream *bs = argp;
+ incoming_byte_stream_unref(exec_ctx, bs);
}
void grpc_chttp2_incoming_byte_stream_finished(
grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, int success,
int from_parsing_thread) {
- if (!success) {
- if (from_parsing_thread) {
- gpr_mu_lock(&bs->transport->mu);
- }
- grpc_exec_ctx_enqueue(exec_ctx, bs->on_next, false, NULL);
- bs->on_next = NULL;
- bs->failed = 1;
- if (from_parsing_thread) {
- gpr_mu_unlock(&bs->transport->mu);
+ if (from_parsing_thread) {
+ if (success) {
+ grpc_chttp2_run_with_global_lock(exec_ctx, bs->transport, bs->stream,
+ incoming_byte_stream_finished_ok_locked,
+ bs, 0);
+ } else {
+ incoming_byte_stream_finished_ok_locked(exec_ctx, bs->transport,
+ bs->stream, bs);
}
} else {
-#ifndef NDEBUG
- if (from_parsing_thread) {
- gpr_mu_lock(&bs->transport->mu);
- }
- GPR_ASSERT(bs->on_next == NULL);
- if (from_parsing_thread) {
- gpr_mu_unlock(&bs->transport->mu);
+ if (success) {
+ grpc_chttp2_run_with_global_lock(
+ exec_ctx, bs->transport, bs->stream,
+ incoming_byte_stream_finished_failed_locked, bs, 0);
+ } else {
+ incoming_byte_stream_finished_failed_locked(exec_ctx, bs->transport,
+ bs->stream, bs);
}
-#endif
}
- incoming_byte_stream_unref(bs);
}
grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create(
@@ -1680,6 +1872,7 @@ grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create(
incoming_byte_stream->next_message = NULL;
incoming_byte_stream->transport = TRANSPORT_FROM_PARSING(transport_parsing);
incoming_byte_stream->stream = STREAM_FROM_PARSING(stream_parsing);
+ gpr_ref(&incoming_byte_stream->stream->global.active_streams);
gpr_slice_buffer_init(&incoming_byte_stream->slices);
incoming_byte_stream->on_next = NULL;
incoming_byte_stream->is_tail = 1;
@@ -1810,7 +2003,7 @@ void grpc_chttp2_transport_start_reading(grpc_exec_ctx *exec_ctx,
grpc_transport *transport,
gpr_slice *slices, size_t nslices) {
grpc_chttp2_transport *t = (grpc_chttp2_transport *)transport;
- REF_TRANSPORT(t, "recv_data"); /* matches unref inside recv_data */
+ REF_TRANSPORT(t, "reading_action"); /* matches unref inside reading_action */
gpr_slice_buffer_addn(&t->read_buffer, slices, nslices);
- recv_data(exec_ctx, t, 1);
+ reading_action(exec_ctx, t, 1);
}
diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h
index 98cd38abd4..7a8084641d 100644
--- a/src/core/ext/transport/chttp2/transport/internal.h
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -291,27 +291,44 @@ struct grpc_chttp2_transport_parsing {
int64_t outgoing_window;
};
+typedef void (*grpc_chttp2_locked_action)(grpc_exec_ctx *ctx,
+ grpc_chttp2_transport *t,
+ grpc_chttp2_stream *s, void *arg);
+
+typedef struct grpc_chttp2_executor_action_header {
+ grpc_chttp2_stream *stream;
+ grpc_chttp2_locked_action action;
+ struct grpc_chttp2_executor_action_header *next;
+ void *arg;
+} grpc_chttp2_executor_action_header;
+
struct grpc_chttp2_transport {
grpc_transport base; /* must be first */
- grpc_endpoint *ep;
gpr_refcount refs;
+ grpc_endpoint *ep;
char *peer_string;
/** when this drops to zero it's safe to shutdown the endpoint */
gpr_refcount shutdown_ep_refs;
- gpr_mu mu;
+ struct {
+ gpr_mu mu;
+
+ /** is a thread currently in the global lock */
+ bool global_active;
+ /** is a thread currently writing */
+ bool writing_active;
+ /** is a thread currently parsing */
+ bool parsing_active;
+
+ grpc_chttp2_executor_action_header *pending_actions;
+ } executor;
/** is the transport destroying itself? */
uint8_t destroying;
/** has the upper layer closed the transport? */
uint8_t closed;
- /** is a thread currently writing */
- uint8_t writing_active;
- /** is a thread currently parsing */
- uint8_t parsing_active;
-
/** is there a read request to the endpoint outstanding? */
uint8_t endpoint_reading;
@@ -338,8 +355,10 @@ struct grpc_chttp2_transport {
/** closure to execute writing */
grpc_closure writing_action;
- /** closure to finish reading from the endpoint */
- grpc_closure recv_data;
+ /** closure to start reading from the endpoint */
+ grpc_closure reading_action;
+ /** closure to actually do parsing */
+ grpc_closure parsing_action;
/** incoming read bytes */
gpr_slice_buffer read_buffer;
@@ -397,21 +416,26 @@ typedef struct {
grpc_transport_stream_stats *collecting_stats;
grpc_transport_stream_stats stats;
+ /** number of streams that are currently being read */
+ gpr_refcount active_streams;
+
/** when the application requests writes be closed, the write_closed is
'queued'; when the close is flow controlled into the send path, we are
'sending' it; when the write has been performed it is 'sent' */
- uint8_t write_closed;
+ bool write_closed;
/** is this stream reading half-closed (boolean) */
- uint8_t read_closed;
+ bool read_closed;
+ /** are all published incoming byte streams closed */
+ bool all_incoming_byte_streams_finished;
/** is this stream in the stream map? (boolean) */
- uint8_t in_stream_map;
+ bool in_stream_map;
/** has this stream seen an error? if 1, then pending incoming frames
can be thrown away */
- uint8_t seen_error;
+ bool seen_error;
- uint8_t published_initial_metadata;
- uint8_t published_trailing_metadata;
- uint8_t faked_trailing_metadata;
+ bool published_initial_metadata;
+ bool published_trailing_metadata;
+ bool faked_trailing_metadata;
grpc_chttp2_incoming_metadata_buffer received_initial_metadata;
grpc_chttp2_incoming_metadata_buffer received_trailing_metadata;
@@ -570,6 +594,9 @@ int grpc_chttp2_list_pop_waiting_for_concurrency(
void grpc_chttp2_list_add_check_read_ops(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global);
+bool grpc_chttp2_list_remove_check_read_ops(
+ grpc_chttp2_transport_global *transport_global,
+ grpc_chttp2_stream_global *stream_global);
int grpc_chttp2_list_pop_check_read_ops(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global **stream_global);
@@ -645,6 +672,12 @@ void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream_global *stream_global,
grpc_closure **pclosure, int success);
+void grpc_chttp2_run_with_global_lock(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *transport,
+ grpc_chttp2_stream *optional_stream,
+ grpc_chttp2_locked_action action,
+ void *arg, size_t sizeof_arg);
+
#define GRPC_CHTTP2_CLIENT_CONNECT_STRING "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
#define GRPC_CHTTP2_CLIENT_CONNECT_STRLEN \
(sizeof(GRPC_CHTTP2_CLIENT_CONNECT_STRING) - 1)
diff --git a/src/core/ext/transport/chttp2/transport/stream_lists.c b/src/core/ext/transport/chttp2/transport/stream_lists.c
index e5b35aadca..8f3ab00e6d 100644
--- a/src/core/ext/transport/chttp2/transport/stream_lists.c
+++ b/src/core/ext/transport/chttp2/transport/stream_lists.c
@@ -305,6 +305,14 @@ void grpc_chttp2_list_add_check_read_ops(
GRPC_CHTTP2_LIST_CHECK_READ_OPS);
}
+bool grpc_chttp2_list_remove_check_read_ops(
+ grpc_chttp2_transport_global *transport_global,
+ grpc_chttp2_stream_global *stream_global) {
+ return stream_list_maybe_remove(TRANSPORT_FROM_GLOBAL(transport_global),
+ STREAM_FROM_GLOBAL(stream_global),
+ GRPC_CHTTP2_LIST_CHECK_READ_OPS);
+}
+
int grpc_chttp2_list_pop_check_read_ops(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global **stream_global) {
diff --git a/src/core/lib/channel/channel_stack.c b/src/core/lib/channel/channel_stack.c
index e36066d863..ad182d1f69 100644
--- a/src/core/lib/channel/channel_stack.c
+++ b/src/core/lib/channel/channel_stack.c
@@ -213,14 +213,16 @@ void grpc_call_stack_ignore_set_pollset(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
grpc_pollset *pollset) {}
-void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack) {
+void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack,
+ void *and_free_memory) {
grpc_call_element *elems = CALL_ELEMS_FROM_STACK(stack);
size_t count = stack->count;
size_t i;
/* destroy per-filter data */
for (i = 0; i < count; i++) {
- elems[i].filter->destroy_call_elem(exec_ctx, &elems[i]);
+ elems[i].filter->destroy_call_elem(exec_ctx, &elems[i],
+ i == count - 1 ? and_free_memory : NULL);
}
}
diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h
index 9e3a25a152..36c17cb467 100644
--- a/src/core/lib/channel/channel_stack.h
+++ b/src/core/lib/channel/channel_stack.h
@@ -104,8 +104,12 @@ typedef struct {
void (*set_pollset)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
grpc_pollset *pollset);
/* Destroy per call data.
- The filter does not need to do any chaining */
- void (*destroy_call_elem)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem);
+ The filter does not need to do any chaining.
+ The bottom filter of a stack will be passed a non-NULL pointer to
+ \a and_free_memory that should be passed to gpr_free when destruction
+ is complete. */
+ void (*destroy_call_elem)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+ void *and_free_memory);
/* sizeof(per channel data) */
size_t sizeof_channel_data;
@@ -223,7 +227,8 @@ void grpc_call_stack_set_pollset(grpc_exec_ctx *exec_ctx,
#endif
/* Destroy a call stack */
-void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack);
+void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack,
+ void *and_free_memory);
/* Ignore set pollset - used by filters to implement the set_pollset method
if they don't care about pollsets at all. Does nothing. */
diff --git a/src/core/lib/channel/compress_filter.c b/src/core/lib/channel/compress_filter.c
index 3d42d0e616..bac0811fd3 100644
--- a/src/core/lib/channel/compress_filter.c
+++ b/src/core/lib/channel/compress_filter.c
@@ -246,8 +246,8 @@ static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
}
/* Destructor for call_data */
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
- grpc_call_element *elem) {
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+ void *ignored) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
gpr_slice_buffer_destroy(&calld->slices);
diff --git a/src/core/lib/channel/connected_channel.c b/src/core/lib/channel/connected_channel.c
index c1debab4c6..68a3a7d6fd 100644
--- a/src/core/lib/channel/connected_channel.c
+++ b/src/core/lib/channel/connected_channel.c
@@ -102,12 +102,13 @@ static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
}
/* Destructor for call_data */
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
- grpc_call_element *elem) {
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+ void *and_free_memory) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
grpc_transport_destroy_stream(exec_ctx, chand->transport,
- TRANSPORT_STREAM_FROM_CALL_DATA(calld));
+ TRANSPORT_STREAM_FROM_CALL_DATA(calld),
+ and_free_memory);
}
/* Constructor for channel_data */
diff --git a/src/core/lib/channel/http_client_filter.c b/src/core/lib/channel/http_client_filter.c
index 211f537c69..516e708d1f 100644
--- a/src/core/lib/channel/http_client_filter.c
+++ b/src/core/lib/channel/http_client_filter.c
@@ -155,8 +155,8 @@ static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
}
/* Destructor for call_data */
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
- grpc_call_element *elem) {}
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+ void *ignored) {}
static grpc_mdelem *scheme_from_args(const grpc_channel_args *args) {
unsigned i;
diff --git a/src/core/lib/channel/http_server_filter.c b/src/core/lib/channel/http_server_filter.c
index 59dded6342..ba865416de 100644
--- a/src/core/lib/channel/http_server_filter.c
+++ b/src/core/lib/channel/http_server_filter.c
@@ -225,8 +225,8 @@ static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
}
/* Destructor for call_data */
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
- grpc_call_element *elem) {}
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+ void *ignored) {}
/* Constructor for channel_data */
static void init_channel_elem(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/lib/iomgr/iomgr.c b/src/core/lib/iomgr/iomgr.c
index 146663984d..60cef8ba77 100644
--- a/src/core/lib/iomgr/iomgr.c
+++ b/src/core/lib/iomgr/iomgr.c
@@ -166,8 +166,10 @@ bool grpc_iomgr_abort_on_leaks(void) {
if (env == NULL) return false;
static const char *truthy[] = {"yes", "Yes", "YES", "true",
"True", "TRUE", "1"};
+ bool should_we = false;
for (size_t i = 0; i < GPR_ARRAY_SIZE(truthy); i++) {
- if (0 == strcmp(env, truthy[i])) return true;
+ if (0 == strcmp(env, truthy[i])) should_we = true;
}
- return false;
+ gpr_free(env);
+ return should_we;
}
diff --git a/src/core/lib/security/client_auth_filter.c b/src/core/lib/security/client_auth_filter.c
index 943b1da85c..8b58cb86bf 100644
--- a/src/core/lib/security/client_auth_filter.c
+++ b/src/core/lib/security/client_auth_filter.c
@@ -277,8 +277,8 @@ static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
}
/* Destructor for call_data */
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
- grpc_call_element *elem) {
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+ void *ignored) {
call_data *calld = elem->call_data;
grpc_call_credentials_unref(calld->creds);
if (calld->host != NULL) {
diff --git a/src/core/lib/security/server_auth_filter.c b/src/core/lib/security/server_auth_filter.c
index 7844dc87cb..3320497d21 100644
--- a/src/core/lib/security/server_auth_filter.c
+++ b/src/core/lib/security/server_auth_filter.c
@@ -224,8 +224,8 @@ static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
grpc_pollset *pollset) {}
/* Destructor for call_data */
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
- grpc_call_element *elem) {}
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+ void *ignored) {}
/* Constructor for channel_data */
static void init_channel_elem(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c
index fa12b6ea61..9b2b94eedf 100644
--- a/src/core/lib/surface/call.c
+++ b/src/core/lib/surface/call.c
@@ -373,8 +373,6 @@ static void destroy_call(grpc_exec_ctx *exec_ctx, void *call, bool success) {
if (c->receiving_stream != NULL) {
grpc_byte_stream_destroy(exec_ctx, c->receiving_stream);
}
- grpc_call_stack_destroy(exec_ctx, CALL_STACK_FROM_CALL(c));
- GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, c->channel, "call");
gpr_mu_destroy(&c->mu);
for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
if (c->status[i].details) {
@@ -392,7 +390,9 @@ static void destroy_call(grpc_exec_ctx *exec_ctx, void *call, bool success) {
if (c->cq) {
GRPC_CQ_INTERNAL_UNREF(c->cq, "bind");
}
- gpr_free(c);
+ grpc_channel *channel = c->channel;
+ grpc_call_stack_destroy(exec_ctx, CALL_STACK_FROM_CALL(c), c);
+ GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel, "call");
GPR_TIMER_END("destroy_call", 0);
}
@@ -1517,3 +1517,39 @@ grpc_compression_algorithm grpc_call_compression_for_level(
gpr_mu_unlock(&call->mu);
return grpc_compression_algorithm_for_level(level, accepted_encodings);
}
+
+const char *grpc_call_error_to_string(grpc_call_error error) {
+ switch (error) {
+ case GRPC_CALL_ERROR:
+ return "GRPC_CALL_ERROR";
+ case GRPC_CALL_ERROR_ALREADY_ACCEPTED:
+ return "GRPC_CALL_ERROR_ALREADY_ACCEPTED";
+ case GRPC_CALL_ERROR_ALREADY_FINISHED:
+ return "GRPC_CALL_ERROR_ALREADY_FINISHED";
+ case GRPC_CALL_ERROR_ALREADY_INVOKED:
+ return "GRPC_CALL_ERROR_ALREADY_INVOKED";
+ case GRPC_CALL_ERROR_BATCH_TOO_BIG:
+ return "GRPC_CALL_ERROR_BATCH_TOO_BIG";
+ case GRPC_CALL_ERROR_INVALID_FLAGS:
+ return "GRPC_CALL_ERROR_INVALID_FLAGS";
+ case GRPC_CALL_ERROR_INVALID_MESSAGE:
+ return "GRPC_CALL_ERROR_INVALID_MESSAGE";
+ case GRPC_CALL_ERROR_INVALID_METADATA:
+ return "GRPC_CALL_ERROR_INVALID_METADATA";
+ case GRPC_CALL_ERROR_NOT_INVOKED:
+ return "GRPC_CALL_ERROR_NOT_INVOKED";
+ case GRPC_CALL_ERROR_NOT_ON_CLIENT:
+ return "GRPC_CALL_ERROR_NOT_ON_CLIENT";
+ case GRPC_CALL_ERROR_NOT_ON_SERVER:
+ return "GRPC_CALL_ERROR_NOT_ON_SERVER";
+ case GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE:
+ return "GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE";
+ case GRPC_CALL_ERROR_PAYLOAD_TYPE_MISMATCH:
+ return "GRPC_CALL_ERROR_PAYLOAD_TYPE_MISMATCH";
+ case GRPC_CALL_ERROR_TOO_MANY_OPERATIONS:
+ return "GRPC_CALL_ERROR_TOO_MANY_OPERATIONS";
+ case GRPC_CALL_OK:
+ return "GRPC_CALL_OK";
+ }
+ GPR_UNREACHABLE_CODE(return "GRPC_CALL_ERROR_UNKNOW");
+}
diff --git a/src/core/lib/surface/completion_queue.c b/src/core/lib/surface/completion_queue.c
index 5ec8808b50..1f82c3bad2 100644
--- a/src/core/lib/surface/completion_queue.c
+++ b/src/core/lib/surface/completion_queue.c
@@ -227,6 +227,10 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
#endif
GPR_TIMER_BEGIN("grpc_cq_end_op", 0);
+ GRPC_API_TRACE(
+ "grpc_cq_end_op(exec_ctx=%p, cc=%p, tag=%p, success=%d, done=%p, "
+ "done_arg=%p, storage=%p)",
+ 7, (exec_ctx, cc, tag, success, done, done_arg, storage));
storage->tag = tag;
storage->done = done;
diff --git a/src/core/lib/surface/init.c b/src/core/lib/surface/init.c
index 03f379aba8..d7ee122f87 100644
--- a/src/core/lib/surface/init.c
+++ b/src/core/lib/surface/init.c
@@ -167,7 +167,6 @@ void grpc_init(void) {
grpc_security_pre_init();
grpc_iomgr_init();
grpc_executor_init();
- grpc_tracer_init("GRPC_TRACE");
gpr_timers_global_init();
grpc_cq_global_init();
for (i = 0; i < g_number_of_plugins; i++) {
@@ -179,6 +178,7 @@ void grpc_init(void) {
* at the appropriate time */
grpc_register_security_filters();
register_builtin_channel_init();
+ grpc_tracer_init("GRPC_TRACE");
/* no more changes to channel init pipelines */
grpc_channel_init_finalize();
}
diff --git a/src/core/lib/surface/lame_client.c b/src/core/lib/surface/lame_client.c
index 80bd95df68..f50ec54cea 100644
--- a/src/core/lib/surface/lame_client.c
+++ b/src/core/lib/surface/lame_client.c
@@ -107,8 +107,10 @@ static void lame_start_transport_op(grpc_exec_ctx *exec_ctx,
static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
grpc_call_element_args *args) {}
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
- grpc_call_element *elem) {}
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+ void *and_free_memory) {
+ gpr_free(and_free_memory);
+}
static void init_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem,
diff --git a/src/core/lib/surface/server.c b/src/core/lib/surface/server.c
index ad8ee8c7a9..2db95b9cdf 100644
--- a/src/core/lib/surface/server.c
+++ b/src/core/lib/surface/server.c
@@ -820,8 +820,8 @@ static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
server_ref(chand->server);
}
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
- grpc_call_element *elem) {
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+ void *ignored) {
channel_data *chand = elem->channel_data;
call_data *calld = elem->call_data;
diff --git a/src/core/lib/transport/transport.c b/src/core/lib/transport/transport.c
index 53c634adca..e6d524abe6 100644
--- a/src/core/lib/transport/transport.c
+++ b/src/core/lib/transport/transport.c
@@ -133,8 +133,9 @@ void grpc_transport_set_pollset(grpc_exec_ctx *exec_ctx,
void grpc_transport_destroy_stream(grpc_exec_ctx *exec_ctx,
grpc_transport *transport,
- grpc_stream *stream) {
- transport->vtable->destroy_stream(exec_ctx, transport, stream);
+ grpc_stream *stream, void *and_free_memory) {
+ transport->vtable->destroy_stream(exec_ctx, transport, stream,
+ and_free_memory);
}
char *grpc_transport_get_peer(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h
index 1eb446312b..482a9d1791 100644
--- a/src/core/lib/transport/transport.h
+++ b/src/core/lib/transport/transport.h
@@ -98,6 +98,11 @@ void grpc_transport_move_stats(grpc_transport_stream_stats *from,
/* Transport stream op: a set of operations to perform on a transport
against a single stream */
typedef struct grpc_transport_stream_op {
+ /** Should be enqueued when all requested operations (excluding recv_message
+ and recv_initial_metadata which have their own closures) in a given batch
+ have been completed. */
+ grpc_closure *on_complete;
+
/** Send initial metadata to the peer, from the provided metadata batch.
idempotent_request MUST be set if this is non-null */
grpc_metadata_batch *send_initial_metadata;
@@ -129,11 +134,6 @@ typedef struct grpc_transport_stream_op {
/** Collect any stats into provided buffer, zero internal stat counters */
grpc_transport_stream_stats *collect_stats;
- /** Should be enqueued when all requested operations (excluding recv_message
- and recv_initial_metadata which have their own closures) in a given batch
- have been completed. */
- grpc_closure *on_complete;
-
/** If != GRPC_STATUS_OK, cancel this stream */
grpc_status_code cancel_with_status;
@@ -213,7 +213,7 @@ void grpc_transport_set_pollset(grpc_exec_ctx *exec_ctx,
caller, but any child memory must be cleaned up) */
void grpc_transport_destroy_stream(grpc_exec_ctx *exec_ctx,
grpc_transport *transport,
- grpc_stream *stream);
+ grpc_stream *stream, void *and_free_memory);
void grpc_transport_stream_op_finish_with_failure(grpc_exec_ctx *exec_ctx,
grpc_transport_stream_op *op);
diff --git a/src/core/lib/transport/transport_impl.h b/src/core/lib/transport/transport_impl.h
index 2ff67073af..956155eec8 100644
--- a/src/core/lib/transport/transport_impl.h
+++ b/src/core/lib/transport/transport_impl.h
@@ -63,7 +63,7 @@ typedef struct grpc_transport_vtable {
/* implementation of grpc_transport_destroy_stream */
void (*destroy_stream)(grpc_exec_ctx *exec_ctx, grpc_transport *self,
- grpc_stream *stream);
+ grpc_stream *stream, void *and_free_memory);
/* implementation of grpc_transport_destroy */
void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_transport *self);
diff --git a/src/csharp/Grpc.Examples/MathGrpc.cs b/src/csharp/Grpc.Examples/MathGrpc.cs
index edbce913b8..2d3034d28b 100644
--- a/src/csharp/Grpc.Examples/MathGrpc.cs
+++ b/src/csharp/Grpc.Examples/MathGrpc.cs
@@ -1,5 +1,35 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: math.proto
+// Original file comments:
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
#region Designer generated code
using System;
@@ -45,56 +75,140 @@ namespace Math {
__Marshaller_Num,
__Marshaller_Num);
- // service descriptor
+ /// <summary>Service descriptor</summary>
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
{
get { return global::Math.MathReflection.Descriptor.Services[0]; }
}
- // client interface
+ /// <summary>Client for Math</summary>
[System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
public interface IMathClient
{
+ /// <summary>
+ /// Div divides args.dividend by args.divisor and returns the quotient and
+ /// remainder.
+ /// </summary>
global::Math.DivReply Div(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// Div divides args.dividend by args.divisor and returns the quotient and
+ /// remainder.
+ /// </summary>
global::Math.DivReply Div(global::Math.DivArgs request, CallOptions options);
+ /// <summary>
+ /// Div divides args.dividend by args.divisor and returns the quotient and
+ /// remainder.
+ /// </summary>
AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// Div divides args.dividend by args.divisor and returns the quotient and
+ /// remainder.
+ /// </summary>
AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, CallOptions options);
+ /// <summary>
+ /// DivMany accepts an arbitrary number of division args from the client stream
+ /// and sends back the results in the reply stream. The stream continues until
+ /// the client closes its end; the server does the same after sending all the
+ /// replies. The stream ends immediately if either end aborts.
+ /// </summary>
AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// DivMany accepts an arbitrary number of division args from the client stream
+ /// and sends back the results in the reply stream. The stream continues until
+ /// the client closes its end; the server does the same after sending all the
+ /// replies. The stream ends immediately if either end aborts.
+ /// </summary>
AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(CallOptions options);
+ /// <summary>
+ /// Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib
+ /// generates up to limit numbers; otherwise it continues until the call is
+ /// canceled. Unlike Fib above, Fib has no final FibReply.
+ /// </summary>
AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib
+ /// generates up to limit numbers; otherwise it continues until the call is
+ /// canceled. Unlike Fib above, Fib has no final FibReply.
+ /// </summary>
AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, CallOptions options);
+ /// <summary>
+ /// Sum sums a stream of numbers, returning the final result once the stream
+ /// is closed.
+ /// </summary>
AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// Sum sums a stream of numbers, returning the final result once the stream
+ /// is closed.
+ /// </summary>
AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(CallOptions options);
}
- // server-side interface
+ /// <summary>Interface of server-side implementations of Math</summary>
[System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
public interface IMath
{
+ /// <summary>
+ /// Div divides args.dividend by args.divisor and returns the quotient and
+ /// remainder.
+ /// </summary>
Task<global::Math.DivReply> Div(global::Math.DivArgs request, ServerCallContext context);
+ /// <summary>
+ /// DivMany accepts an arbitrary number of division args from the client stream
+ /// and sends back the results in the reply stream. The stream continues until
+ /// the client closes its end; the server does the same after sending all the
+ /// replies. The stream ends immediately if either end aborts.
+ /// </summary>
Task DivMany(IAsyncStreamReader<global::Math.DivArgs> requestStream, IServerStreamWriter<global::Math.DivReply> responseStream, ServerCallContext context);
+ /// <summary>
+ /// Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib
+ /// generates up to limit numbers; otherwise it continues until the call is
+ /// canceled. Unlike Fib above, Fib has no final FibReply.
+ /// </summary>
Task Fib(global::Math.FibArgs request, IServerStreamWriter<global::Math.Num> responseStream, ServerCallContext context);
+ /// <summary>
+ /// Sum sums a stream of numbers, returning the final result once the stream
+ /// is closed.
+ /// </summary>
Task<global::Math.Num> Sum(IAsyncStreamReader<global::Math.Num> requestStream, ServerCallContext context);
}
- // server-side abstract class
+ /// <summary>Base class for server-side implementations of Math</summary>
public abstract class MathBase
{
+ /// <summary>
+ /// Div divides args.dividend by args.divisor and returns the quotient and
+ /// remainder.
+ /// </summary>
public virtual Task<global::Math.DivReply> Div(global::Math.DivArgs request, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
}
+ /// <summary>
+ /// DivMany accepts an arbitrary number of division args from the client stream
+ /// and sends back the results in the reply stream. The stream continues until
+ /// the client closes its end; the server does the same after sending all the
+ /// replies. The stream ends immediately if either end aborts.
+ /// </summary>
public virtual Task DivMany(IAsyncStreamReader<global::Math.DivArgs> requestStream, IServerStreamWriter<global::Math.DivReply> responseStream, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
}
+ /// <summary>
+ /// Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib
+ /// generates up to limit numbers; otherwise it continues until the call is
+ /// canceled. Unlike Fib above, Fib has no final FibReply.
+ /// </summary>
public virtual Task Fib(global::Math.FibArgs request, IServerStreamWriter<global::Math.Num> responseStream, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
}
+ /// <summary>
+ /// Sum sums a stream of numbers, returning the final result once the stream
+ /// is closed.
+ /// </summary>
public virtual Task<global::Math.Num> Sum(IAsyncStreamReader<global::Math.Num> requestStream, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
@@ -102,7 +216,7 @@ namespace Math {
}
- // client stub
+ /// <summary>Client for Math</summary>
#pragma warning disable 0618
public class MathClient : ClientBase<MathClient>, IMathClient
#pragma warning restore 0618
@@ -122,42 +236,88 @@ namespace Math {
{
}
+ /// <summary>
+ /// Div divides args.dividend by args.divisor and returns the quotient and
+ /// remainder.
+ /// </summary>
public virtual global::Math.DivReply Div(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return Div(request, new CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// Div divides args.dividend by args.divisor and returns the quotient and
+ /// remainder.
+ /// </summary>
public virtual global::Math.DivReply Div(global::Math.DivArgs request, CallOptions options)
{
return CallInvoker.BlockingUnaryCall(__Method_Div, null, options, request);
}
+ /// <summary>
+ /// Div divides args.dividend by args.divisor and returns the quotient and
+ /// remainder.
+ /// </summary>
public virtual AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return DivAsync(request, new CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// Div divides args.dividend by args.divisor and returns the quotient and
+ /// remainder.
+ /// </summary>
public virtual AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, CallOptions options)
{
return CallInvoker.AsyncUnaryCall(__Method_Div, null, options, request);
}
+ /// <summary>
+ /// DivMany accepts an arbitrary number of division args from the client stream
+ /// and sends back the results in the reply stream. The stream continues until
+ /// the client closes its end; the server does the same after sending all the
+ /// replies. The stream ends immediately if either end aborts.
+ /// </summary>
public virtual AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return DivMany(new CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// DivMany accepts an arbitrary number of division args from the client stream
+ /// and sends back the results in the reply stream. The stream continues until
+ /// the client closes its end; the server does the same after sending all the
+ /// replies. The stream ends immediately if either end aborts.
+ /// </summary>
public virtual AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(CallOptions options)
{
return CallInvoker.AsyncDuplexStreamingCall(__Method_DivMany, null, options);
}
+ /// <summary>
+ /// Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib
+ /// generates up to limit numbers; otherwise it continues until the call is
+ /// canceled. Unlike Fib above, Fib has no final FibReply.
+ /// </summary>
public virtual AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return Fib(request, new CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib
+ /// generates up to limit numbers; otherwise it continues until the call is
+ /// canceled. Unlike Fib above, Fib has no final FibReply.
+ /// </summary>
public virtual AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, CallOptions options)
{
return CallInvoker.AsyncServerStreamingCall(__Method_Fib, null, options, request);
}
+ /// <summary>
+ /// Sum sums a stream of numbers, returning the final result once the stream
+ /// is closed.
+ /// </summary>
public virtual AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return Sum(new CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// Sum sums a stream of numbers, returning the final result once the stream
+ /// is closed.
+ /// </summary>
public virtual AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(CallOptions options)
{
return CallInvoker.AsyncClientStreamingCall(__Method_Sum, null, options);
@@ -168,13 +328,13 @@ namespace Math {
}
}
- // creates a new client
+ /// <summary>Creates a new client for Math</summary>
public static MathClient NewClient(Channel channel)
{
return new MathClient(channel);
}
- // creates service definition that can be registered with a server
+ /// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(IMath serviceImpl)
#pragma warning restore 0618
@@ -186,7 +346,7 @@ namespace Math {
.AddMethod(__Method_Sum, serviceImpl.Sum).Build();
}
- // creates service definition that can be registered with a server
+ /// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(MathBase serviceImpl)
#pragma warning restore 0618
diff --git a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
index e2cdabf011..967d1170be 100644
--- a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
+++ b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
@@ -1,5 +1,35 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: health.proto
+// Original file comments:
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
#region Designer generated code
using System;
@@ -22,13 +52,13 @@ namespace Grpc.Health.V1 {
__Marshaller_HealthCheckRequest,
__Marshaller_HealthCheckResponse);
- // service descriptor
+ /// <summary>Service descriptor</summary>
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
{
get { return global::Grpc.Health.V1.HealthReflection.Descriptor.Services[0]; }
}
- // client interface
+ /// <summary>Client for Health</summary>
[System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
public interface IHealthClient
{
@@ -38,14 +68,14 @@ namespace Grpc.Health.V1 {
AsyncUnaryCall<global::Grpc.Health.V1.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1.HealthCheckRequest request, CallOptions options);
}
- // server-side interface
+ /// <summary>Interface of server-side implementations of Health</summary>
[System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
public interface IHealth
{
Task<global::Grpc.Health.V1.HealthCheckResponse> Check(global::Grpc.Health.V1.HealthCheckRequest request, ServerCallContext context);
}
- // server-side abstract class
+ /// <summary>Base class for server-side implementations of Health</summary>
public abstract class HealthBase
{
public virtual Task<global::Grpc.Health.V1.HealthCheckResponse> Check(global::Grpc.Health.V1.HealthCheckRequest request, ServerCallContext context)
@@ -55,7 +85,7 @@ namespace Grpc.Health.V1 {
}
- // client stub
+ /// <summary>Client for Health</summary>
#pragma warning disable 0618
public class HealthClient : ClientBase<HealthClient>, IHealthClient
#pragma warning restore 0618
@@ -97,13 +127,13 @@ namespace Grpc.Health.V1 {
}
}
- // creates a new client
+ /// <summary>Creates a new client for Health</summary>
public static HealthClient NewClient(Channel channel)
{
return new HealthClient(channel);
}
- // creates service definition that can be registered with a server
+ /// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(IHealth serviceImpl)
#pragma warning restore 0618
@@ -112,7 +142,7 @@ namespace Grpc.Health.V1 {
.AddMethod(__Method_Check, serviceImpl.Check).Build();
}
- // creates service definition that can be registered with a server
+ /// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(HealthBase serviceImpl)
#pragma warning restore 0618
diff --git a/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs b/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
index 0f701a837f..aa4f1c5c3e 100644
--- a/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
@@ -1,5 +1,41 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: src/proto/grpc/testing/metrics.proto
+// Original file comments:
+// Copyright 2015-2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Contains the definitions for a metrics service and the type of metrics
+// exposed by the service.
+//
+// Currently, 'Gauge' (i.e a metric that represents the measured value of
+// something at an instant of time) is the only metric type supported by the
+// service.
#region Designer generated code
using System;
@@ -30,40 +66,74 @@ namespace Grpc.Testing {
__Marshaller_GaugeRequest,
__Marshaller_GaugeResponse);
- // service descriptor
+ /// <summary>Service descriptor</summary>
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
{
get { return global::Grpc.Testing.MetricsReflection.Descriptor.Services[0]; }
}
- // client interface
+ /// <summary>Client for MetricsService</summary>
[System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
public interface IMetricsServiceClient
{
+ /// <summary>
+ /// Returns the values of all the gauges that are currently being maintained by
+ /// the service
+ /// </summary>
AsyncServerStreamingCall<global::Grpc.Testing.GaugeResponse> GetAllGauges(global::Grpc.Testing.EmptyMessage request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// Returns the values of all the gauges that are currently being maintained by
+ /// the service
+ /// </summary>
AsyncServerStreamingCall<global::Grpc.Testing.GaugeResponse> GetAllGauges(global::Grpc.Testing.EmptyMessage request, CallOptions options);
+ /// <summary>
+ /// Returns the value of one gauge
+ /// </summary>
global::Grpc.Testing.GaugeResponse GetGauge(global::Grpc.Testing.GaugeRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// Returns the value of one gauge
+ /// </summary>
global::Grpc.Testing.GaugeResponse GetGauge(global::Grpc.Testing.GaugeRequest request, CallOptions options);
+ /// <summary>
+ /// Returns the value of one gauge
+ /// </summary>
AsyncUnaryCall<global::Grpc.Testing.GaugeResponse> GetGaugeAsync(global::Grpc.Testing.GaugeRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// Returns the value of one gauge
+ /// </summary>
AsyncUnaryCall<global::Grpc.Testing.GaugeResponse> GetGaugeAsync(global::Grpc.Testing.GaugeRequest request, CallOptions options);
}
- // server-side interface
+ /// <summary>Interface of server-side implementations of MetricsService</summary>
[System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
public interface IMetricsService
{
+ /// <summary>
+ /// Returns the values of all the gauges that are currently being maintained by
+ /// the service
+ /// </summary>
Task GetAllGauges(global::Grpc.Testing.EmptyMessage request, IServerStreamWriter<global::Grpc.Testing.GaugeResponse> responseStream, ServerCallContext context);
+ /// <summary>
+ /// Returns the value of one gauge
+ /// </summary>
Task<global::Grpc.Testing.GaugeResponse> GetGauge(global::Grpc.Testing.GaugeRequest request, ServerCallContext context);
}
- // server-side abstract class
+ /// <summary>Base class for server-side implementations of MetricsService</summary>
public abstract class MetricsServiceBase
{
+ /// <summary>
+ /// Returns the values of all the gauges that are currently being maintained by
+ /// the service
+ /// </summary>
public virtual Task GetAllGauges(global::Grpc.Testing.EmptyMessage request, IServerStreamWriter<global::Grpc.Testing.GaugeResponse> responseStream, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
}
+ /// <summary>
+ /// Returns the value of one gauge
+ /// </summary>
public virtual Task<global::Grpc.Testing.GaugeResponse> GetGauge(global::Grpc.Testing.GaugeRequest request, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
@@ -71,7 +141,7 @@ namespace Grpc.Testing {
}
- // client stub
+ /// <summary>Client for MetricsService</summary>
#pragma warning disable 0618
public class MetricsServiceClient : ClientBase<MetricsServiceClient>, IMetricsServiceClient
#pragma warning restore 0618
@@ -91,26 +161,46 @@ namespace Grpc.Testing {
{
}
+ /// <summary>
+ /// Returns the values of all the gauges that are currently being maintained by
+ /// the service
+ /// </summary>
public virtual AsyncServerStreamingCall<global::Grpc.Testing.GaugeResponse> GetAllGauges(global::Grpc.Testing.EmptyMessage request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return GetAllGauges(request, new CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// Returns the values of all the gauges that are currently being maintained by
+ /// the service
+ /// </summary>
public virtual AsyncServerStreamingCall<global::Grpc.Testing.GaugeResponse> GetAllGauges(global::Grpc.Testing.EmptyMessage request, CallOptions options)
{
return CallInvoker.AsyncServerStreamingCall(__Method_GetAllGauges, null, options, request);
}
+ /// <summary>
+ /// Returns the value of one gauge
+ /// </summary>
public virtual global::Grpc.Testing.GaugeResponse GetGauge(global::Grpc.Testing.GaugeRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return GetGauge(request, new CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// Returns the value of one gauge
+ /// </summary>
public virtual global::Grpc.Testing.GaugeResponse GetGauge(global::Grpc.Testing.GaugeRequest request, CallOptions options)
{
return CallInvoker.BlockingUnaryCall(__Method_GetGauge, null, options, request);
}
+ /// <summary>
+ /// Returns the value of one gauge
+ /// </summary>
public virtual AsyncUnaryCall<global::Grpc.Testing.GaugeResponse> GetGaugeAsync(global::Grpc.Testing.GaugeRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return GetGaugeAsync(request, new CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// Returns the value of one gauge
+ /// </summary>
public virtual AsyncUnaryCall<global::Grpc.Testing.GaugeResponse> GetGaugeAsync(global::Grpc.Testing.GaugeRequest request, CallOptions options)
{
return CallInvoker.AsyncUnaryCall(__Method_GetGauge, null, options, request);
@@ -121,13 +211,13 @@ namespace Grpc.Testing {
}
}
- // creates a new client
+ /// <summary>Creates a new client for MetricsService</summary>
public static MetricsServiceClient NewClient(Channel channel)
{
return new MetricsServiceClient(channel);
}
- // creates service definition that can be registered with a server
+ /// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(IMetricsService serviceImpl)
#pragma warning restore 0618
@@ -137,7 +227,7 @@ namespace Grpc.Testing {
.AddMethod(__Method_GetGauge, serviceImpl.GetGauge).Build();
}
- // creates service definition that can be registered with a server
+ /// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(MetricsServiceBase serviceImpl)
#pragma warning restore 0618
diff --git a/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs b/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs
index 3f07a7aeb6..42bf5e0b58 100644
--- a/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs
@@ -1,5 +1,37 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: src/proto/grpc/testing/services.proto
+// Original file comments:
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// An integration test service that covers all the method signature permutations
+// of unary/streaming requests/responses.
#region Designer generated code
using System;
@@ -29,40 +61,80 @@ namespace Grpc.Testing {
__Marshaller_SimpleRequest,
__Marshaller_SimpleResponse);
- // service descriptor
+ /// <summary>Service descriptor</summary>
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
{
get { return global::Grpc.Testing.ServicesReflection.Descriptor.Services[0]; }
}
- // client interface
+ /// <summary>Client for BenchmarkService</summary>
[System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
public interface IBenchmarkServiceClient
{
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options);
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options);
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(CallOptions options);
}
- // server-side interface
+ /// <summary>Interface of server-side implementations of BenchmarkService</summary>
[System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
public interface IBenchmarkService
{
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
Task<global::Grpc.Testing.SimpleResponse> UnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context);
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
Task StreamingCall(IAsyncStreamReader<global::Grpc.Testing.SimpleRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.SimpleResponse> responseStream, ServerCallContext context);
}
- // server-side abstract class
+ /// <summary>Base class for server-side implementations of BenchmarkService</summary>
public abstract class BenchmarkServiceBase
{
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
public virtual Task<global::Grpc.Testing.SimpleResponse> UnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
}
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
public virtual Task StreamingCall(IAsyncStreamReader<global::Grpc.Testing.SimpleRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.SimpleResponse> responseStream, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
@@ -70,7 +142,7 @@ namespace Grpc.Testing {
}
- // client stub
+ /// <summary>Client for BenchmarkService</summary>
#pragma warning disable 0618
public class BenchmarkServiceClient : ClientBase<BenchmarkServiceClient>, IBenchmarkServiceClient
#pragma warning restore 0618
@@ -90,26 +162,50 @@ namespace Grpc.Testing {
{
}
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
public virtual global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return UnaryCall(request, new CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
public virtual global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options)
{
return CallInvoker.BlockingUnaryCall(__Method_UnaryCall, null, options, request);
}
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
public virtual AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return UnaryCallAsync(request, new CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
public virtual AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options)
{
return CallInvoker.AsyncUnaryCall(__Method_UnaryCall, null, options, request);
}
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return StreamingCall(new CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// One request followed by one response.
+ /// The server returns the client payload as-is.
+ /// </summary>
public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(CallOptions options)
{
return CallInvoker.AsyncDuplexStreamingCall(__Method_StreamingCall, null, options);
@@ -120,13 +216,13 @@ namespace Grpc.Testing {
}
}
- // creates a new client
+ /// <summary>Creates a new client for BenchmarkService</summary>
public static BenchmarkServiceClient NewClient(Channel channel)
{
return new BenchmarkServiceClient(channel);
}
- // creates service definition that can be registered with a server
+ /// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(IBenchmarkService serviceImpl)
#pragma warning restore 0618
@@ -136,7 +232,7 @@ namespace Grpc.Testing {
.AddMethod(__Method_StreamingCall, serviceImpl.StreamingCall).Build();
}
- // creates service definition that can be registered with a server
+ /// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(BenchmarkServiceBase serviceImpl)
#pragma warning restore 0618
@@ -187,58 +283,158 @@ namespace Grpc.Testing {
__Marshaller_Void,
__Marshaller_Void);
- // service descriptor
+ /// <summary>Service descriptor</summary>
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
{
get { return global::Grpc.Testing.ServicesReflection.Descriptor.Services[1]; }
}
- // client interface
+ /// <summary>Client for WorkerService</summary>
[System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
public interface IWorkerServiceClient
{
+ /// <summary>
+ /// Start server with specified workload.
+ /// First request sent specifies the ServerConfig followed by ServerStatus
+ /// response. After that, a "Mark" can be sent anytime to request the latest
+ /// stats. Closing the stream will initiate shutdown of the test server
+ /// and once the shutdown has finished, the OK status is sent to terminate
+ /// this RPC.
+ /// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// Start server with specified workload.
+ /// First request sent specifies the ServerConfig followed by ServerStatus
+ /// response. After that, a "Mark" can be sent anytime to request the latest
+ /// stats. Closing the stream will initiate shutdown of the test server
+ /// and once the shutdown has finished, the OK status is sent to terminate
+ /// this RPC.
+ /// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(CallOptions options);
+ /// <summary>
+ /// Start client with specified workload.
+ /// First request sent specifies the ClientConfig followed by ClientStatus
+ /// response. After that, a "Mark" can be sent anytime to request the latest
+ /// stats. Closing the stream will initiate shutdown of the test client
+ /// and once the shutdown has finished, the OK status is sent to terminate
+ /// this RPC.
+ /// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// Start client with specified workload.
+ /// First request sent specifies the ClientConfig followed by ClientStatus
+ /// response. After that, a "Mark" can be sent anytime to request the latest
+ /// stats. Closing the stream will initiate shutdown of the test client
+ /// and once the shutdown has finished, the OK status is sent to terminate
+ /// this RPC.
+ /// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(CallOptions options);
+ /// <summary>
+ /// Just return the core count - unary call
+ /// </summary>
global::Grpc.Testing.CoreResponse CoreCount(global::Grpc.Testing.CoreRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// Just return the core count - unary call
+ /// </summary>
global::Grpc.Testing.CoreResponse CoreCount(global::Grpc.Testing.CoreRequest request, CallOptions options);
+ /// <summary>
+ /// Just return the core count - unary call
+ /// </summary>
AsyncUnaryCall<global::Grpc.Testing.CoreResponse> CoreCountAsync(global::Grpc.Testing.CoreRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// Just return the core count - unary call
+ /// </summary>
AsyncUnaryCall<global::Grpc.Testing.CoreResponse> CoreCountAsync(global::Grpc.Testing.CoreRequest request, CallOptions options);
+ /// <summary>
+ /// Quit this worker
+ /// </summary>
global::Grpc.Testing.Void QuitWorker(global::Grpc.Testing.Void request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// Quit this worker
+ /// </summary>
global::Grpc.Testing.Void QuitWorker(global::Grpc.Testing.Void request, CallOptions options);
+ /// <summary>
+ /// Quit this worker
+ /// </summary>
AsyncUnaryCall<global::Grpc.Testing.Void> QuitWorkerAsync(global::Grpc.Testing.Void request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// Quit this worker
+ /// </summary>
AsyncUnaryCall<global::Grpc.Testing.Void> QuitWorkerAsync(global::Grpc.Testing.Void request, CallOptions options);
}
- // server-side interface
+ /// <summary>Interface of server-side implementations of WorkerService</summary>
[System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
public interface IWorkerService
{
+ /// <summary>
+ /// Start server with specified workload.
+ /// First request sent specifies the ServerConfig followed by ServerStatus
+ /// response. After that, a "Mark" can be sent anytime to request the latest
+ /// stats. Closing the stream will initiate shutdown of the test server
+ /// and once the shutdown has finished, the OK status is sent to terminate
+ /// this RPC.
+ /// </summary>
Task RunServer(IAsyncStreamReader<global::Grpc.Testing.ServerArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ServerStatus> responseStream, ServerCallContext context);
+ /// <summary>
+ /// Start client with specified workload.
+ /// First request sent specifies the ClientConfig followed by ClientStatus
+ /// response. After that, a "Mark" can be sent anytime to request the latest
+ /// stats. Closing the stream will initiate shutdown of the test client
+ /// and once the shutdown has finished, the OK status is sent to terminate
+ /// this RPC.
+ /// </summary>
Task RunClient(IAsyncStreamReader<global::Grpc.Testing.ClientArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ClientStatus> responseStream, ServerCallContext context);
+ /// <summary>
+ /// Just return the core count - unary call
+ /// </summary>
Task<global::Grpc.Testing.CoreResponse> CoreCount(global::Grpc.Testing.CoreRequest request, ServerCallContext context);
+ /// <summary>
+ /// Quit this worker
+ /// </summary>
Task<global::Grpc.Testing.Void> QuitWorker(global::Grpc.Testing.Void request, ServerCallContext context);
}
- // server-side abstract class
+ /// <summary>Base class for server-side implementations of WorkerService</summary>
public abstract class WorkerServiceBase
{
+ /// <summary>
+ /// Start server with specified workload.
+ /// First request sent specifies the ServerConfig followed by ServerStatus
+ /// response. After that, a "Mark" can be sent anytime to request the latest
+ /// stats. Closing the stream will initiate shutdown of the test server
+ /// and once the shutdown has finished, the OK status is sent to terminate
+ /// this RPC.
+ /// </summary>
public virtual Task RunServer(IAsyncStreamReader<global::Grpc.Testing.ServerArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ServerStatus> responseStream, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
}
+ /// <summary>
+ /// Start client with specified workload.
+ /// First request sent specifies the ClientConfig followed by ClientStatus
+ /// response. After that, a "Mark" can be sent anytime to request the latest
+ /// stats. Closing the stream will initiate shutdown of the test client
+ /// and once the shutdown has finished, the OK status is sent to terminate
+ /// this RPC.
+ /// </summary>
public virtual Task RunClient(IAsyncStreamReader<global::Grpc.Testing.ClientArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ClientStatus> responseStream, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
}
+ /// <summary>
+ /// Just return the core count - unary call
+ /// </summary>
public virtual Task<global::Grpc.Testing.CoreResponse> CoreCount(global::Grpc.Testing.CoreRequest request, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
}
+ /// <summary>
+ /// Quit this worker
+ /// </summary>
public virtual Task<global::Grpc.Testing.Void> QuitWorker(global::Grpc.Testing.Void request, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
@@ -246,7 +442,7 @@ namespace Grpc.Testing {
}
- // client stub
+ /// <summary>Client for WorkerService</summary>
#pragma warning disable 0618
public class WorkerServiceClient : ClientBase<WorkerServiceClient>, IWorkerServiceClient
#pragma warning restore 0618
@@ -266,50 +462,106 @@ namespace Grpc.Testing {
{
}
+ /// <summary>
+ /// Start server with specified workload.
+ /// First request sent specifies the ServerConfig followed by ServerStatus
+ /// response. After that, a "Mark" can be sent anytime to request the latest
+ /// stats. Closing the stream will initiate shutdown of the test server
+ /// and once the shutdown has finished, the OK status is sent to terminate
+ /// this RPC.
+ /// </summary>
public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return RunServer(new CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// Start server with specified workload.
+ /// First request sent specifies the ServerConfig followed by ServerStatus
+ /// response. After that, a "Mark" can be sent anytime to request the latest
+ /// stats. Closing the stream will initiate shutdown of the test server
+ /// and once the shutdown has finished, the OK status is sent to terminate
+ /// this RPC.
+ /// </summary>
public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(CallOptions options)
{
return CallInvoker.AsyncDuplexStreamingCall(__Method_RunServer, null, options);
}
+ /// <summary>
+ /// Start client with specified workload.
+ /// First request sent specifies the ClientConfig followed by ClientStatus
+ /// response. After that, a "Mark" can be sent anytime to request the latest
+ /// stats. Closing the stream will initiate shutdown of the test client
+ /// and once the shutdown has finished, the OK status is sent to terminate
+ /// this RPC.
+ /// </summary>
public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return RunClient(new CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// Start client with specified workload.
+ /// First request sent specifies the ClientConfig followed by ClientStatus
+ /// response. After that, a "Mark" can be sent anytime to request the latest
+ /// stats. Closing the stream will initiate shutdown of the test client
+ /// and once the shutdown has finished, the OK status is sent to terminate
+ /// this RPC.
+ /// </summary>
public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(CallOptions options)
{
return CallInvoker.AsyncDuplexStreamingCall(__Method_RunClient, null, options);
}
+ /// <summary>
+ /// Just return the core count - unary call
+ /// </summary>
public virtual global::Grpc.Testing.CoreResponse CoreCount(global::Grpc.Testing.CoreRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return CoreCount(request, new CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// Just return the core count - unary call
+ /// </summary>
public virtual global::Grpc.Testing.CoreResponse CoreCount(global::Grpc.Testing.CoreRequest request, CallOptions options)
{
return CallInvoker.BlockingUnaryCall(__Method_CoreCount, null, options, request);
}
+ /// <summary>
+ /// Just return the core count - unary call
+ /// </summary>
public virtual AsyncUnaryCall<global::Grpc.Testing.CoreResponse> CoreCountAsync(global::Grpc.Testing.CoreRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return CoreCountAsync(request, new CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// Just return the core count - unary call
+ /// </summary>
public virtual AsyncUnaryCall<global::Grpc.Testing.CoreResponse> CoreCountAsync(global::Grpc.Testing.CoreRequest request, CallOptions options)
{
return CallInvoker.AsyncUnaryCall(__Method_CoreCount, null, options, request);
}
+ /// <summary>
+ /// Quit this worker
+ /// </summary>
public virtual global::Grpc.Testing.Void QuitWorker(global::Grpc.Testing.Void request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return QuitWorker(request, new CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// Quit this worker
+ /// </summary>
public virtual global::Grpc.Testing.Void QuitWorker(global::Grpc.Testing.Void request, CallOptions options)
{
return CallInvoker.BlockingUnaryCall(__Method_QuitWorker, null, options, request);
}
+ /// <summary>
+ /// Quit this worker
+ /// </summary>
public virtual AsyncUnaryCall<global::Grpc.Testing.Void> QuitWorkerAsync(global::Grpc.Testing.Void request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return QuitWorkerAsync(request, new CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// Quit this worker
+ /// </summary>
public virtual AsyncUnaryCall<global::Grpc.Testing.Void> QuitWorkerAsync(global::Grpc.Testing.Void request, CallOptions options)
{
return CallInvoker.AsyncUnaryCall(__Method_QuitWorker, null, options, request);
@@ -320,13 +572,13 @@ namespace Grpc.Testing {
}
}
- // creates a new client
+ /// <summary>Creates a new client for WorkerService</summary>
public static WorkerServiceClient NewClient(Channel channel)
{
return new WorkerServiceClient(channel);
}
- // creates service definition that can be registered with a server
+ /// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(IWorkerService serviceImpl)
#pragma warning restore 0618
@@ -338,7 +590,7 @@ namespace Grpc.Testing {
.AddMethod(__Method_QuitWorker, serviceImpl.QuitWorker).Build();
}
- // creates service definition that can be registered with a server
+ /// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(WorkerServiceBase serviceImpl)
#pragma warning restore 0618
diff --git a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
index 4efd35f81f..f1878cbb55 100644
--- a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
@@ -1,5 +1,38 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: src/proto/grpc/testing/test.proto
+// Original file comments:
+// Copyright 2015-2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// An integration test service that covers all the method signature permutations
+// of unary/streaming requests/responses.
+//
#region Designer generated code
using System;
@@ -8,6 +41,10 @@ using System.Threading.Tasks;
using Grpc.Core;
namespace Grpc.Testing {
+ /// <summary>
+ /// A simple service to test the various types of RPCs and experiment with
+ /// performance with various types of payload.
+ /// </summary>
public static class TestService
{
static readonly string __ServiceName = "grpc.testing.TestService";
@@ -62,74 +99,186 @@ namespace Grpc.Testing {
__Marshaller_StreamingOutputCallRequest,
__Marshaller_StreamingOutputCallResponse);
- // service descriptor
+ /// <summary>Service descriptor</summary>
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
{
get { return global::Grpc.Testing.TestReflection.Descriptor.Services[0]; }
}
- // client interface
+ /// <summary>Client for TestService</summary>
[System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
public interface ITestServiceClient
{
+ /// <summary>
+ /// One empty request followed by one empty response.
+ /// </summary>
global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// One empty request followed by one empty response.
+ /// </summary>
global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, CallOptions options);
+ /// <summary>
+ /// One empty request followed by one empty response.
+ /// </summary>
AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// One empty request followed by one empty response.
+ /// </summary>
AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, CallOptions options);
+ /// <summary>
+ /// One request followed by one response.
+ /// </summary>
global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// One request followed by one response.
+ /// </summary>
global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options);
+ /// <summary>
+ /// One request followed by one response.
+ /// </summary>
AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// One request followed by one response.
+ /// </summary>
AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options);
+ /// <summary>
+ /// One request followed by a sequence of responses (streamed download).
+ /// The server returns the payload with client desired type and sizes.
+ /// </summary>
AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// One request followed by a sequence of responses (streamed download).
+ /// The server returns the payload with client desired type and sizes.
+ /// </summary>
AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, CallOptions options);
+ /// <summary>
+ /// A sequence of requests followed by one response (streamed upload).
+ /// The server returns the aggregated size of client payload as the result.
+ /// </summary>
AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// A sequence of requests followed by one response (streamed upload).
+ /// The server returns the aggregated size of client payload as the result.
+ /// </summary>
AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(CallOptions options);
+ /// <summary>
+ /// A sequence of requests with each request served by the server immediately.
+ /// As one request could lead to multiple responses, this interface
+ /// demonstrates the idea of full duplexing.
+ /// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// A sequence of requests with each request served by the server immediately.
+ /// As one request could lead to multiple responses, this interface
+ /// demonstrates the idea of full duplexing.
+ /// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(CallOptions options);
+ /// <summary>
+ /// A sequence of requests followed by a sequence of responses.
+ /// The server buffers all the client requests and then serves them in order. A
+ /// stream of responses are returned to the client when the server starts with
+ /// first request.
+ /// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// A sequence of requests followed by a sequence of responses.
+ /// The server buffers all the client requests and then serves them in order. A
+ /// stream of responses are returned to the client when the server starts with
+ /// first request.
+ /// </summary>
AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(CallOptions options);
}
- // server-side interface
+ /// <summary>Interface of server-side implementations of TestService</summary>
[System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
public interface ITestService
{
+ /// <summary>
+ /// One empty request followed by one empty response.
+ /// </summary>
Task<global::Grpc.Testing.Empty> EmptyCall(global::Grpc.Testing.Empty request, ServerCallContext context);
+ /// <summary>
+ /// One request followed by one response.
+ /// </summary>
Task<global::Grpc.Testing.SimpleResponse> UnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context);
+ /// <summary>
+ /// One request followed by a sequence of responses (streamed download).
+ /// The server returns the payload with client desired type and sizes.
+ /// </summary>
Task StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context);
+ /// <summary>
+ /// A sequence of requests followed by one response (streamed upload).
+ /// The server returns the aggregated size of client payload as the result.
+ /// </summary>
Task<global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(IAsyncStreamReader<global::Grpc.Testing.StreamingInputCallRequest> requestStream, ServerCallContext context);
+ /// <summary>
+ /// A sequence of requests with each request served by the server immediately.
+ /// As one request could lead to multiple responses, this interface
+ /// demonstrates the idea of full duplexing.
+ /// </summary>
Task FullDuplexCall(IAsyncStreamReader<global::Grpc.Testing.StreamingOutputCallRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context);
+ /// <summary>
+ /// A sequence of requests followed by a sequence of responses.
+ /// The server buffers all the client requests and then serves them in order. A
+ /// stream of responses are returned to the client when the server starts with
+ /// first request.
+ /// </summary>
Task HalfDuplexCall(IAsyncStreamReader<global::Grpc.Testing.StreamingOutputCallRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context);
}
- // server-side abstract class
+ /// <summary>Base class for server-side implementations of TestService</summary>
public abstract class TestServiceBase
{
+ /// <summary>
+ /// One empty request followed by one empty response.
+ /// </summary>
public virtual Task<global::Grpc.Testing.Empty> EmptyCall(global::Grpc.Testing.Empty request, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
}
+ /// <summary>
+ /// One request followed by one response.
+ /// </summary>
public virtual Task<global::Grpc.Testing.SimpleResponse> UnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
}
+ /// <summary>
+ /// One request followed by a sequence of responses (streamed download).
+ /// The server returns the payload with client desired type and sizes.
+ /// </summary>
public virtual Task StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
}
+ /// <summary>
+ /// A sequence of requests followed by one response (streamed upload).
+ /// The server returns the aggregated size of client payload as the result.
+ /// </summary>
public virtual Task<global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(IAsyncStreamReader<global::Grpc.Testing.StreamingInputCallRequest> requestStream, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
}
+ /// <summary>
+ /// A sequence of requests with each request served by the server immediately.
+ /// As one request could lead to multiple responses, this interface
+ /// demonstrates the idea of full duplexing.
+ /// </summary>
public virtual Task FullDuplexCall(IAsyncStreamReader<global::Grpc.Testing.StreamingOutputCallRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
}
+ /// <summary>
+ /// A sequence of requests followed by a sequence of responses.
+ /// The server buffers all the client requests and then serves them in order. A
+ /// stream of responses are returned to the client when the server starts with
+ /// first request.
+ /// </summary>
public virtual Task HalfDuplexCall(IAsyncStreamReader<global::Grpc.Testing.StreamingOutputCallRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
@@ -137,7 +286,7 @@ namespace Grpc.Testing {
}
- // client stub
+ /// <summary>Client for TestService</summary>
#pragma warning disable 0618
public class TestServiceClient : ClientBase<TestServiceClient>, ITestServiceClient
#pragma warning restore 0618
@@ -157,66 +306,128 @@ namespace Grpc.Testing {
{
}
+ /// <summary>
+ /// One empty request followed by one empty response.
+ /// </summary>
public virtual global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return EmptyCall(request, new CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// One empty request followed by one empty response.
+ /// </summary>
public virtual global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, CallOptions options)
{
return CallInvoker.BlockingUnaryCall(__Method_EmptyCall, null, options, request);
}
+ /// <summary>
+ /// One empty request followed by one empty response.
+ /// </summary>
public virtual AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return EmptyCallAsync(request, new CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// One empty request followed by one empty response.
+ /// </summary>
public virtual AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, CallOptions options)
{
return CallInvoker.AsyncUnaryCall(__Method_EmptyCall, null, options, request);
}
+ /// <summary>
+ /// One request followed by one response.
+ /// </summary>
public virtual global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return UnaryCall(request, new CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// One request followed by one response.
+ /// </summary>
public virtual global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options)
{
return CallInvoker.BlockingUnaryCall(__Method_UnaryCall, null, options, request);
}
+ /// <summary>
+ /// One request followed by one response.
+ /// </summary>
public virtual AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return UnaryCallAsync(request, new CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// One request followed by one response.
+ /// </summary>
public virtual AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options)
{
return CallInvoker.AsyncUnaryCall(__Method_UnaryCall, null, options, request);
}
+ /// <summary>
+ /// One request followed by a sequence of responses (streamed download).
+ /// The server returns the payload with client desired type and sizes.
+ /// </summary>
public virtual AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return StreamingOutputCall(request, new CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// One request followed by a sequence of responses (streamed download).
+ /// The server returns the payload with client desired type and sizes.
+ /// </summary>
public virtual AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, CallOptions options)
{
return CallInvoker.AsyncServerStreamingCall(__Method_StreamingOutputCall, null, options, request);
}
+ /// <summary>
+ /// A sequence of requests followed by one response (streamed upload).
+ /// The server returns the aggregated size of client payload as the result.
+ /// </summary>
public virtual AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return StreamingInputCall(new CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// A sequence of requests followed by one response (streamed upload).
+ /// The server returns the aggregated size of client payload as the result.
+ /// </summary>
public virtual AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(CallOptions options)
{
return CallInvoker.AsyncClientStreamingCall(__Method_StreamingInputCall, null, options);
}
+ /// <summary>
+ /// A sequence of requests with each request served by the server immediately.
+ /// As one request could lead to multiple responses, this interface
+ /// demonstrates the idea of full duplexing.
+ /// </summary>
public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return FullDuplexCall(new CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// A sequence of requests with each request served by the server immediately.
+ /// As one request could lead to multiple responses, this interface
+ /// demonstrates the idea of full duplexing.
+ /// </summary>
public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(CallOptions options)
{
return CallInvoker.AsyncDuplexStreamingCall(__Method_FullDuplexCall, null, options);
}
+ /// <summary>
+ /// A sequence of requests followed by a sequence of responses.
+ /// The server buffers all the client requests and then serves them in order. A
+ /// stream of responses are returned to the client when the server starts with
+ /// first request.
+ /// </summary>
public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return HalfDuplexCall(new CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// A sequence of requests followed by a sequence of responses.
+ /// The server buffers all the client requests and then serves them in order. A
+ /// stream of responses are returned to the client when the server starts with
+ /// first request.
+ /// </summary>
public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(CallOptions options)
{
return CallInvoker.AsyncDuplexStreamingCall(__Method_HalfDuplexCall, null, options);
@@ -227,13 +438,13 @@ namespace Grpc.Testing {
}
}
- // creates a new client
+ /// <summary>Creates a new client for TestService</summary>
public static TestServiceClient NewClient(Channel channel)
{
return new TestServiceClient(channel);
}
- // creates service definition that can be registered with a server
+ /// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(ITestService serviceImpl)
#pragma warning restore 0618
@@ -247,7 +458,7 @@ namespace Grpc.Testing {
.AddMethod(__Method_HalfDuplexCall, serviceImpl.HalfDuplexCall).Build();
}
- // creates service definition that can be registered with a server
+ /// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(TestServiceBase serviceImpl)
#pragma warning restore 0618
@@ -262,6 +473,10 @@ namespace Grpc.Testing {
}
}
+ /// <summary>
+ /// A simple service NOT implemented at servers so clients can test for
+ /// that case.
+ /// </summary>
public static class UnimplementedService
{
static readonly string __ServiceName = "grpc.testing.UnimplementedService";
@@ -275,32 +490,50 @@ namespace Grpc.Testing {
__Marshaller_Empty,
__Marshaller_Empty);
- // service descriptor
+ /// <summary>Service descriptor</summary>
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
{
get { return global::Grpc.Testing.TestReflection.Descriptor.Services[1]; }
}
- // client interface
+ /// <summary>Client for UnimplementedService</summary>
[System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
public interface IUnimplementedServiceClient
{
+ /// <summary>
+ /// A call that no server should implement
+ /// </summary>
global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// A call that no server should implement
+ /// </summary>
global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, CallOptions options);
+ /// <summary>
+ /// A call that no server should implement
+ /// </summary>
AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ /// <summary>
+ /// A call that no server should implement
+ /// </summary>
AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, CallOptions options);
}
- // server-side interface
+ /// <summary>Interface of server-side implementations of UnimplementedService</summary>
[System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
public interface IUnimplementedService
{
+ /// <summary>
+ /// A call that no server should implement
+ /// </summary>
Task<global::Grpc.Testing.Empty> UnimplementedCall(global::Grpc.Testing.Empty request, ServerCallContext context);
}
- // server-side abstract class
+ /// <summary>Base class for server-side implementations of UnimplementedService</summary>
public abstract class UnimplementedServiceBase
{
+ /// <summary>
+ /// A call that no server should implement
+ /// </summary>
public virtual Task<global::Grpc.Testing.Empty> UnimplementedCall(global::Grpc.Testing.Empty request, ServerCallContext context)
{
throw new RpcException(new Status(StatusCode.Unimplemented, ""));
@@ -308,7 +541,7 @@ namespace Grpc.Testing {
}
- // client stub
+ /// <summary>Client for UnimplementedService</summary>
#pragma warning disable 0618
public class UnimplementedServiceClient : ClientBase<UnimplementedServiceClient>, IUnimplementedServiceClient
#pragma warning restore 0618
@@ -328,18 +561,30 @@ namespace Grpc.Testing {
{
}
+ /// <summary>
+ /// A call that no server should implement
+ /// </summary>
public virtual global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return UnimplementedCall(request, new CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// A call that no server should implement
+ /// </summary>
public virtual global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, CallOptions options)
{
return CallInvoker.BlockingUnaryCall(__Method_UnimplementedCall, null, options, request);
}
+ /// <summary>
+ /// A call that no server should implement
+ /// </summary>
public virtual AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return UnimplementedCallAsync(request, new CallOptions(headers, deadline, cancellationToken));
}
+ /// <summary>
+ /// A call that no server should implement
+ /// </summary>
public virtual AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, CallOptions options)
{
return CallInvoker.AsyncUnaryCall(__Method_UnimplementedCall, null, options, request);
@@ -350,13 +595,13 @@ namespace Grpc.Testing {
}
}
- // creates a new client
+ /// <summary>Creates a new client for UnimplementedService</summary>
public static UnimplementedServiceClient NewClient(Channel channel)
{
return new UnimplementedServiceClient(channel);
}
- // creates service definition that can be registered with a server
+ /// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(IUnimplementedService serviceImpl)
#pragma warning restore 0618
@@ -365,7 +610,7 @@ namespace Grpc.Testing {
.AddMethod(__Method_UnimplementedCall, serviceImpl.UnimplementedCall).Build();
}
- // creates service definition that can be registered with a server
+ /// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(UnimplementedServiceBase serviceImpl)
#pragma warning restore 0618
@@ -375,6 +620,9 @@ namespace Grpc.Testing {
}
}
+ /// <summary>
+ /// A service used to control reconnect server.
+ /// </summary>
public static class ReconnectService
{
static readonly string __ServiceName = "grpc.testing.ReconnectService";
@@ -397,13 +645,13 @@ namespace Grpc.Testing {
__Marshaller_Empty,
__Marshaller_ReconnectInfo);
- // service descriptor
+ /// <summary>Service descriptor</summary>
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
{
get { return global::Grpc.Testing.TestReflection.Descriptor.Services[2]; }
}
- // client interface
+ /// <summary>Client for ReconnectService</summary>
[System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
public interface IReconnectServiceClient
{
@@ -417,7 +665,7 @@ namespace Grpc.Testing {
AsyncUnaryCall<global::Grpc.Testing.ReconnectInfo> StopAsync(global::Grpc.Testing.Empty request, CallOptions options);
}
- // server-side interface
+ /// <summary>Interface of server-side implementations of ReconnectService</summary>
[System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
public interface IReconnectService
{
@@ -425,7 +673,7 @@ namespace Grpc.Testing {
Task<global::Grpc.Testing.ReconnectInfo> Stop(global::Grpc.Testing.Empty request, ServerCallContext context);
}
- // server-side abstract class
+ /// <summary>Base class for server-side implementations of ReconnectService</summary>
public abstract class ReconnectServiceBase
{
public virtual Task<global::Grpc.Testing.Empty> Start(global::Grpc.Testing.ReconnectParams request, ServerCallContext context)
@@ -440,7 +688,7 @@ namespace Grpc.Testing {
}
- // client stub
+ /// <summary>Client for ReconnectService</summary>
#pragma warning disable 0618
public class ReconnectServiceClient : ClientBase<ReconnectServiceClient>, IReconnectServiceClient
#pragma warning restore 0618
@@ -498,13 +746,13 @@ namespace Grpc.Testing {
}
}
- // creates a new client
+ /// <summary>Creates a new client for ReconnectService</summary>
public static ReconnectServiceClient NewClient(Channel channel)
{
return new ReconnectServiceClient(channel);
}
- // creates service definition that can be registered with a server
+ /// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(IReconnectService serviceImpl)
#pragma warning restore 0618
@@ -514,7 +762,7 @@ namespace Grpc.Testing {
.AddMethod(__Method_Stop, serviceImpl.Stop).Build();
}
- // creates service definition that can be registered with a server
+ /// <summary>Creates service definition that can be registered with a server</summary>
#pragma warning disable 0618
public static ServerServiceDefinition BindService(ReconnectServiceBase serviceImpl)
#pragma warning restore 0618
diff --git a/src/node/ext/node_grpc.cc b/src/node/ext/node_grpc.cc
index b988f29878..6b6e42737b 100644
--- a/src/node/ext/node_grpc.cc
+++ b/src/node/ext/node_grpc.cc
@@ -35,6 +35,8 @@
#include <nan.h>
#include <v8.h>
#include "grpc/grpc.h"
+#include "grpc/grpc_security.h"
+#include "grpc/support/alloc.h"
#include "call.h"
#include "call_credentials.h"
@@ -51,6 +53,8 @@ using v8::Object;
using v8::Uint32;
using v8::String;
+static char *pem_root_certs = NULL;
+
void InitStatusConstants(Local<Object> exports) {
Nan::HandleScope scope;
Local<Object> status = Nan::New<Object>();
@@ -268,9 +272,36 @@ NAN_METHOD(MetadataKeyIsBinary) {
grpc_is_binary_header(key_str, static_cast<size_t>(key->Length()))));
}
+static grpc_ssl_roots_override_result get_ssl_roots_override(
+ char **pem_root_certs_ptr) {
+ *pem_root_certs_ptr = pem_root_certs;
+ if (pem_root_certs == NULL) {
+ return GRPC_SSL_ROOTS_OVERRIDE_FAIL;
+ } else {
+ return GRPC_SSL_ROOTS_OVERRIDE_OK;
+ }
+}
+
+/* This should only be called once, and only before creating any
+ *ServerCredentials */
+NAN_METHOD(SetDefaultRootsPem) {
+ if (!info[0]->IsString()) {
+ return Nan::ThrowTypeError(
+ "setDefaultRootsPem's argument must be a string");
+ }
+ Nan::Utf8String utf8_roots(info[0]);
+ size_t length = static_cast<size_t>(utf8_roots.length());
+ if (length > 0) {
+ const char *data = *utf8_roots;
+ pem_root_certs = (char *)gpr_malloc((length + 1) * sizeof(char));
+ memcpy(pem_root_certs, data, length + 1);
+ }
+}
+
void init(Local<Object> exports) {
Nan::HandleScope scope;
grpc_init();
+ grpc_set_ssl_roots_override_callback(get_ssl_roots_override);
InitStatusConstants(exports);
InitCallErrorConstants(exports);
InitOpTypeConstants(exports);
@@ -298,6 +329,10 @@ void init(Local<Object> exports) {
Nan::GetFunction(
Nan::New<FunctionTemplate>(MetadataKeyIsBinary)
).ToLocalChecked());
+ Nan::Set(exports, Nan::New("setDefaultRootsPem").ToLocalChecked(),
+ Nan::GetFunction(
+ Nan::New<FunctionTemplate>(SetDefaultRootsPem)
+ ).ToLocalChecked());
}
NODE_MODULE(grpc_node, init)
diff --git a/src/node/ext/server_credentials.cc b/src/node/ext/server_credentials.cc
index cff821aafc..a817ade518 100644
--- a/src/node/ext/server_credentials.cc
+++ b/src/node/ext/server_credentials.cc
@@ -146,7 +146,9 @@ NAN_METHOD(ServerCredentials::CreateSsl) {
"createSsl's second argument must be a list of objects");
}
- grpc_ssl_client_certificate_request_type client_certificate_request;
+ // Default to not requesting the client certificate
+ grpc_ssl_client_certificate_request_type client_certificate_request =
+ GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE;
if (info[2]->IsBoolean()) {
client_certificate_request =
Nan::To<bool>(info[2]).FromJust()
diff --git a/src/node/index.js b/src/node/index.js
index d345a5142d..66664d94b5 100644
--- a/src/node/index.js
+++ b/src/node/index.js
@@ -34,13 +34,10 @@
'use strict';
var path = require('path');
+var fs = require('fs');
var SSL_ROOTS_PATH = path.resolve(__dirname, '..', '..', 'etc', 'roots.pem');
-if (!process.env.GRPC_DEFAULT_SSL_ROOTS_FILE_PATH) {
- process.env.GRPC_DEFAULT_SSL_ROOTS_FILE_PATH = SSL_ROOTS_PATH;
-}
-
var _ = require('lodash');
var ProtoBuf = require('protobufjs');
@@ -53,6 +50,8 @@ var Metadata = require('./src/metadata.js');
var grpc = require('./src/grpc_extension');
+grpc.setDefaultRootsPem(fs.readFileSync(SSL_ROOTS_PATH, 'ascii'));
+
/**
* Load a gRPC object from an existing ProtoBuf.Reflect object.
* @param {ProtoBuf.Reflect.Namespace} value The ProtoBuf object to load.
diff --git a/src/node/src/server.js b/src/node/src/server.js
index 22128343a9..fd5153f124 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -684,6 +684,26 @@ Server.prototype.register = function(name, handler, serialize, deserialize,
return true;
};
+var unimplementedStatusResponse = {
+ code: grpc.status.UNIMPLEMENTED,
+ details: 'The server does not implement this method'
+};
+
+var defaultHandler = {
+ unary: function(call, callback) {
+ callback(unimplementedStatusResponse);
+ },
+ client_stream: function(call, callback) {
+ callback(unimplementedStatusResponse);
+ },
+ server_stream: function(call) {
+ call.emit('error', unimplementedStatusResponse);
+ },
+ bidi: function(call) {
+ call.emit('error', unimplementedStatusResponse);
+ }
+};
+
/**
* Add a service to the server, with a corresponding implementation. If you are
* generating this from a proto file, you should instead use
@@ -713,16 +733,18 @@ Server.prototype.addService = function(service, implementation) {
method_type = 'unary';
}
}
+ var impl;
if (implementation[name] === undefined) {
- throw new Error('Method handler for ' + attrs.path +
- ' not provided.');
+ console.warn('Method handler for %s expected but not provided',
+ attrs.path);
+ impl = defaultHandler[method_type];
+ } else {
+ impl = _.bind(implementation[name], implementation);
}
var serialize = attrs.responseSerialize;
var deserialize = attrs.requestDeserialize;
- var register_success = self.register(attrs.path,
- _.bind(implementation[name],
- implementation),
- serialize, deserialize, method_type);
+ var register_success = self.register(attrs.path, impl, serialize,
+ deserialize, method_type);
if (!register_success) {
throw new Error('Method handler for ' + attrs.path +
' already provided.');
diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js
index b96e8e487c..d8b36dc55c 100644
--- a/src/node/test/surface_test.js
+++ b/src/node/test/surface_test.js
@@ -143,21 +143,59 @@ describe('Server.prototype.addProtoService', function() {
server.addProtoService(mathService, dummyImpls);
});
});
- it('Should fail with missing handlers', function() {
- assert.throws(function() {
- server.addProtoService(mathService, {
- 'div': function() {},
- 'divMany': function() {},
- 'fib': function() {}
- });
- }, /math.Math.Sum/);
- });
it('Should fail if the server has been started', function() {
server.start();
assert.throws(function() {
server.addProtoService(mathService, dummyImpls);
});
});
+ describe('Default handlers', function() {
+ var client;
+ beforeEach(function() {
+ server.addProtoService(mathService, {});
+ var port = server.bind('localhost:0', server_insecure_creds);
+ var Client = surface_client.makeProtobufClientConstructor(mathService);
+ client = new Client('localhost:' + port,
+ grpc.credentials.createInsecure());
+ server.start();
+ });
+ it('should respond to a unary call with UNIMPLEMENTED', function(done) {
+ client.div({divisor: 4, dividend: 3}, function(error, response) {
+ assert(error);
+ assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED);
+ done();
+ });
+ });
+ it('should respond to a client stream with UNIMPLEMENTED', function(done) {
+ var call = client.sum(function(error, respones) {
+ assert(error);
+ assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED);
+ done();
+ });
+ call.end();
+ });
+ it('should respond to a server stream with UNIMPLEMENTED', function(done) {
+ var call = client.fib({limit: 5});
+ call.on('data', function(value) {
+ assert.fail('No messages expected');
+ });
+ call.on('status', function(status) {
+ assert.strictEqual(status.code, grpc.status.UNIMPLEMENTED);
+ done();
+ });
+ });
+ it('should respond to a bidi call with UNIMPLEMENTED', function(done) {
+ var call = client.divMany();
+ call.on('data', function(value) {
+ assert.fail('No messages expected');
+ });
+ call.on('status', function(status) {
+ assert.strictEqual(status.code, grpc.status.UNIMPLEMENTED);
+ done();
+ });
+ call.end();
+ });
+ });
});
describe('Client constructor building', function() {
var illegal_service_attrs = {
diff --git a/src/python/grpcio/README.rst b/src/python/grpcio/README.rst
index 33a462b66f..cb3f6b87fe 100644
--- a/src/python/grpcio/README.rst
+++ b/src/python/grpcio/README.rst
@@ -23,6 +23,16 @@ Else system wide (on Ubuntu)...
$ sudo pip install grpcio
+If you're on Windows make sure that you installed the :code:`pip.exe` component
+when you installed Python (if not go back and install it!) then invoke:
+
+::
+
+ $ pip.exe install grpcio
+
+Windows users may need to invoke :code:`pip.exe` from a command line ran as
+administrator.
+
n.b. On Windows and on Mac OS X one *must* have a recent release of :code:`pip`
to retrieve the proper wheel from PyPI. Be sure to upgrade to the latest
version!
@@ -43,6 +53,9 @@ package named :code:`python-dev`).
$ pip install -rrequirements.txt
$ GRPC_PYTHON_BUILD_WITH_CYTHON=1 pip install .
+You cannot currently install Python from source on Windows. Things might work
+out for you in MSYS2 (follow the Linux instructions), but it isn't officially
+supported at the moment.
Troubleshooting
~~~~~~~~~~~~~~~
diff --git a/src/python/grpcio/grpc/_cython/imports.generated.c b/src/python/grpcio/grpc/_cython/imports.generated.c
index 9ab0696702..f0a40dbb35 100644
--- a/src/python/grpcio/grpc/_cython/imports.generated.c
+++ b/src/python/grpcio/grpc/_cython/imports.generated.c
@@ -124,6 +124,7 @@ grpc_tracer_set_enabled_type grpc_tracer_set_enabled_import;
grpc_header_key_is_legal_type grpc_header_key_is_legal_import;
grpc_header_nonbin_value_is_legal_type grpc_header_nonbin_value_is_legal_import;
grpc_is_binary_header_type grpc_is_binary_header_import;
+grpc_call_error_to_string_type grpc_call_error_to_string_import;
grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import;
grpc_auth_context_property_iterator_type grpc_auth_context_property_iterator_import;
grpc_auth_context_peer_identity_type grpc_auth_context_peer_identity_import;
@@ -393,6 +394,7 @@ void pygrpc_load_imports(HMODULE library) {
grpc_header_key_is_legal_import = (grpc_header_key_is_legal_type) GetProcAddress(library, "grpc_header_key_is_legal");
grpc_header_nonbin_value_is_legal_import = (grpc_header_nonbin_value_is_legal_type) GetProcAddress(library, "grpc_header_nonbin_value_is_legal");
grpc_is_binary_header_import = (grpc_is_binary_header_type) GetProcAddress(library, "grpc_is_binary_header");
+ grpc_call_error_to_string_import = (grpc_call_error_to_string_type) GetProcAddress(library, "grpc_call_error_to_string");
grpc_auth_property_iterator_next_import = (grpc_auth_property_iterator_next_type) GetProcAddress(library, "grpc_auth_property_iterator_next");
grpc_auth_context_property_iterator_import = (grpc_auth_context_property_iterator_type) GetProcAddress(library, "grpc_auth_context_property_iterator");
grpc_auth_context_peer_identity_import = (grpc_auth_context_peer_identity_type) GetProcAddress(library, "grpc_auth_context_peer_identity");
diff --git a/src/python/grpcio/grpc/_cython/imports.generated.h b/src/python/grpcio/grpc/_cython/imports.generated.h
index e50051ddc7..d5e810b7cf 100644
--- a/src/python/grpcio/grpc/_cython/imports.generated.h
+++ b/src/python/grpcio/grpc/_cython/imports.generated.h
@@ -322,6 +322,9 @@ extern grpc_header_nonbin_value_is_legal_type grpc_header_nonbin_value_is_legal_
typedef int(*grpc_is_binary_header_type)(const char *key, size_t length);
extern grpc_is_binary_header_type grpc_is_binary_header_import;
#define grpc_is_binary_header grpc_is_binary_header_import
+typedef const char *(*grpc_call_error_to_string_type)(grpc_call_error error);
+extern grpc_call_error_to_string_type grpc_call_error_to_string_import;
+#define grpc_call_error_to_string grpc_call_error_to_string_import
typedef const grpc_auth_property *(*grpc_auth_property_iterator_next_type)(grpc_auth_property_iterator *it);
extern grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import;
#define grpc_auth_property_iterator_next grpc_auth_property_iterator_next_import
diff --git a/src/python/grpcio/tests/protoc_plugin/beta_python_plugin_test.py b/src/python/grpcio/tests/protoc_plugin/beta_python_plugin_test.py
index 6fba3d4271..3dc3042e38 100644
--- a/src/python/grpcio/tests/protoc_plugin/beta_python_plugin_test.py
+++ b/src/python/grpcio/tests/protoc_plugin/beta_python_plugin_test.py
@@ -45,6 +45,7 @@ import unittest
from six import moves
from grpc.beta import implementations
+from grpc.beta import interfaces
from grpc.framework.foundation import future
from grpc.framework.interfaces.face import face
from tests.unit.framework.common import test_constants
@@ -178,6 +179,36 @@ def _CreateService(test_pb2):
server.stop(0)
+@contextlib.contextmanager
+def _CreateIncompleteService(test_pb2):
+ """Provides a servicer backend that fails to implement methods and its stub.
+
+ The servicer is just the implementation of the actual servicer passed to the
+ face player of the python RPC implementation; the two are detached.
+
+ Args:
+ test_pb2: The test_pb2 module generated by this test.
+
+ Yields:
+ A (servicer_methods, stub) pair where servicer_methods is the back-end of
+ the service bound to the stub and and stub is the stub on which to invoke
+ RPCs.
+ """
+ servicer_methods = _ServicerMethods(test_pb2)
+
+ class Servicer(getattr(test_pb2, SERVICER_IDENTIFIER)):
+ pass
+
+ servicer = Servicer()
+ server = getattr(test_pb2, SERVER_FACTORY_IDENTIFIER)(servicer)
+ port = server.add_insecure_port('[::]:0')
+ server.start()
+ channel = implementations.insecure_channel('localhost', port)
+ stub = getattr(test_pb2, STUB_FACTORY_IDENTIFIER)(channel)
+ yield servicer_methods, stub
+ server.stop(0)
+
+
def _streaming_input_request_iterator(test_pb2):
for _ in range(3):
request = test_pb2.StreamingInputCallRequest()
@@ -264,6 +295,16 @@ class PythonPluginTest(unittest.TestCase):
with _CreateService(test_pb2) as (servicer, stub):
request = test_pb2.SimpleRequest(response_size=13)
+ def testIncompleteServicer(self):
+ import protoc_plugin_test_pb2 as test_pb2
+ moves.reload_module(test_pb2)
+ with _CreateIncompleteService(test_pb2) as (servicer, stub):
+ request = test_pb2.SimpleRequest(response_size=13)
+ try:
+ response = stub.UnaryCall(request, test_constants.LONG_TIMEOUT)
+ except face.AbortionError as error:
+ self.assertEqual(interfaces.StatusCode.UNIMPLEMENTED, error.code)
+
def testUnaryCall(self):
import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top
moves.reload_module(test_pb2)
diff --git a/src/python/grpcio/tests/qps/__init__.py b/src/python/grpcio/tests/qps/__init__.py
new file mode 100644
index 0000000000..100a624dc9
--- /dev/null
+++ b/src/python/grpcio/tests/qps/__init__.py
@@ -0,0 +1,28 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/src/python/grpcio/tests/qps/benchmark_client.py b/src/python/grpcio/tests/qps/benchmark_client.py
new file mode 100644
index 0000000000..eed0b0c6da
--- /dev/null
+++ b/src/python/grpcio/tests/qps/benchmark_client.py
@@ -0,0 +1,186 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Defines test client behaviors (UNARY/STREAMING) (SYNC/ASYNC)."""
+
+import abc
+import time
+try:
+ import Queue as queue # Python 2.x
+except ImportError:
+ import queue # Python 3
+
+from concurrent import futures
+
+from grpc.beta import implementations
+from src.proto.grpc.testing import messages_pb2
+from src.proto.grpc.testing import services_pb2
+from tests.unit import resources
+from tests.unit.beta import test_utilities
+
+_TIMEOUT = 60 * 60 * 24
+
+
+class BenchmarkClient:
+ """Benchmark client interface that exposes a non-blocking send_request()."""
+
+ __metaclass__ = abc.ABCMeta
+
+ def __init__(self, server, config, hist):
+ # Create the stub
+ host, port = server.split(':')
+ port = int(port)
+ if config.HasField('security_params'):
+ creds = implementations.ssl_channel_credentials(
+ resources.test_root_certificates())
+ channel = test_utilities.not_really_secure_channel(
+ host, port, creds, config.security_params.server_host_override)
+ else:
+ channel = implementations.insecure_channel(host, port)
+
+ if config.payload_config.WhichOneof('payload') == 'simple_params':
+ self._generic = False
+ self._stub = services_pb2.beta_create_BenchmarkService_stub(channel)
+ payload = messages_pb2.Payload(
+ body='\0' * config.payload_config.simple_params.req_size)
+ self._request = messages_pb2.SimpleRequest(
+ payload=payload,
+ response_size=config.payload_config.simple_params.resp_size)
+ else:
+ self._generic = True
+ self._stub = implementations.generic_stub(channel)
+ self._request = '\0' * config.payload_config.bytebuf_params.req_size
+
+ self._hist = hist
+ self._response_callbacks = []
+
+ def add_response_callback(self, callback):
+ self._response_callbacks.append(callback)
+
+ @abc.abstractmethod
+ def send_request(self):
+ """Non-blocking wrapper for a client's request operation."""
+ raise NotImplementedError()
+
+ def start(self):
+ pass
+
+ def stop(self):
+ pass
+
+ def _handle_response(self, query_time):
+ self._hist.add(query_time * 1e9) # Report times in nanoseconds
+ for callback in self._response_callbacks:
+ callback(query_time)
+
+
+class UnarySyncBenchmarkClient(BenchmarkClient):
+
+ def __init__(self, server, config, hist):
+ super(UnarySyncBenchmarkClient, self).__init__(server, config, hist)
+ self._pool = futures.ThreadPoolExecutor(
+ max_workers=config.outstanding_rpcs_per_channel)
+
+ def send_request(self):
+ # Send requests in seperate threads to support multiple outstanding rpcs
+ # (See src/proto/grpc/testing/control.proto)
+ self._pool.submit(self._dispatch_request)
+
+ def stop(self):
+ self._pool.shutdown(wait=True)
+ self._stub = None
+
+ def _dispatch_request(self):
+ start_time = time.time()
+ self._stub.UnaryCall(self._request, _TIMEOUT)
+ end_time = time.time()
+ self._handle_response(end_time - start_time)
+
+
+class UnaryAsyncBenchmarkClient(BenchmarkClient):
+
+ def send_request(self):
+ # Use the Future callback api to support multiple outstanding rpcs
+ start_time = time.time()
+ response_future = self._stub.UnaryCall.future(self._request, _TIMEOUT)
+ response_future.add_done_callback(
+ lambda resp: self._response_received(start_time, resp))
+
+ def _response_received(self, start_time, resp):
+ resp.result()
+ end_time = time.time()
+ self._handle_response(end_time - start_time)
+
+ def stop(self):
+ self._stub = None
+
+
+class StreamingAsyncBenchmarkClient(BenchmarkClient):
+
+ def __init__(self, server, config, hist):
+ super(StreamingAsyncBenchmarkClient, self).__init__(server, config, hist)
+ self._is_streaming = False
+ self._pool = futures.ThreadPoolExecutor(max_workers=1)
+ # Use a thread-safe queue to put requests on the stream
+ self._request_queue = queue.Queue()
+ self._send_time_queue = queue.Queue()
+
+ def send_request(self):
+ self._send_time_queue.put(time.time())
+ self._request_queue.put(self._request)
+
+ def start(self):
+ self._is_streaming = True
+ self._pool.submit(self._request_stream)
+
+ def stop(self):
+ self._is_streaming = False
+ self._pool.shutdown(wait=True)
+ self._stub = None
+
+ def _request_stream(self):
+ self._is_streaming = True
+ if self._generic:
+ response_stream = self._stub.inline_stream_stream(
+ 'grpc.testing.BenchmarkService', 'StreamingCall',
+ self._request_generator(), _TIMEOUT)
+ else:
+ response_stream = self._stub.StreamingCall(self._request_generator(),
+ _TIMEOUT)
+ for _ in response_stream:
+ end_time = time.time()
+ self._handle_response(end_time - self._send_time_queue.get_nowait())
+
+ def _request_generator(self):
+ while self._is_streaming:
+ try:
+ request = self._request_queue.get(block=True, timeout=1.0)
+ yield request
+ except queue.Empty:
+ pass
diff --git a/src/python/grpcio/tests/qps/benchmark_server.py b/src/python/grpcio/tests/qps/benchmark_server.py
new file mode 100644
index 0000000000..8cbf480d58
--- /dev/null
+++ b/src/python/grpcio/tests/qps/benchmark_server.py
@@ -0,0 +1,58 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from src.proto.grpc.testing import messages_pb2
+from src.proto.grpc.testing import services_pb2
+
+
+class BenchmarkServer(services_pb2.BetaBenchmarkServiceServicer):
+ """Synchronous Server implementation for the Benchmark service."""
+
+ def UnaryCall(self, request, context):
+ payload = messages_pb2.Payload(body='\0' * request.response_size)
+ return messages_pb2.SimpleResponse(payload=payload)
+
+ def StreamingCall(self, request_iterator, context):
+ for request in request_iterator:
+ payload = messages_pb2.Payload(body='\0' * request.response_size)
+ yield messages_pb2.SimpleResponse(payload=payload)
+
+
+class GenericBenchmarkServer(services_pb2.BetaBenchmarkServiceServicer):
+ """Generic Server implementation for the Benchmark service."""
+
+ def __init__(self, resp_size):
+ self._response = '\0' * resp_size
+
+ def UnaryCall(self, request, context):
+ return self._response
+
+ def StreamingCall(self, request_iterator, context):
+ for request in request_iterator:
+ yield self._response
diff --git a/src/python/grpcio/tests/qps/client_runner.py b/src/python/grpcio/tests/qps/client_runner.py
new file mode 100644
index 0000000000..a36c30ccc0
--- /dev/null
+++ b/src/python/grpcio/tests/qps/client_runner.py
@@ -0,0 +1,104 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Defines behavior for WHEN clients send requests.
+
+Each client exposes a non-blocking send_request() method that the
+ClientRunner invokes either periodically or in response to some event.
+"""
+
+import abc
+import thread
+import time
+
+
+class ClientRunner:
+ """Abstract interface for sending requests from clients."""
+
+ __metaclass__ = abc.ABCMeta
+
+ def __init__(self, client):
+ self._client = client
+
+ @abc.abstractmethod
+ def start(self):
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def stop(self):
+ raise NotImplementedError()
+
+
+class OpenLoopClientRunner(ClientRunner):
+
+ def __init__(self, client, interval_generator):
+ super(OpenLoopClientRunner, self).__init__(client)
+ self._is_running = False
+ self._interval_generator = interval_generator
+
+ def start(self):
+ self._is_running = True
+ self._client.start()
+ thread.start_new_thread(self._dispatch_requests, ())
+
+ def stop(self):
+ self._is_running = False
+ self._client.stop()
+ self._client = None
+
+ def _dispatch_requests(self):
+ while self._is_running:
+ self._client.send_request()
+ time.sleep(next(self._interval_generator))
+
+
+class ClosedLoopClientRunner(ClientRunner):
+
+ def __init__(self, client, request_count):
+ super(ClosedLoopClientRunner, self).__init__(client)
+ self._is_running = False
+ self._request_count = request_count
+ # Send a new request on each response for closed loop
+ self._client.add_response_callback(self._send_request)
+
+ def start(self):
+ self._is_running = True
+ for _ in xrange(self._request_count):
+ self._client.send_request()
+ self._client.start()
+
+ def stop(self):
+ self._is_running = False
+ self._client.stop()
+ self._client = None
+
+ def _send_request(self, response_time):
+ if self._is_running:
+ self._client.send_request()
+
diff --git a/src/python/grpcio/tests/qps/histogram.py b/src/python/grpcio/tests/qps/histogram.py
new file mode 100644
index 0000000000..9a7b5eb2ba
--- /dev/null
+++ b/src/python/grpcio/tests/qps/histogram.py
@@ -0,0 +1,85 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import math
+import threading
+
+from src.proto.grpc.testing import stats_pb2
+
+
+class Histogram(object):
+ """Histogram class used for recording performance testing data.
+
+ This class is thread safe.
+ """
+
+ def __init__(self, resolution, max_possible):
+ self._lock = threading.Lock()
+ self._resolution = resolution
+ self._max_possible = max_possible
+ self._sum = 0
+ self._sum_of_squares = 0
+ self.multiplier = 1.0 + self._resolution
+ self._count = 0
+ self._min = self._max_possible
+ self._max = 0
+ self._buckets = [0] * (self._bucket_for(self._max_possible) + 1)
+
+ def reset(self):
+ with self._lock:
+ self._sum = 0
+ self._sum_of_squares = 0
+ self._count = 0
+ self._min = self._max_possible
+ self._max = 0
+ self._buckets = [0] * (self._bucket_for(self._max_possible) + 1)
+
+ def add(self, val):
+ with self._lock:
+ self._sum += val
+ self._sum_of_squares += val * val
+ self._count += 1
+ self._min = min(self._min, val)
+ self._max = max(self._max, val)
+ self._buckets[self._bucket_for(val)] += 1
+
+ def get_data(self):
+ with self._lock:
+ data = stats_pb2.HistogramData()
+ data.bucket.extend(self._buckets)
+ data.min_seen = self._min
+ data.max_seen = self._max
+ data.sum = self._sum
+ data.sum_of_squares = self._sum_of_squares
+ data.count = self._count
+ return data
+
+ def _bucket_for(self, val):
+ val = min(val, self._max_possible)
+ return int(math.log(val, self.multiplier))
diff --git a/src/python/grpcio/tests/qps/qps_worker.py b/src/python/grpcio/tests/qps/qps_worker.py
new file mode 100644
index 0000000000..3dda718638
--- /dev/null
+++ b/src/python/grpcio/tests/qps/qps_worker.py
@@ -0,0 +1,60 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""The entry point for the qps worker."""
+
+import argparse
+import time
+
+from src.proto.grpc.testing import services_pb2
+
+from tests.qps import worker_server
+
+
+def run_worker_server(port):
+ servicer = worker_server.WorkerServer()
+ server = services_pb2.beta_create_WorkerService_server(servicer)
+ server.add_insecure_port('[::]:{}'.format(port))
+ server.start()
+ servicer.wait_for_quit()
+ # Drain outstanding requests for clean exit
+ time.sleep(2)
+ server.stop(0)
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(
+ description='gRPC Python performance testing worker')
+ parser.add_argument('--driver_port',
+ type=int,
+ dest='port',
+ help='The port the worker should listen on')
+ args = parser.parse_args()
+
+ run_worker_server(args.port)
diff --git a/src/python/grpcio/tests/qps/worker_server.py b/src/python/grpcio/tests/qps/worker_server.py
new file mode 100644
index 0000000000..0b3acc14e7
--- /dev/null
+++ b/src/python/grpcio/tests/qps/worker_server.py
@@ -0,0 +1,184 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import multiprocessing
+import random
+import threading
+import time
+
+from grpc.beta import implementations
+from grpc.framework.interfaces.face import utilities
+from src.proto.grpc.testing import control_pb2
+from src.proto.grpc.testing import services_pb2
+from src.proto.grpc.testing import stats_pb2
+
+from tests.qps import benchmark_client
+from tests.qps import benchmark_server
+from tests.qps import client_runner
+from tests.qps import histogram
+from tests.unit import resources
+
+
+class WorkerServer(services_pb2.BetaWorkerServiceServicer):
+ """Python Worker Server implementation."""
+
+ def __init__(self):
+ self._quit_event = threading.Event()
+
+ def RunServer(self, request_iterator, context):
+ config = next(request_iterator).setup
+ server, port = self._create_server(config)
+ cores = multiprocessing.cpu_count()
+ server.start()
+ start_time = time.time()
+ yield self._get_server_status(start_time, start_time, port, cores)
+
+ for request in request_iterator:
+ end_time = time.time()
+ status = self._get_server_status(start_time, end_time, port, cores)
+ if request.mark.reset:
+ start_time = end_time
+ yield status
+ server.stop(0)
+
+ def _get_server_status(self, start_time, end_time, port, cores):
+ end_time = time.time()
+ elapsed_time = end_time - start_time
+ stats = stats_pb2.ServerStats(time_elapsed=elapsed_time,
+ time_user=elapsed_time,
+ time_system=elapsed_time)
+ return control_pb2.ServerStatus(stats=stats, port=port, cores=cores)
+
+ def _create_server(self, config):
+ if config.server_type == control_pb2.SYNC_SERVER:
+ servicer = benchmark_server.BenchmarkServer()
+ server = services_pb2.beta_create_BenchmarkService_server(servicer)
+ elif config.server_type == control_pb2.ASYNC_GENERIC_SERVER:
+ resp_size = config.payload_config.bytebuf_params.resp_size
+ servicer = benchmark_server.GenericBenchmarkServer(resp_size)
+ method_implementations = {
+ ('grpc.testing.BenchmarkService', 'StreamingCall'):
+ utilities.stream_stream_inline(servicer.StreamingCall),
+ ('grpc.testing.BenchmarkService', 'UnaryCall'):
+ utilities.unary_unary_inline(servicer.UnaryCall),
+ }
+ server = implementations.server(method_implementations)
+ else:
+ raise Exception('Unsupported server type {}'.format(config.server_type))
+
+ if config.HasField('security_params'): # Use SSL
+ server_creds = implementations.ssl_server_credentials([(
+ resources.private_key(), resources.certificate_chain())])
+ port = server.add_secure_port('[::]:{}'.format(config.port), server_creds)
+ else:
+ port = server.add_insecure_port('[::]:{}'.format(config.port))
+
+ return (server, port)
+
+ def RunClient(self, request_iterator, context):
+ config = next(request_iterator).setup
+ client_runners = []
+ qps_data = histogram.Histogram(config.histogram_params.resolution,
+ config.histogram_params.max_possible)
+ start_time = time.time()
+
+ # Create a client for each channel
+ for i in xrange(config.client_channels):
+ server = config.server_targets[i % len(config.server_targets)]
+ runner = self._create_client_runner(server, config, qps_data)
+ client_runners.append(runner)
+ runner.start()
+
+ end_time = time.time()
+ yield self._get_client_status(start_time, end_time, qps_data)
+
+ # Respond to stat requests
+ for request in request_iterator:
+ end_time = time.time()
+ status = self._get_client_status(start_time, end_time, qps_data)
+ if request.mark.reset:
+ qps_data.reset()
+ start_time = time.time()
+ yield status
+
+ # Cleanup the clients
+ for runner in client_runners:
+ runner.stop()
+
+ def _get_client_status(self, start_time, end_time, qps_data):
+ latencies = qps_data.get_data()
+ end_time = time.time()
+ elapsed_time = end_time - start_time
+ stats = stats_pb2.ClientStats(latencies=latencies,
+ time_elapsed=elapsed_time,
+ time_user=elapsed_time,
+ time_system=elapsed_time)
+ return control_pb2.ClientStatus(stats=stats)
+
+ def _create_client_runner(self, server, config, qps_data):
+ if config.client_type == control_pb2.SYNC_CLIENT:
+ if config.rpc_type == control_pb2.UNARY:
+ client = benchmark_client.UnarySyncBenchmarkClient(
+ server, config, qps_data)
+ else:
+ raise Exception('STREAMING SYNC client not supported')
+ elif config.client_type == control_pb2.ASYNC_CLIENT:
+ if config.rpc_type == control_pb2.UNARY:
+ client = benchmark_client.UnaryAsyncBenchmarkClient(
+ server, config, qps_data)
+ elif config.rpc_type == control_pb2.STREAMING:
+ client = benchmark_client.StreamingAsyncBenchmarkClient(
+ server, config, qps_data)
+ else:
+ raise Exception('Unsupported client type {}'.format(config.client_type))
+
+ # In multi-channel tests, we split the load across all channels
+ load_factor = float(config.client_channels)
+ if config.load_params.WhichOneof('load') == 'closed_loop':
+ runner = client_runner.ClosedLoopClientRunner(
+ client, config.outstanding_rpcs_per_channel)
+ else: # Open loop Poisson
+ alpha = config.load_params.poisson.offered_load / load_factor
+ def poisson():
+ while True:
+ yield random.expovariate(alpha)
+
+ runner = client_runner.OpenLoopClientRunner(client, poisson())
+
+ return runner
+
+ def CoreCount(self, request, context):
+ return control_pb2.CoreResponse(cores=multiprocessing.cpu_count())
+
+ def QuitWorker(self, request, context):
+ self._quit_event.set()
+ return control_pb2.Void()
+
+ def wait_for_quit(self):
+ self._quit_event.wait()
diff --git a/src/ruby/ext/grpc/rb_channel_credentials.c b/src/ruby/ext/grpc/rb_channel_credentials.c
index 10391bc963..09bd3093a9 100644
--- a/src/ruby/ext/grpc/rb_channel_credentials.c
+++ b/src/ruby/ext/grpc/rb_channel_credentials.c
@@ -31,6 +31,8 @@
*
*/
+#include <string.h>
+
#include <ruby/ruby.h>
#include "rb_grpc_imports.generated.h"
#include "rb_channel_credentials.h"
@@ -39,6 +41,7 @@
#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
+#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "rb_call_credentials.h"
@@ -48,6 +51,8 @@
grpc_channel_credentials. */
static VALUE grpc_rb_cChannelCredentials = Qnil;
+static char *pem_root_certs = NULL;
+
/* grpc_rb_channel_credentials wraps a grpc_channel_credentials. It provides a
* mark object that is used to hold references to any objects used to create
* the credentials. */
@@ -236,6 +241,25 @@ static VALUE grpc_rb_channel_credentials_compose(int argc, VALUE *argv,
return grpc_rb_wrap_channel_credentials(creds, mark);
}
+static grpc_ssl_roots_override_result get_ssl_roots_override(
+ char **pem_root_certs_ptr) {
+ *pem_root_certs_ptr = pem_root_certs;
+ if (pem_root_certs == NULL) {
+ return GRPC_SSL_ROOTS_OVERRIDE_FAIL;
+ } else {
+ return GRPC_SSL_ROOTS_OVERRIDE_OK;
+ }
+}
+
+static VALUE grpc_rb_set_default_roots_pem(VALUE self, VALUE roots) {
+ char *roots_ptr = StringValueCStr(roots);
+ size_t length = strlen(roots_ptr);
+ (void)self;
+ pem_root_certs = gpr_malloc((length + 1) * sizeof(char));
+ memcpy(pem_root_certs, roots_ptr, length + 1);
+ return Qnil;
+}
+
void Init_grpc_channel_credentials() {
grpc_rb_cChannelCredentials =
rb_define_class_under(grpc_rb_mGrpcCore, "ChannelCredentials", rb_cObject);
@@ -251,6 +275,11 @@ void Init_grpc_channel_credentials() {
grpc_rb_channel_credentials_init_copy, 1);
rb_define_method(grpc_rb_cChannelCredentials, "compose",
grpc_rb_channel_credentials_compose, -1);
+ rb_define_module_function(grpc_rb_cChannelCredentials,
+ "set_default_roots_pem",
+ grpc_rb_set_default_roots_pem, 1);
+
+ grpc_set_ssl_roots_override_callback(get_ssl_roots_override);
id_pem_cert_chain = rb_intern("__pem_cert_chain");
id_pem_private_key = rb_intern("__pem_private_key");
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
index e2068d752a..bc43f9d36b 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
@@ -124,6 +124,7 @@ grpc_tracer_set_enabled_type grpc_tracer_set_enabled_import;
grpc_header_key_is_legal_type grpc_header_key_is_legal_import;
grpc_header_nonbin_value_is_legal_type grpc_header_nonbin_value_is_legal_import;
grpc_is_binary_header_type grpc_is_binary_header_import;
+grpc_call_error_to_string_type grpc_call_error_to_string_import;
grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import;
grpc_auth_context_property_iterator_type grpc_auth_context_property_iterator_import;
grpc_auth_context_peer_identity_type grpc_auth_context_peer_identity_import;
@@ -389,6 +390,7 @@ void grpc_rb_load_imports(HMODULE library) {
grpc_header_key_is_legal_import = (grpc_header_key_is_legal_type) GetProcAddress(library, "grpc_header_key_is_legal");
grpc_header_nonbin_value_is_legal_import = (grpc_header_nonbin_value_is_legal_type) GetProcAddress(library, "grpc_header_nonbin_value_is_legal");
grpc_is_binary_header_import = (grpc_is_binary_header_type) GetProcAddress(library, "grpc_is_binary_header");
+ grpc_call_error_to_string_import = (grpc_call_error_to_string_type) GetProcAddress(library, "grpc_call_error_to_string");
grpc_auth_property_iterator_next_import = (grpc_auth_property_iterator_next_type) GetProcAddress(library, "grpc_auth_property_iterator_next");
grpc_auth_context_property_iterator_import = (grpc_auth_context_property_iterator_type) GetProcAddress(library, "grpc_auth_context_property_iterator");
grpc_auth_context_peer_identity_import = (grpc_auth_context_peer_identity_type) GetProcAddress(library, "grpc_auth_context_peer_identity");
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
index c8d21333ba..b67361ca25 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
@@ -322,6 +322,9 @@ extern grpc_header_nonbin_value_is_legal_type grpc_header_nonbin_value_is_legal_
typedef int(*grpc_is_binary_header_type)(const char *key, size_t length);
extern grpc_is_binary_header_type grpc_is_binary_header_import;
#define grpc_is_binary_header grpc_is_binary_header_import
+typedef const char *(*grpc_call_error_to_string_type)(grpc_call_error error);
+extern grpc_call_error_to_string_type grpc_call_error_to_string_import;
+#define grpc_call_error_to_string grpc_call_error_to_string_import
typedef const grpc_auth_property *(*grpc_auth_property_iterator_next_type)(grpc_auth_property_iterator *it);
extern grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import;
#define grpc_auth_property_iterator_next grpc_auth_property_iterator_next_import
diff --git a/src/ruby/lib/grpc.rb b/src/ruby/lib/grpc.rb
index a56c49ff59..79fa705b1c 100644
--- a/src/ruby/lib/grpc.rb
+++ b/src/ruby/lib/grpc.rb
@@ -28,9 +28,6 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
ssl_roots_path = File.expand_path('../../../../etc/roots.pem', __FILE__)
-unless ENV['GRPC_DEFAULT_SSL_ROOTS_FILE_PATH']
- ENV['GRPC_DEFAULT_SSL_ROOTS_FILE_PATH'] = ssl_roots_path
-end
require_relative 'grpc/errors'
require_relative 'grpc/grpc'
@@ -42,3 +39,11 @@ require_relative 'grpc/generic/active_call'
require_relative 'grpc/generic/client_stub'
require_relative 'grpc/generic/service'
require_relative 'grpc/generic/rpc_server'
+
+begin
+ file = File.open(ssl_roots_path)
+ roots = file.read
+ GRPC::Core::ChannelCredentials.set_default_roots_pem roots
+ensure
+ file.close
+end
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile.template
new file mode 100644
index 0000000000..4cb8d3b088
--- /dev/null
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile.template
@@ -0,0 +1,39 @@
+%YAML 1.2
+--- |
+ # Copyright 2015, Google Inc.
+ # All rights reserved.
+ #
+ # Redistribution and use in source and binary forms, with or without
+ # modification, are permitted provided that the following conditions are
+ # met:
+ #
+ # * Redistributions of source code must retain the above copyright
+ # notice, this list of conditions and the following disclaimer.
+ # * Redistributions in binary form must reproduce the above
+ # copyright notice, this list of conditions and the following disclaimer
+ # in the documentation and/or other materials provided with the
+ # distribution.
+ # * Neither the name of Google Inc. nor the names of its
+ # contributors may be used to endorse or promote products derived from
+ # this software without specific prior written permission.
+ #
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ FROM debian:jessie
+
+ <%include file="../../apt_get_basic.include"/>
+ <%include file="../../csharp_deps.include"/>
+ <%include file="../../run_tests_addons.include"/>
+ # Define the default command.
+ CMD ["bash"]
+
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile.template
new file mode 100644
index 0000000000..e39175a1ea
--- /dev/null
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile.template
@@ -0,0 +1,39 @@
+%YAML 1.2
+--- |
+ # Copyright 2015, Google Inc.
+ # All rights reserved.
+ #
+ # Redistribution and use in source and binary forms, with or without
+ # modification, are permitted provided that the following conditions are
+ # met:
+ #
+ # * Redistributions of source code must retain the above copyright
+ # notice, this list of conditions and the following disclaimer.
+ # * Redistributions in binary form must reproduce the above
+ # copyright notice, this list of conditions and the following disclaimer
+ # in the documentation and/or other materials provided with the
+ # distribution.
+ # * Neither the name of Google Inc. nor the names of its
+ # contributors may be used to endorse or promote products derived from
+ # this software without specific prior written permission.
+ #
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ FROM debian:jessie
+
+ <%include file="../../apt_get_basic.include"/>
+ <%include file="../../cxx_deps.include"/>
+ <%include file="../../run_tests_addons.include"/>
+ # Define the default command.
+ CMD ["bash"]
+
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile.template
new file mode 100644
index 0000000000..542c81d614
--- /dev/null
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile.template
@@ -0,0 +1,37 @@
+%YAML 1.2
+--- |
+ # Copyright 2015, Google Inc.
+ # All rights reserved.
+ #
+ # Redistribution and use in source and binary forms, with or without
+ # modification, are permitted provided that the following conditions are
+ # met:
+ #
+ # * Redistributions of source code must retain the above copyright
+ # notice, this list of conditions and the following disclaimer.
+ # * Redistributions in binary form must reproduce the above
+ # copyright notice, this list of conditions and the following disclaimer
+ # in the documentation and/or other materials provided with the
+ # distribution.
+ # * Neither the name of Google Inc. nor the names of its
+ # contributors may be used to endorse or promote products derived from
+ # this software without specific prior written permission.
+ #
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ FROM golang:1.5
+
+ <%include file="../../go_path.include"/>
+ # Define the default command.
+ CMD ["bash"]
+
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile.template
new file mode 100644
index 0000000000..542c81d614
--- /dev/null
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile.template
@@ -0,0 +1,37 @@
+%YAML 1.2
+--- |
+ # Copyright 2015, Google Inc.
+ # All rights reserved.
+ #
+ # Redistribution and use in source and binary forms, with or without
+ # modification, are permitted provided that the following conditions are
+ # met:
+ #
+ # * Redistributions of source code must retain the above copyright
+ # notice, this list of conditions and the following disclaimer.
+ # * Redistributions in binary form must reproduce the above
+ # copyright notice, this list of conditions and the following disclaimer
+ # in the documentation and/or other materials provided with the
+ # distribution.
+ # * Neither the name of Google Inc. nor the names of its
+ # contributors may be used to endorse or promote products derived from
+ # this software without specific prior written permission.
+ #
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ FROM golang:1.5
+
+ <%include file="../../go_path.include"/>
+ # Define the default command.
+ CMD ["bash"]
+
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile.template
new file mode 100644
index 0000000000..c286e80826
--- /dev/null
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile.template
@@ -0,0 +1,44 @@
+%YAML 1.2
+--- |
+ # Copyright 2015, Google Inc.
+ # All rights reserved.
+ #
+ # Redistribution and use in source and binary forms, with or without
+ # modification, are permitted provided that the following conditions are
+ # met:
+ #
+ # * Redistributions of source code must retain the above copyright
+ # notice, this list of conditions and the following disclaimer.
+ # * Redistributions in binary form must reproduce the above
+ # copyright notice, this list of conditions and the following disclaimer
+ # in the documentation and/or other materials provided with the
+ # distribution.
+ # * Neither the name of Google Inc. nor the names of its
+ # contributors may be used to endorse or promote products derived from
+ # this software without specific prior written permission.
+ #
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ FROM debian:jessie
+
+ <%include file="../../java_deps.include"/>
+
+ # Trigger download of as many Gradle artifacts as possible.
+ RUN git clone --recursive --depth 1 https://github.com/grpc/grpc-java.git && ${'\\'}
+ cd grpc-java && ${'\\'}
+ ./gradlew :grpc-interop-testing:installDist -PskipCodegen=true && ${'\\'}
+ rm -r "$(pwd)"
+
+ # Define the default command.
+ CMD ["bash"]
+
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile.template
new file mode 100644
index 0000000000..89bb9acc1a
--- /dev/null
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile.template
@@ -0,0 +1,39 @@
+%YAML 1.2
+--- |
+ # Copyright 2015, Google Inc.
+ # All rights reserved.
+ #
+ # Redistribution and use in source and binary forms, with or without
+ # modification, are permitted provided that the following conditions are
+ # met:
+ #
+ # * Redistributions of source code must retain the above copyright
+ # notice, this list of conditions and the following disclaimer.
+ # * Redistributions in binary form must reproduce the above
+ # copyright notice, this list of conditions and the following disclaimer
+ # in the documentation and/or other materials provided with the
+ # distribution.
+ # * Neither the name of Google Inc. nor the names of its
+ # contributors may be used to endorse or promote products derived from
+ # this software without specific prior written permission.
+ #
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ FROM debian:jessie
+
+ <%include file="../../apt_get_basic.include"/>
+ <%include file="../../node_deps.include"/>
+ <%include file="../../run_tests_addons.include"/>
+ # Define the default command.
+ CMD ["bash"]
+
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_php/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_php/Dockerfile.template
new file mode 100644
index 0000000000..476f9d3d3e
--- /dev/null
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_php/Dockerfile.template
@@ -0,0 +1,64 @@
+%YAML 1.2
+--- |
+ # Copyright 2015, Google Inc.
+ # All rights reserved.
+ #
+ # Redistribution and use in source and binary forms, with or without
+ # modification, are permitted provided that the following conditions are
+ # met:
+ #
+ # * Redistributions of source code must retain the above copyright
+ # notice, this list of conditions and the following disclaimer.
+ # * Redistributions in binary form must reproduce the above
+ # copyright notice, this list of conditions and the following disclaimer
+ # in the documentation and/or other materials provided with the
+ # distribution.
+ # * Neither the name of Google Inc. nor the names of its
+ # contributors may be used to endorse or promote products derived from
+ # this software without specific prior written permission.
+ #
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ FROM debian:jessie
+
+ <%include file="../../apt_get_basic.include"/>
+ <%include file="../../ruby_deps.include"/>
+ <%include file="../../php_deps.include"/>
+ <%include file="../../run_tests_addons.include"/>
+ # ronn: a ruby tool used to convert markdown to man pages, used during the
+ # install of Protobuf extensions
+ #
+ # rake: a ruby version of make used to build the PHP Protobuf extension
+ RUN /bin/bash -l -c "rvm all do gem install ronn rake"
+
+ # Install composer
+ RUN curl -sS https://getcomposer.org/installer | php
+ RUN mv composer.phar /usr/local/bin/composer
+
+ # As an attempt to work around #4212, try to prefetch Protobuf-PHP dependency
+ # into composer cache to prevent "composer install" from cloning on each build.
+ RUN git clone --mirror https://github.com/stanley-cheung/Protobuf-PHP.git ${'\\'}
+ /root/.composer/cache/vcs/git-github.com-stanley-cheung-Protobuf-PHP.git/
+
+ # Download the patched PHP protobuf so that PHP gRPC clients can be generated
+ # from proto3 schemas.
+ RUN git clone https://github.com/stanley-cheung/Protobuf-PHP.git /var/local/git/protobuf-php
+
+ RUN /bin/bash -l -c "rvm use ruby-2.1 ${'\\'}
+ && cd /var/local/git/protobuf-php ${'\\'}
+ && rvm all do rake pear:package version=1.0 ${'\\'}
+ && pear install Protobuf-1.0.tgz"
+
+ # Define the default command.
+ CMD ["bash"]
+
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile.template
new file mode 100644
index 0000000000..4e816ce5b6
--- /dev/null
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile.template
@@ -0,0 +1,39 @@
+%YAML 1.2
+--- |
+ # Copyright 2015, Google Inc.
+ # All rights reserved.
+ #
+ # Redistribution and use in source and binary forms, with or without
+ # modification, are permitted provided that the following conditions are
+ # met:
+ #
+ # * Redistributions of source code must retain the above copyright
+ # notice, this list of conditions and the following disclaimer.
+ # * Redistributions in binary form must reproduce the above
+ # copyright notice, this list of conditions and the following disclaimer
+ # in the documentation and/or other materials provided with the
+ # distribution.
+ # * Neither the name of Google Inc. nor the names of its
+ # contributors may be used to endorse or promote products derived from
+ # this software without specific prior written permission.
+ #
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ FROM debian:jessie
+
+ <%include file="../../apt_get_basic.include"/>
+ <%include file="../../python_deps.include"/>
+ <%include file="../../run_tests_addons.include"/>
+ # Define the default command.
+ CMD ["bash"]
+
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile.template
new file mode 100644
index 0000000000..c3625b91fc
--- /dev/null
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile.template
@@ -0,0 +1,39 @@
+%YAML 1.2
+--- |
+ # Copyright 2015, Google Inc.
+ # All rights reserved.
+ #
+ # Redistribution and use in source and binary forms, with or without
+ # modification, are permitted provided that the following conditions are
+ # met:
+ #
+ # * Redistributions of source code must retain the above copyright
+ # notice, this list of conditions and the following disclaimer.
+ # * Redistributions in binary form must reproduce the above
+ # copyright notice, this list of conditions and the following disclaimer
+ # in the documentation and/or other materials provided with the
+ # distribution.
+ # * Neither the name of Google Inc. nor the names of its
+ # contributors may be used to endorse or promote products derived from
+ # this software without specific prior written permission.
+ #
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ FROM debian:jessie
+
+ <%include file="../../apt_get_basic.include"/>
+ <%include file="../../ruby_deps.include"/>
+ <%include file="../../run_tests_addons.include"/>
+ # Define the default command.
+ CMD ["bash"]
+
diff --git a/test/core/channel/channel_stack_test.c b/test/core/channel/channel_stack_test.c
index 81e3927a00..1a5594bde8 100644
--- a/test/core/channel/channel_stack_test.c
+++ b/test/core/channel/channel_stack_test.c
@@ -62,8 +62,8 @@ static void call_init_func(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
static void channel_destroy_func(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem) {}
-static void call_destroy_func(grpc_exec_ctx *exec_ctx,
- grpc_call_element *elem) {
+static void call_destroy_func(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+ void *ignored) {
++*(int *)(elem->channel_data);
}
@@ -87,7 +87,7 @@ static void free_channel(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
}
static void free_call(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
- grpc_call_stack_destroy(exec_ctx, arg);
+ grpc_call_stack_destroy(exec_ctx, arg, NULL);
gpr_free(arg);
}
diff --git a/test/core/end2end/tests/filter_causes_close.c b/test/core/end2end/tests/filter_causes_close.c
index 9f9ee85648..99049aa6bd 100644
--- a/test/core/end2end/tests/filter_causes_close.c
+++ b/test/core/end2end/tests/filter_causes_close.c
@@ -232,8 +232,8 @@ static void start_transport_stream_op(grpc_exec_ctx *exec_ctx,
static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
grpc_call_element_args *args) {}
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
- grpc_call_element *elem) {}
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+ void *and_free_memory) {}
static void init_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem,
diff --git a/test/cpp/interop/stress_interop_client.cc b/test/cpp/interop/stress_interop_client.cc
index 04671fb935..f287a5aa3b 100644
--- a/test/cpp/interop/stress_interop_client.cc
+++ b/test/cpp/interop/stress_interop_client.cc
@@ -84,49 +84,37 @@ StressTestInteropClient::StressTestInteropClient(
int test_id, const grpc::string& server_address,
std::shared_ptr<Channel> channel,
const WeightedRandomTestSelector& test_selector, long test_duration_secs,
- long sleep_duration_ms, long metrics_collection_interval_secs)
+ long sleep_duration_ms)
: test_id_(test_id),
server_address_(server_address),
channel_(channel),
interop_client_(new InteropClient(channel, false)),
test_selector_(test_selector),
test_duration_secs_(test_duration_secs),
- sleep_duration_ms_(sleep_duration_ms),
- metrics_collection_interval_secs_(metrics_collection_interval_secs) {}
+ sleep_duration_ms_(sleep_duration_ms) {}
-void StressTestInteropClient::MainLoop(std::shared_ptr<Gauge> qps_gauge) {
+void StressTestInteropClient::MainLoop(std::shared_ptr<QpsGauge> qps_gauge) {
gpr_log(GPR_INFO, "Running test %d. ServerAddr: %s", test_id_,
server_address_.c_str());
- gpr_timespec test_end_time =
- gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
- gpr_time_from_seconds(test_duration_secs_, GPR_TIMESPAN));
+ gpr_timespec test_end_time;
+ if (test_duration_secs_ < 0) {
+ test_end_time = gpr_inf_future(GPR_CLOCK_REALTIME);
+ } else {
+ test_end_time =
+ gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+ gpr_time_from_seconds(test_duration_secs_, GPR_TIMESPAN));
+ }
- gpr_timespec current_time = gpr_now(GPR_CLOCK_REALTIME);
- gpr_timespec next_stat_collection_time = current_time;
- gpr_timespec collection_interval =
- gpr_time_from_seconds(metrics_collection_interval_secs_, GPR_TIMESPAN);
- long num_calls_per_interval = 0;
+ qps_gauge->Reset();
- while (test_duration_secs_ < 0 ||
- gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), test_end_time) < 0) {
+ while (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), test_end_time) < 0) {
// Select the test case to execute based on the weights and execute it
TestCaseType test_case = test_selector_.GetNextTest();
gpr_log(GPR_DEBUG, "%d - Executing the test case %d", test_id_, test_case);
RunTest(test_case);
- num_calls_per_interval++;
-
- // See if its time to collect stats yet
- current_time = gpr_now(GPR_CLOCK_REALTIME);
- if (gpr_time_cmp(next_stat_collection_time, current_time) < 0) {
- qps_gauge->Set(num_calls_per_interval /
- metrics_collection_interval_secs_);
-
- num_calls_per_interval = 0;
- next_stat_collection_time =
- gpr_time_add(current_time, collection_interval);
- }
+ qps_gauge->Incr();
// Sleep between successive calls if needed
if (sleep_duration_ms_ > 0) {
diff --git a/test/cpp/interop/stress_interop_client.h b/test/cpp/interop/stress_interop_client.h
index 6fd303d6b7..cb0cd98821 100644
--- a/test/cpp/interop/stress_interop_client.h
+++ b/test/cpp/interop/stress_interop_client.h
@@ -87,12 +87,11 @@ class StressTestInteropClient {
StressTestInteropClient(int test_id, const grpc::string& server_address,
std::shared_ptr<Channel> channel,
const WeightedRandomTestSelector& test_selector,
- long test_duration_secs, long sleep_duration_ms,
- long metrics_collection_interval_secs);
+ long test_duration_secs, long sleep_duration_ms);
// The main function. Use this as the thread entry point.
- // qps_gauge is the Gauge to record the requests per second metric
- void MainLoop(std::shared_ptr<Gauge> qps_gauge);
+ // qps_gauge is the QpsGauge to record the requests per second metric
+ void MainLoop(std::shared_ptr<QpsGauge> qps_gauge);
private:
void RunTest(TestCaseType test_case);
@@ -104,7 +103,6 @@ class StressTestInteropClient {
const WeightedRandomTestSelector& test_selector_;
long test_duration_secs_;
long sleep_duration_ms_;
- long metrics_collection_interval_secs_;
};
} // namespace testing
diff --git a/test/cpp/interop/stress_test.cc b/test/cpp/interop/stress_test.cc
index 38caf31b76..d9e3fd25c5 100644
--- a/test/cpp/interop/stress_test.cc
+++ b/test/cpp/interop/stress_test.cc
@@ -56,9 +56,6 @@ extern void gpr_default_log(gpr_log_func_args* args);
DEFINE_int32(metrics_port, 8081, "The metrics server port.");
-DEFINE_int32(metrics_collection_interval_secs, 5,
- "How often (in seconds) should metrics be recorded.");
-
DEFINE_int32(sleep_duration_ms, 0,
"The duration (in millisec) between two"
" consecutive test calls (per server) issued by the server.");
@@ -275,19 +272,19 @@ int main(int argc, char** argv) {
stub_idx++) {
StressTestInteropClient* client = new StressTestInteropClient(
++thread_idx, *it, channel, test_selector, FLAGS_test_duration_secs,
- FLAGS_sleep_duration_ms, FLAGS_metrics_collection_interval_secs);
+ FLAGS_sleep_duration_ms);
- bool is_already_created;
- // Gauge name
+ bool is_already_created = false;
+ // QpsGauge name
std::snprintf(buffer, sizeof(buffer),
"/stress_test/server_%d/channel_%d/stub_%d/qps",
server_idx, channel_idx, stub_idx);
test_threads.emplace_back(grpc::thread(
&StressTestInteropClient::MainLoop, client,
- metrics_service.CreateGauge(buffer, &is_already_created)));
+ metrics_service.CreateQpsGauge(buffer, &is_already_created)));
- // The Gauge should not have been already created
+ // The QpsGauge should not have been already created
GPR_ASSERT(!is_already_created);
}
}
diff --git a/test/cpp/util/metrics_server.cc b/test/cpp/util/metrics_server.cc
index d9b44a6a92..cc6b39b753 100644
--- a/test/cpp/util/metrics_server.cc
+++ b/test/cpp/util/metrics_server.cc
@@ -42,16 +42,26 @@
namespace grpc {
namespace testing {
-Gauge::Gauge(long initial_val) : val_(initial_val) {}
+QpsGauge::QpsGauge()
+ : start_time_(gpr_now(GPR_CLOCK_REALTIME)), num_queries_(0) {}
-void Gauge::Set(long new_val) {
- std::lock_guard<std::mutex> lock(val_mu_);
- val_ = new_val;
+void QpsGauge::Reset() {
+ std::lock_guard<std::mutex> lock(num_queries_mu_);
+ num_queries_ = 0;
+ start_time_ = gpr_now(GPR_CLOCK_REALTIME);
}
-long Gauge::Get() {
- std::lock_guard<std::mutex> lock(val_mu_);
- return val_;
+void QpsGauge::Incr() {
+ std::lock_guard<std::mutex> lock(num_queries_mu_);
+ num_queries_++;
+}
+
+long QpsGauge::Get() {
+ std::lock_guard<std::mutex> lock(num_queries_mu_);
+ gpr_timespec time_diff =
+ gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), start_time_);
+ long duration_secs = time_diff.tv_sec > 0 ? time_diff.tv_sec : 1;
+ return num_queries_ / duration_secs;
}
grpc::Status MetricsServiceImpl::GetAllGauges(
@@ -60,7 +70,7 @@ grpc::Status MetricsServiceImpl::GetAllGauges(
gpr_log(GPR_DEBUG, "GetAllGauges called");
std::lock_guard<std::mutex> lock(mu_);
- for (auto it = gauges_.begin(); it != gauges_.end(); it++) {
+ for (auto it = qps_gauges_.begin(); it != qps_gauges_.end(); it++) {
GaugeResponse resp;
resp.set_name(it->first); // Gauge name
resp.set_long_value(it->second->Get()); // Gauge value
@@ -75,8 +85,8 @@ grpc::Status MetricsServiceImpl::GetGauge(ServerContext* context,
GaugeResponse* response) {
std::lock_guard<std::mutex> lock(mu_);
- const auto it = gauges_.find(request->name());
- if (it != gauges_.end()) {
+ const auto it = qps_gauges_.find(request->name());
+ if (it != qps_gauges_.end()) {
response->set_name(it->first);
response->set_long_value(it->second->Get());
}
@@ -84,16 +94,17 @@ grpc::Status MetricsServiceImpl::GetGauge(ServerContext* context,
return Status::OK;
}
-std::shared_ptr<Gauge> MetricsServiceImpl::CreateGauge(const grpc::string& name,
- bool* already_present) {
+std::shared_ptr<QpsGauge> MetricsServiceImpl::CreateQpsGauge(
+ const grpc::string& name, bool* already_present) {
std::lock_guard<std::mutex> lock(mu_);
- std::shared_ptr<Gauge> gauge(new Gauge(0));
- const auto p = gauges_.emplace(name, gauge);
+ std::shared_ptr<QpsGauge> qps_gauge(new QpsGauge());
+ const auto p = qps_gauges_.emplace(name, qps_gauge);
- // p.first is an iterator pointing to <name, shared_ptr<Gauge>> pair. p.second
- // is a boolean which is set to 'true' if the Gauge is inserted in the guages_
- // map and 'false' if it is already present in the map
+ // p.first is an iterator pointing to <name, shared_ptr<QpsGauge>> pair.
+ // p.second is a boolean which is set to 'true' if the QpsGauge is
+ // successfully inserted in the guages_ map and 'false' if it is already
+ // present in the map
*already_present = !p.second;
return p.first->second;
}
diff --git a/test/cpp/util/metrics_server.h b/test/cpp/util/metrics_server.h
index ce05e0be64..aa9bfed23d 100644
--- a/test/cpp/util/metrics_server.h
+++ b/test/cpp/util/metrics_server.h
@@ -48,10 +48,13 @@
* Example:
* MetricsServiceImpl metricsImpl;
* ..
- * // Create Gauge(s). Note: Gauges can be created even after calling
+ * // Create QpsGauge(s). Note: QpsGauges can be created even after calling
* // 'StartServer'.
- * Gauge gauge1 = metricsImpl.CreateGauge("foo",is_present);
- * // gauge1 can now be used anywhere in the program to set values.
+ * QpsGauge qps_gauge1 = metricsImpl.CreateQpsGauge("foo", is_present);
+ * // qps_gauge1 can now be used anywhere in the program by first making a
+ * // one-time call qps_gauge1.Reset() and then calling qps_gauge1.Incr()
+ * // every time to increment a query counter
+ *
* ...
* // Create the metrics server
* std::unique_ptr<grpc::Server> server = metricsImpl.StartServer(port);
@@ -60,17 +63,24 @@
namespace grpc {
namespace testing {
-// TODO(sreek): Add support for other types of Gauges like Double, String in
-// future
-class Gauge {
+class QpsGauge {
public:
- Gauge(long initial_val);
- void Set(long new_val);
+ QpsGauge();
+
+ // Initialize the internal timer and reset the query count to 0
+ void Reset();
+
+ // Increment the query count by 1
+ void Incr();
+
+ // Return the current qps (i.e query count divided by the time since this
+ // QpsGauge object created (or Reset() was called))
long Get();
private:
- long val_;
- std::mutex val_mu_;
+ gpr_timespec start_time_;
+ long num_queries_;
+ std::mutex num_queries_mu_;
};
class MetricsServiceImpl GRPC_FINAL : public MetricsService::Service {
@@ -81,17 +91,17 @@ class MetricsServiceImpl GRPC_FINAL : public MetricsService::Service {
grpc::Status GetGauge(ServerContext* context, const GaugeRequest* request,
GaugeResponse* response) GRPC_OVERRIDE;
- // Create a Gauge with name 'name'. is_present is set to true if the Gauge
+ // Create a QpsGauge with name 'name'. is_present is set to true if the Gauge
// is already present in the map.
- // NOTE: CreateGauge can be called anytime (i.e before or after calling
+ // NOTE: CreateQpsGauge can be called anytime (i.e before or after calling
// StartServer).
- std::shared_ptr<Gauge> CreateGauge(const grpc::string& name,
- bool* already_present);
+ std::shared_ptr<QpsGauge> CreateQpsGauge(const grpc::string& name,
+ bool* already_present);
std::unique_ptr<grpc::Server> StartServer(int port);
private:
- std::map<string, std::shared_ptr<Gauge>> gauges_;
+ std::map<string, std::shared_ptr<QpsGauge>> qps_gauges_;
std::mutex mu_;
};
diff --git a/tools/buildgen/plugins/expand_version.py b/tools/buildgen/plugins/expand_version.py
index dd77f7af12..c6cc5621c9 100755
--- a/tools/buildgen/plugins/expand_version.py
+++ b/tools/buildgen/plugins/expand_version.py
@@ -27,10 +27,10 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""Buildgen .proto files list plugin.
+"""Buildgen package version plugin
This parses the list of targets from the yaml build file, and creates
-a list called "protos" that contains all of the proto file names.
+a custom version string for each language's package.
"""
diff --git a/tools/dockerfile/grpc_base/README.md b/tools/dockerfile/grpc_base/README.md
deleted file mode 100644
index 5c81b02425..0000000000
--- a/tools/dockerfile/grpc_base/README.md
+++ /dev/null
@@ -1,11 +0,0 @@
-Base GRPC Dockerfile
-====================
-
-Dockerfile for creating the base gRPC development Docker instance.
-For now, this assumes that the development will be done on GCE instances,
-with source code on GitHub.
-
-As of 2015/02/02, it includes
-- git
-- some useful tools like curl, emacs, strace, telnet etc
-- a patched version of protoc, to allow protos with stream tags to work
diff --git a/tools/dockerfile/grpc_linuxbrew/Dockerfile b/tools/dockerfile/grpc_linuxbrew/Dockerfile
deleted file mode 100644
index 848489e091..0000000000
--- a/tools/dockerfile/grpc_linuxbrew/Dockerfile
+++ /dev/null
@@ -1,62 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-# A work-in-progress Dockerfile that allows running gRPC homebrew
-# installations inside docker containers
-FROM debian:jessie
-
-# Core dependencies
-RUN apt-get update && apt-get install -y \
- bzip2 curl git ruby wget
-
-# Install linuxbrew
-ENV PATH /home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:$PATH
-RUN git clone https://github.com/Homebrew/linuxbrew.git /home/linuxbrew/.linuxbrew
-RUN brew doctor || true
-
-# Python dependency
-RUN apt-get update && apt-get install -y python-dev
-RUN curl https://bootstrap.pypa.io/get-pip.py | python
-
-# NodeJS dependency
-RUN touch .profile
-RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
-RUN /bin/bash -l -c "nvm install 0.12"
-
-# Ruby dependency
-RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
-RUN /bin/bash -l -c "\curl -sSL https://get.rvm.io | bash -s stable"
-RUN /bin/bash -l -c "rvm install ruby-2.1"
-
-# PHP dependency
-RUN apt-get update && apt-get install -y php5 php5-dev php-pear phpunit unzip
-
-RUN /bin/bash -l -c "echo 'export PATH=/home/linuxbrew/.linuxbrew/bin:\$PATH' >> ~/.bashrc"
-
-CMD ["bash"]
diff --git a/tools/dockerfile/grpc_interop_csharp/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile
index 93cd25010e..baab2f5638 100644
--- a/tools/dockerfile/grpc_interop_csharp/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile
@@ -27,12 +27,9 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-# A work-in-progress Dockerfile that allows running gRPC test suites
-# inside a docker container.
-
FROM debian:jessie
-# Install Git.
+# Install Git and basic packages.
RUN apt-get update && apt-get install -y \
autoconf \
autotools-dev \
@@ -43,13 +40,16 @@ RUN apt-get update && apt-get install -y \
gcc \
gcc-multilib \
git \
+ golang \
gyp \
+ lcov \
libc6 \
libc6-dbg \
libc6-dev \
libgtest-dev \
libtool \
make \
+ perl \
strace \
python-dev \
python-setuptools \
@@ -59,15 +59,11 @@ RUN apt-get update && apt-get install -y \
wget \
zip && apt-get clean
-# Prepare ccache
-RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
-RUN ln -s /usr/bin/ccache /usr/local/bin/g++
-RUN ln -s /usr/bin/ccache /usr/local/bin/cc
-RUN ln -s /usr/bin/ccache /usr/local/bin/c++
-RUN ln -s /usr/bin/ccache /usr/local/bin/clang
-RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
-#################
+#================
# C# dependencies
# Update to a newer version of mono
@@ -84,5 +80,20 @@ RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y \
nuget \
&& apt-get clean
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
+
+RUN mkdir /var/local/jenkins
+
# Define the default command.
CMD ["bash"]
diff --git a/tools/dockerfile/grpc_interop_csharp/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_csharp/build_interop.sh
index fd5436c44f..fd5436c44f 100755
--- a/tools/dockerfile/grpc_interop_csharp/build_interop.sh
+++ b/tools/dockerfile/interoptest/grpc_interop_csharp/build_interop.sh
diff --git a/tools/dockerfile/grpc_interop_cxx/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile
index 1fa1907533..2bbccca9e5 100644
--- a/tools/dockerfile/grpc_interop_cxx/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile
@@ -27,12 +27,9 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-# A work-in-progress Dockerfile that allows running gRPC test suites
-# inside a docker container.
-
FROM debian:jessie
-# Install Git.
+# Install Git and basic packages.
RUN apt-get update && apt-get install -y \
autoconf \
autotools-dev \
@@ -43,13 +40,16 @@ RUN apt-get update && apt-get install -y \
gcc \
gcc-multilib \
git \
+ golang \
gyp \
+ lcov \
libc6 \
libc6-dbg \
libc6-dev \
libgtest-dev \
libtool \
make \
+ perl \
strace \
python-dev \
python-setuptools \
@@ -59,6 +59,14 @@ RUN apt-get update && apt-get install -y \
wget \
zip && apt-get clean
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+#=================
+# C++ dependencies
+RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang && apt-get clean
+
# Prepare ccache
RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
RUN ln -s /usr/bin/ccache /usr/local/bin/g++
@@ -67,9 +75,12 @@ RUN ln -s /usr/bin/ccache /usr/local/bin/c++
RUN ln -s /usr/bin/ccache /usr/local/bin/clang
RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
-##################
-# C++ dependencies
-RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
+
+RUN mkdir /var/local/jenkins
# Define the default command.
CMD ["bash"]
diff --git a/tools/dockerfile/grpc_interop_cxx/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_cxx/build_interop.sh
index 1c0828d23a..1c0828d23a 100755
--- a/tools/dockerfile/grpc_interop_cxx/build_interop.sh
+++ b/tools/dockerfile/interoptest/grpc_interop_cxx/build_interop.sh
diff --git a/tools/dockerfile/grpc_interop_go/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile
index ec71a53c2d..ec71a53c2d 100644
--- a/tools/dockerfile/grpc_interop_go/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile
diff --git a/tools/dockerfile/grpc_interop_go/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_go/build_interop.sh
index e891549342..e891549342 100755
--- a/tools/dockerfile/grpc_interop_go/build_interop.sh
+++ b/tools/dockerfile/interoptest/grpc_interop_go/build_interop.sh
diff --git a/tools/dockerfile/grpc_interop_http2/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile
index ec71a53c2d..ec71a53c2d 100644
--- a/tools/dockerfile/grpc_interop_http2/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile
diff --git a/tools/dockerfile/grpc_interop_http2/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_http2/build_interop.sh
index 46ddaf929a..46ddaf929a 100755
--- a/tools/dockerfile/grpc_interop_http2/build_interop.sh
+++ b/tools/dockerfile/interoptest/grpc_interop_http2/build_interop.sh
diff --git a/tools/dockerfile/grpc_interop_java/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile
index 370657b651..252c9bc928 100644
--- a/tools/dockerfile/grpc_interop_java/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile
@@ -31,23 +31,23 @@ FROM debian:jessie
# Install JDK 8 and Git
#
-# TODO(temiola): simplify this if/when a simpler process is available.
-#
RUN echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | /usr/bin/debconf-set-selections && \
echo "deb http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main" | tee /etc/apt/sources.list.d/webupd8team-java.list && \
echo "deb-src http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main" | tee -a /etc/apt/sources.list.d/webupd8team-java.list && \
- apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys EEA14886 && \
- apt-get update && \
- apt-get -y install \
+ apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys EEA14886
+
+RUN apt-get update && apt-get -y install \
git \
libapr1 \
oracle-java8-installer \
&& \
- apt-get clean && rm -r /var/cache/oracle-jdk8-installer/
+ apt-get clean && rm -r /var/cache/oracle-jdk8-installer/
ENV JAVA_HOME /usr/lib/jvm/java-8-oracle
ENV PATH $PATH:$JAVA_HOME/bin
+
+
# Trigger download of as many Gradle artifacts as possible.
RUN git clone --recursive --depth 1 https://github.com/grpc/grpc-java.git && \
cd grpc-java && \
diff --git a/tools/dockerfile/grpc_interop_java/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_java/build_interop.sh
index 9997c63308..9997c63308 100755
--- a/tools/dockerfile/grpc_interop_java/build_interop.sh
+++ b/tools/dockerfile/interoptest/grpc_interop_java/build_interop.sh
diff --git a/tools/dockerfile/grpc_interop_node/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile
index db5aff844d..64314f8864 100644
--- a/tools/dockerfile/grpc_interop_node/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile
@@ -27,12 +27,9 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-# A work-in-progress Dockerfile that allows running gRPC test suites
-# inside a docker container.
-
FROM debian:jessie
-# Install Git.
+# Install Git and basic packages.
RUN apt-get update && apt-get install -y \
autoconf \
autotools-dev \
@@ -43,14 +40,16 @@ RUN apt-get update && apt-get install -y \
gcc \
gcc-multilib \
git \
+ golang \
gyp \
+ lcov \
libc6 \
libc6-dbg \
libc6-dev \
libgtest-dev \
- libssl-dev \
libtool \
make \
+ perl \
strace \
python-dev \
python-setuptools \
@@ -60,6 +59,18 @@ RUN apt-get update && apt-get install -y \
wget \
zip && apt-get clean
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+#==================
+# Node dependencies
+
+# Install nvm
+RUN touch .profile
+RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
+RUN /bin/bash -l -c "nvm install 0.12 && npm config set cache /tmp/npm-cache"
+
# Prepare ccache
RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
RUN ln -s /usr/bin/ccache /usr/local/bin/g++
@@ -68,13 +79,12 @@ RUN ln -s /usr/bin/ccache /usr/local/bin/c++
RUN ln -s /usr/bin/ccache /usr/local/bin/clang
RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
-##################
-# Node dependencies
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
-# Install nvm
-RUN touch .profile
-RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
-RUN /bin/bash -l -c "nvm install 0.12"
+RUN mkdir /var/local/jenkins
# Define the default command.
CMD ["bash"]
diff --git a/tools/dockerfile/grpc_interop_node/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_node/build_interop.sh
index 4d4290d0b4..b99fd444ee 100755
--- a/tools/dockerfile/grpc_interop_node/build_interop.sh
+++ b/tools/dockerfile/interoptest/grpc_interop_node/build_interop.sh
@@ -41,8 +41,6 @@ cd /var/local/git/grpc
nvm use 0.12
nvm alias default 0.12 # prevent the need to run 'nvm use' in every shell
-make install-certs
-
# build Node interop client & server
npm install -g node-gyp
npm install --unsafe-perm --build-from-source
diff --git a/tools/dockerfile/grpc_interop_php/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_php/Dockerfile
index cf3e79176a..e27a6a2301 100644
--- a/tools/dockerfile/grpc_interop_php/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_php/Dockerfile
@@ -27,12 +27,9 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-# A work-in-progress Dockerfile that allows running gRPC test suites
-# inside a docker container.
-
FROM debian:jessie
-# Install Git.
+# Install Git and basic packages.
RUN apt-get update && apt-get install -y \
autoconf \
autotools-dev \
@@ -43,13 +40,16 @@ RUN apt-get update && apt-get install -y \
gcc \
gcc-multilib \
git \
+ golang \
gyp \
+ lcov \
libc6 \
libc6-dbg \
libc6-dev \
libgtest-dev \
libtool \
make \
+ perl \
strace \
python-dev \
python-setuptools \
@@ -59,15 +59,11 @@ RUN apt-get update && apt-get install -y \
wget \
zip && apt-get clean
-# Prepare ccache
-RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
-RUN ln -s /usr/bin/ccache /usr/local/bin/g++
-RUN ln -s /usr/bin/ccache /usr/local/bin/cc
-RUN ln -s /usr/bin/ccache /usr/local/bin/c++
-RUN ln -s /usr/bin/ccache /usr/local/bin/clang
-RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
-##################
+#==================
# Ruby dependencies
# Install rvm
@@ -82,14 +78,35 @@ RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc"
RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1' >> ~/.bashrc"
RUN /bin/bash -l -c "gem install bundler --no-ri --no-rdoc"
-##################
+#=================
# PHP dependencies
# Install dependencies
+RUN /bin/bash -l -c "echo 'deb http://packages.dotdeb.org wheezy-php55 all' \
+ >> /etc/apt/sources.list.d/dotdeb.list"
+RUN /bin/bash -l -c "echo 'deb-src http://packages.dotdeb.org wheezy-php55 all' \
+ >> /etc/apt/sources.list.d/dotdeb.list"
+RUN wget http://www.dotdeb.org/dotdeb.gpg -O- | apt-key add -
+
RUN apt-get update && apt-get install -y \
git php5 php5-dev phpunit unzip
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
+
+RUN mkdir /var/local/jenkins
+
# ronn: a ruby tool used to convert markdown to man pages, used during the
# install of Protobuf extensions
#
diff --git a/tools/dockerfile/grpc_interop_php/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_php/build_interop.sh
index 87262f1d62..87262f1d62 100755
--- a/tools/dockerfile/grpc_interop_php/build_interop.sh
+++ b/tools/dockerfile/interoptest/grpc_interop_php/build_interop.sh
diff --git a/tools/dockerfile/grpc_interop_python/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile
index 047604b1b7..071fb2c93b 100644
--- a/tools/dockerfile/grpc_interop_python/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile
@@ -27,12 +27,9 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-# A work-in-progress Dockerfile that allows running gRPC test suites
-# inside a docker container.
-
FROM debian:jessie
-# Install Git.
+# Install Git and basic packages.
RUN apt-get update && apt-get install -y \
autoconf \
autotools-dev \
@@ -43,17 +40,18 @@ RUN apt-get update && apt-get install -y \
gcc \
gcc-multilib \
git \
+ golang \
gyp \
+ lcov \
libc6 \
libc6-dbg \
libc6-dev \
libgtest-dev \
- libssl-dev \
libtool \
make \
+ perl \
strace \
python-dev \
- python-pip \
python-setuptools \
python-yaml \
telnet \
@@ -61,6 +59,25 @@ RUN apt-get update && apt-get install -y \
wget \
zip && apt-get clean
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+ python-all-dev \
+ python3-all-dev \
+ python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 tox
+
# Prepare ccache
RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
RUN ln -s /usr/bin/ccache /usr/local/bin/g++
@@ -69,14 +86,12 @@ RUN ln -s /usr/bin/ccache /usr/local/bin/c++
RUN ln -s /usr/bin/ccache /usr/local/bin/clang
RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
-#####################
-# Python dependencies
-
-# Install Python requisites
-RUN /bin/bash -l -c "pip install --upgrade pip"
-RUN /bin/bash -l -c "pip install virtualenv"
-RUN /bin/bash -l -c "pip install tox"
+RUN mkdir /var/local/jenkins
# Define the default command.
CMD ["bash"]
diff --git a/tools/dockerfile/grpc_interop_python/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_python/build_interop.sh
index f29c59da8e..f29c59da8e 100755
--- a/tools/dockerfile/grpc_interop_python/build_interop.sh
+++ b/tools/dockerfile/interoptest/grpc_interop_python/build_interop.sh
diff --git a/tools/dockerfile/grpc_interop_ruby/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile
index ff201fa291..df8eef5438 100644
--- a/tools/dockerfile/grpc_interop_ruby/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile
@@ -27,12 +27,9 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-# A work-in-progress Dockerfile that allows running gRPC test suites
-# inside a docker container.
-
FROM debian:jessie
-# Install Git.
+# Install Git and basic packages.
RUN apt-get update && apt-get install -y \
autoconf \
autotools-dev \
@@ -43,13 +40,16 @@ RUN apt-get update && apt-get install -y \
gcc \
gcc-multilib \
git \
+ golang \
gyp \
+ lcov \
libc6 \
libc6-dbg \
libc6-dev \
libgtest-dev \
libtool \
make \
+ perl \
strace \
python-dev \
python-setuptools \
@@ -59,16 +59,11 @@ RUN apt-get update && apt-get install -y \
wget \
zip && apt-get clean
-# Prepare ccache
-RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
-RUN ln -s /usr/bin/ccache /usr/local/bin/g++
-RUN ln -s /usr/bin/ccache /usr/local/bin/cc
-RUN ln -s /usr/bin/ccache /usr/local/bin/c++
-RUN ln -s /usr/bin/ccache /usr/local/bin/clang
-RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
-
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
-##################
+#==================
# Ruby dependencies
# Install rvm
@@ -83,5 +78,20 @@ RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc"
RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1' >> ~/.bashrc"
RUN /bin/bash -l -c "gem install bundler --no-ri --no-rdoc"
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
+
+RUN mkdir /var/local/jenkins
+
# Define the default command.
CMD ["bash"]
diff --git a/tools/dockerfile/grpc_interop_ruby/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_ruby/build_interop.sh
index 685397bac2..97b3860f98 100755
--- a/tools/dockerfile/grpc_interop_ruby/build_interop.sh
+++ b/tools/dockerfile/interoptest/grpc_interop_ruby/build_interop.sh
@@ -40,7 +40,5 @@ cp -r /var/local/jenkins/service_account $HOME || true
cd /var/local/git/grpc
rvm --default use ruby-2.1
-make install-certs
-
# build Ruby interop client and server
(cd src/ruby && gem update bundler && bundle && rake compile)
diff --git a/tools/gce/linux_performance_worker_init.sh b/tools/gce/linux_performance_worker_init.sh
index 478e04ef37..25ac3bcede 100755
--- a/tools/gce/linux_performance_worker_init.sh
+++ b/tools/gce/linux_performance_worker_init.sh
@@ -83,11 +83,13 @@ sudo apt-get install -y libgflags-dev libgtest-dev libc++-dev clang
# Python dependencies
sudo pip install tabulate
sudo pip install google-api-python-client
+sudo pip install tox
curl -O https://bootstrap.pypa.io/get-pip.py
sudo pypy get-pip.py
sudo pypy -m pip install tabulate
sudo pip install google-api-python-client
+sudo pip install tox
# Node dependencies (nvm has to be installed under user jenkins)
touch .profile
diff --git a/tools/jenkins/build_interop_image.sh b/tools/jenkins/build_interop_image.sh
index 26687a5a85..d2ba97c3de 100755
--- a/tools/jenkins/build_interop_image.sh
+++ b/tools/jenkins/build_interop_image.sh
@@ -71,10 +71,10 @@ then
fi
# Use image name based on Dockerfile checksum
-BASE_IMAGE=${BASE_NAME}_base:`sha1sum tools/dockerfile/$BASE_NAME/Dockerfile | cut -f1 -d\ `
+BASE_IMAGE=${BASE_NAME}_base:`sha1sum tools/dockerfile/interoptest/$BASE_NAME/Dockerfile | cut -f1 -d\ `
# Make sure base docker image has been built. Should be instantaneous if so.
-docker build -t $BASE_IMAGE --force-rm=true tools/dockerfile/$BASE_NAME || exit $?
+docker build -t $BASE_IMAGE --force-rm=true tools/dockerfile/interoptest/$BASE_NAME || exit $?
# Create a local branch so the child Docker script won't complain
git branch -f jenkins-docker
@@ -92,7 +92,7 @@ CONTAINER_NAME="build_${BASE_NAME}_$(uuidgen)"
-v /tmp/ccache:/tmp/ccache \
--name=$CONTAINER_NAME \
$BASE_IMAGE \
- bash -l /var/local/jenkins/grpc/tools/dockerfile/$BASE_NAME/build_interop.sh \
+ bash -l /var/local/jenkins/grpc/tools/dockerfile/interoptest/$BASE_NAME/build_interop.sh \
&& docker commit $CONTAINER_NAME $INTEROP_IMAGE \
&& echo "Successfully built image $INTEROP_IMAGE")
EXITCODE=$?
diff --git a/tools/jenkins/run_distribution.sh b/tools/jenkins/run_distribution.sh
deleted file mode 100755
index 306b85b045..0000000000
--- a/tools/jenkins/run_distribution.sh
+++ /dev/null
@@ -1,144 +0,0 @@
-#!/bin/bash
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# This script is invoked by Jenkins and triggers a test run of
-# linuxbrew installation of a selected language
-set -ex
-
-# Our homebrew installation script command, per language
-# Can be used in both linux and macos
-if [ "$language" == "core" ]; then
- command="curl -fsSL https://goo.gl/getgrpc | bash -"
-elif [[ "python nodejs ruby php" =~ "$language" ]]; then
- command="curl -fsSL https://goo.gl/getgrpc | bash -s $language"
-else
- echo "unsupported language $language"
- exit 1
-fi
-
-if [ "$platform" == "linux" ]; then
-
- if [ "$dist_channel" == "homebrew" ]; then
-
- sha1=$(sha1sum tools/dockerfile/grpc_linuxbrew/Dockerfile | cut -f1 -d\ )
- DOCKER_IMAGE_NAME=grpc_linuxbrew_$sha1
-
- # build docker image, contains all pre-requisites
- docker build -t $DOCKER_IMAGE_NAME tools/dockerfile/grpc_linuxbrew
-
- # run per-language homebrew installation script
- docker run --rm=true $DOCKER_IMAGE_NAME bash -l \
- -c "nvm use 0.12; \
- npm set unsafe-perm true; \
- rvm use ruby-2.1; \
- $command"
-
- else
- echo "Unsupported $platform dist_channel $dist_channel"
- exit 1
- fi
-
-elif [ "$platform" == "macos" ]; then
-
- if [ "$dist_channel" == "homebrew" ]; then
-
- echo "Formulas installed by system-wide homebrew (before)"
- brew list -l
-
- # Save the original PATH so that we can run the system `brew` command
- # again at the end of the script
- export ORIGINAL_PATH=$PATH
-
- # Set up temp directories for test installation of homebrew
- brew_root=/tmp/homebrew-test-$language
- rm -rf $brew_root
- mkdir -p $brew_root
- git clone https://github.com/Homebrew/homebrew.git $brew_root
-
- # Make sure we are operating at the right copy of temp homebrew
- # installation
- export PATH=$brew_root/bin:$PATH
-
- # Set up right environment for each language
- case $language in
- *python*)
- rm -rf jenkins_python_venv
- virtualenv jenkins_python_venv
- source jenkins_python_venv/bin/activate
- ;;
- *nodejs*)
- export PATH=$HOME/.nvm/versions/node/v0.12.7/bin:$PATH
- ;;
- *ruby*)
- export PATH=/usr/local/rvm/rubies/ruby-2.2.1/bin:$PATH
- ;;
- *php*)
- export CFLAGS="-Wno-parentheses-equality"
- ;;
- esac
-
- # Run our homebrew installation script
- bash -c "$command"
-
- # Uninstall / clean up per-language modules/extensions after the test
- case $language in
- *python*)
- deactivate
- rm -rf jenkins_python_venv
- ;;
- *nodejs*)
- npm list -g | grep grpc
- npm uninstall -g grpc
- ;;
- *ruby*)
- gem list | grep grpc
- gem uninstall grpc
- ;;
- *php*)
- rm grpc.so
- ;;
- esac
-
- # Clean up
- rm -rf $brew_root
-
- echo "Formulas installed by system-wide homebrew (after, should be unaffected)"
- export PATH=$ORIGINAL_PATH
- brew list -l
-
- else
- echo "Unsupported $platform dist_channel $dist_channel"
- exit 1
- fi
-
-else
- echo "unsupported platform $platform"
- exit 1
-fi
diff --git a/tools/jenkins/run_performance.sh b/tools/jenkins/run_performance.sh
index 903a144215..13a332751b 100755
--- a/tools/jenkins/run_performance.sh
+++ b/tools/jenkins/run_performance.sh
@@ -34,4 +34,4 @@ set -ex
# Enter the gRPC repo root
cd $(dirname $0)/../..
-tools/run_tests/run_performance_tests.py -l c++ node ruby csharp
+tools/run_tests/run_performance_tests.py -l c++ node ruby csharp python
diff --git a/tools/dockerfile/grpc_base/Dockerfile b/tools/run_tests/performance/kill_workers.sh
index 91862773d5..3eae8c31cb 100644..100755
--- a/tools/dockerfile/grpc_base/Dockerfile
+++ b/tools/run_tests/performance/kill_workers.sh
@@ -1,3 +1,4 @@
+#!/bin/bash
# Copyright 2015, Google Inc.
# All rights reserved.
#
@@ -27,42 +28,24 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-# Base Dockerfile for gRPC dev images
-FROM debian:latest
+set -ex
-# Install Git.
-RUN apt-get update && apt-get install -y \
- autoconf \
- autotools-dev \
- build-essential \
- bzip2 \
- curl \
- gcc \
- git \
- libc6 \
- libc6-dbg \
- libc6-dev \
- libgtest-dev \
- libtool \
- make \
- strace \
- python-dev \
- python-setuptools \
- telnet \
- unzip \
- wget \
- zip && apt-get clean
+cd $(dirname $0)/../../..
-# Install useful useful python modules
-RUN easy_install -U pip
-RUN pip install -U crcmod # makes downloads from cloud storage faster
+# Make sure there are no pre-existing QPS workers around before starting
+# the performance test suite
-# Install GCloud
-RUN wget https://dl.google.com/dl/cloudsdk/release/google-cloud-sdk.zip \
- && unzip google-cloud-sdk.zip && rm google-cloud-sdk.zip
-ENV CLOUD_SDK /google-cloud-sdk
-RUN $CLOUD_SDK/install.sh --usage-reporting=true --path-update=true --bash-completion=true --rc-path=/.bashrc --disable-installation-options
-ENV PATH $CLOUD_SDK/bin:$PATH
+# C++
+killall -9 qps_worker || true
-# Define the default command.
-CMD ["bash"]
+# C#
+ps -C mono -o pid=,cmd= | grep QpsWorker | awk '{print $1}' | xargs kill -9
+
+# Ruby
+ps -C ruby -o pid=,cmd= | grep 'qps/worker.rb' | awk '{print $1}' | xargs kill -9
+
+# Node
+ps -C node -o pid=,cmd= | grep 'performance/worker.js' | awk '{print $1}' | xargs kill -9
+
+# Java
+jps | grep LoadWorker | awk '{print $1}' | xargs kill -9
diff --git a/tools/run_tests/performance/remote_host_prepare.sh b/tools/run_tests/performance/remote_host_prepare.sh
index 17cfa1a599..d7f539a74e 100755
--- a/tools/run_tests/performance/remote_host_prepare.sh
+++ b/tools/run_tests/performance/remote_host_prepare.sh
@@ -41,10 +41,9 @@ ssh "${USER_AT_HOST}" "rm -rf ~/performance_workspace && mkdir -p ~/performance_
# could also kill jenkins.
ssh "${USER_AT_HOST}" "killall -9 qps_worker mono node ruby || true"
-# Kill all java LoadWorker processes. We can't just killall java
-# as one of the processes might be jenkins.
-ssh "${USER_AT_HOST}" 'kill -9 $(jps | grep LoadWorker | cut -f1 -d" ") || true'
-
# push the current sources to the slave and unpack it.
scp ../grpc.tar "${USER_AT_HOST}:~/performance_workspace"
ssh "${USER_AT_HOST}" "tar -xf ~/performance_workspace/grpc.tar -C ~/performance_workspace"
+
+# For consistency with local run, invoke the kill_workers script remotely.
+ssh "${USER_AT_HOST}" "~/performance_workspace/grpc/tools/run_tests/performance/kill_workers.sh"
diff --git a/tools/run_tests/performance/run_worker_python.sh b/tools/run_tests/performance/run_worker_python.sh
new file mode 100755
index 0000000000..0da8deda58
--- /dev/null
+++ b/tools/run_tests/performance/run_worker_python.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+set -ex
+
+cd $(dirname $0)/../../..
+
+PYTHONPATH=src/python/grpcio:src/python/gens .tox/py27/bin/python src/python/grpcio/tests/qps/qps_worker.py $@
diff --git a/tools/run_tests/performance/scenario_config.py b/tools/run_tests/performance/scenario_config.py
index 55657f8d8a..ddbe237569 100644
--- a/tools/run_tests/performance/scenario_config.py
+++ b/tools/run_tests/performance/scenario_config.py
@@ -456,6 +456,128 @@ class NodeLanguage:
def __str__(self):
return 'node'
+class PythonLanguage:
+
+ def __init__(self):
+ self.safename = 'python'
+
+ def worker_cmdline(self):
+ return ['tools/run_tests/performance/run_worker_python.sh']
+
+ def worker_port_offset(self):
+ return 500
+
+ def scenarios(self):
+ yield {
+ 'name': 'python_to_cpp_protobuf_streaming_ping_pong',
+ 'num_servers': 1,
+ 'num_clients': 1,
+ 'client_config': {
+ 'client_type': 'ASYNC_CLIENT',
+ 'security_params': SECURE_SECARGS,
+ 'outstanding_rpcs_per_channel': 1,
+ 'client_channels': 1,
+ 'async_client_threads': 1,
+ 'rpc_type': 'STREAMING',
+ 'load_params': {
+ 'closed_loop': {}
+ },
+ 'payload_config': EMPTY_PROTO_PAYLOAD,
+ 'histogram_params': HISTOGRAM_PARAMS,
+ },
+ 'server_config': {
+ 'server_type': 'SYNC_SERVER',
+ 'security_params': SECURE_SECARGS,
+ 'core_limit': 0,
+ 'async_server_threads': 1,
+ },
+ 'warmup_seconds': WARMUP_SECONDS,
+ 'benchmark_seconds': BENCHMARK_SECONDS,
+ 'SERVER_LANGUAGE': 'c++'
+ }
+ yield {
+ 'name': 'python_protobuf_sync_unary_ping_pong',
+ 'num_servers': 1,
+ 'num_clients': 1,
+ 'client_config': {
+ 'client_type': 'SYNC_CLIENT',
+ 'security_params': SECURE_SECARGS,
+ 'outstanding_rpcs_per_channel': 1,
+ 'client_channels': 1,
+ 'async_client_threads': 1,
+ 'rpc_type': 'UNARY',
+ 'load_params': {
+ 'closed_loop': {}
+ },
+ 'payload_config': EMPTY_PROTO_PAYLOAD,
+ 'histogram_params': HISTOGRAM_PARAMS,
+ },
+ 'server_config': {
+ 'server_type': 'SYNC_SERVER',
+ 'security_params': SECURE_SECARGS,
+ 'core_limit': 0,
+ 'async_server_threads': 1,
+ },
+ 'warmup_seconds': WARMUP_SECONDS,
+ 'benchmark_seconds': BENCHMARK_SECONDS,
+ }
+ yield {
+ 'name': 'python_protobuf_async_unary_ping_pong',
+ 'num_servers': 1,
+ 'num_clients': 1,
+ 'client_config': {
+ 'client_type': 'ASYNC_CLIENT',
+ 'security_params': SECURE_SECARGS,
+ 'outstanding_rpcs_per_channel': 1,
+ 'client_channels': 1,
+ 'async_client_threads': 1,
+ 'rpc_type': 'UNARY',
+ 'load_params': {
+ 'closed_loop': {}
+ },
+ 'payload_config': EMPTY_PROTO_PAYLOAD,
+ 'histogram_params': HISTOGRAM_PARAMS,
+ },
+ 'server_config': {
+ 'server_type': 'SYNC_SERVER',
+ 'security_params': SECURE_SECARGS,
+ 'core_limit': 0,
+ 'async_server_threads': 1,
+ },
+ 'warmup_seconds': WARMUP_SECONDS,
+ 'benchmark_seconds': BENCHMARK_SECONDS,
+ }
+ yield {
+ 'name': 'python_to_cpp_single_channel_throughput',
+ 'num_servers': 1,
+ 'num_clients': 1,
+ 'client_config': {
+ 'client_type': 'ASYNC_CLIENT',
+ 'security_params': SECURE_SECARGS,
+ 'outstanding_rpcs_per_channel': 1,
+ 'client_channels': 1,
+ 'async_client_threads': 1,
+ 'rpc_type': 'STREAMING',
+ 'load_params': {
+ 'closed_loop': {}
+ },
+ 'payload_config': BIG_GENERIC_PAYLOAD,
+ 'histogram_params': HISTOGRAM_PARAMS,
+ },
+ 'server_config': {
+ 'server_type': 'ASYNC_GENERIC_SERVER',
+ 'security_params': SECURE_SECARGS,
+ 'core_limit': SINGLE_MACHINE_CORES/2,
+ 'async_server_threads': 1,
+ 'payload_config': BIG_GENERIC_PAYLOAD,
+ },
+ 'warmup_seconds': WARMUP_SECONDS,
+ 'benchmark_seconds': BENCHMARK_SECONDS,
+ 'SERVER_LANGUAGE': 'c++'
+ }
+
+ def __str__(self):
+ return 'python'
class RubyLanguage:
@@ -562,4 +684,5 @@ LANGUAGES = {
'node' : NodeLanguage(),
'ruby' : RubyLanguage(),
'java' : JavaLanguage(),
+ 'python' : PythonLanguage(),
}
diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py
index 18d4c1072b..758be9304d 100755
--- a/tools/run_tests/run_interop_tests.py
+++ b/tools/run_tests/run_interop_tests.py
@@ -111,8 +111,7 @@ class CSharpLanguage:
return {}
def unimplemented_test_cases(self):
- # TODO: status_code_and_message doesn't work against node_server
- return _SKIP_COMPRESSION + ['status_code_and_message']
+ return _SKIP_COMPRESSION
def unimplemented_test_cases_server(self):
return _SKIP_COMPRESSION
diff --git a/tools/run_tests/run_performance_tests.py b/tools/run_tests/run_performance_tests.py
index ada341abf5..5519666e84 100755
--- a/tools/run_tests/run_performance_tests.py
+++ b/tools/run_tests/run_performance_tests.py
@@ -157,8 +157,9 @@ def archive_repo(languages):
sys.exit(1)
-def prepare_remote_hosts(hosts):
- """Prepares remote hosts."""
+def prepare_remote_hosts(hosts, prepare_local=False):
+ """Prepares remote hosts (and maybe prepare localhost as well)."""
+ prepare_timeout = 5*60
prepare_jobs = []
for host in hosts:
user_at_host = '%s@%s' % (_REMOTE_HOST_USERNAME, host)
@@ -167,13 +168,20 @@ def prepare_remote_hosts(hosts):
cmdline=['tools/run_tests/performance/remote_host_prepare.sh'],
shortname='remote_host_prepare.%s' % host,
environ = {'USER_AT_HOST': user_at_host},
- timeout_seconds=5*60))
- jobset.message('START', 'Preparing remote hosts.', do_newline=True)
+ timeout_seconds=prepare_timeout))
+ if prepare_local:
+ # Prepare localhost as well
+ prepare_jobs.append(
+ jobset.JobSpec(
+ cmdline=['tools/run_tests/performance/kill_workers.sh'],
+ shortname='local_prepare',
+ timeout_seconds=prepare_timeout))
+ jobset.message('START', 'Preparing hosts.', do_newline=True)
num_failures, _ = jobset.run(
prepare_jobs, newline_on_success=True, maxjobs=10)
if num_failures == 0:
jobset.message('SUCCESS',
- 'Remote hosts ready to start build.',
+ 'Prepare step completed successfully.',
do_newline=True)
else:
jobset.message('FAILED', 'Failed to prepare remote hosts.',
@@ -238,6 +246,9 @@ def start_qpsworkers(languages, worker_hosts):
def create_scenarios(languages, workers_by_lang, remote_host=None, regex='.*',
bq_result_table=None):
"""Create jobspecs for scenarios to run."""
+ all_workers = [worker
+ for workers in workers_by_lang.values()
+ for worker in workers]
scenarios = []
for language in languages:
for scenario_json in language.scenarios():
@@ -263,9 +274,6 @@ def create_scenarios(languages, workers_by_lang, remote_host=None, regex='.*',
scenarios.append(scenario)
# the very last scenario requests shutting down the workers.
- all_workers = [worker
- for workers in workers_by_lang.values()
- for worker in workers]
scenarios.append(create_quit_jobspec(all_workers, remote_host=remote_host))
return scenarios
@@ -322,7 +330,9 @@ if args.remote_driver_host:
if remote_hosts:
archive_repo(languages=[str(l) for l in languages])
- prepare_remote_hosts(remote_hosts)
+ prepare_remote_hosts(remote_hosts, prepare_local=True)
+else:
+ prepare_remote_hosts([], prepare_local=True)
build_local = False
if not args.remote_driver_host:
diff --git a/tools/run_tests/stress_test/STRESS_CLIENT_SPEC.md b/tools/run_tests/stress_test/STRESS_CLIENT_SPEC.md
index 62ca8aff2c..9f079beebc 100644
--- a/tools/run_tests/stress_test/STRESS_CLIENT_SPEC.md
+++ b/tools/run_tests/stress_test/STRESS_CLIENT_SPEC.md
@@ -6,8 +6,8 @@ This document specifies the features a stress test client should implement in or
--------------
**1.** A stress test client should be able to repeatedly execute one or more of the existing 'interop test cases'. It may just be a wrapper around the existing interop test client. The exact command line arguments the client should support are listed in _Table 1_ below.
-**2.** The stress test client must implement a metrics server defined by _[metrics.proto](https://github.com/grpc/grpc/blob/master/src/proto/grpc/testing/metrics.proto)_ and must expose _qps_ as a long-valued Gauge. The client can track the overall _qps_ in one Gauge or in multiple Gauges (for example: One per Channel or Stub).
- The framework periodically queries the _qps_ by calling the `GetAllGauges()` method (the framework assumes that all the returned Gauges are _qps_ Gauges) and uses this to determine if the stress test client is running or crashed or stalled.
+**2.** The stress test client must implement a metrics server defined by _[metrics.proto](https://github.com/grpc/grpc/blob/master/src/proto/grpc/testing/metrics.proto)_ and must expose _qps_ as a `Long`-valued Gauge. The client can track the overall _qps_ in one Gauge or in multiple Gauges (for example: One per Channel or Stub).
+ The framework periodically queries the _qps_ by calling the `GetAllGauges()` method (the framework assumes that all the returned Gauges are _qps_ Gauges and adds them up to determine the final qps) and uses this to determine if the stress test client is running or crashed or stalled.
> *Note:* In this context, the term _**qps**_ means _interop test cases per second_ (not _messages per second_ or _rpc calls per second_)
diff --git a/tools/run_tests/stress_test/configs/asan.json b/tools/run_tests/stress_test/configs/asan.json
index c558855314..cb9f55763b 100644
--- a/tools/run_tests/stress_test/configs/asan.json
+++ b/tools/run_tests/stress_test/configs/asan.json
@@ -16,8 +16,7 @@
"num_channels_per_server":5,
"num_stubs_per_channel":10,
"test_cases": "empty_unary:1,large_unary:1,client_streaming:1,server_streaming:1,empty_stream:1",
- "metrics_port": 8081,
- "metrics_collection_interval_secs":120
+ "metrics_port": 8081
},
"metricsPort": 8081,
"metricsArgs": {
diff --git a/tools/run_tests/stress_test/configs/opt-tsan-asan.json b/tools/run_tests/stress_test/configs/opt-tsan-asan.json
index 4f172ef30b..936d15169e 100644
--- a/tools/run_tests/stress_test/configs/opt-tsan-asan.json
+++ b/tools/run_tests/stress_test/configs/opt-tsan-asan.json
@@ -26,8 +26,7 @@
"num_channels_per_server":5,
"num_stubs_per_channel":10,
"test_cases": "empty_unary:1,large_unary:1,client_streaming:1,server_streaming:1,empty_stream:1",
- "metrics_port": 8081,
- "metrics_collection_interval_secs": 60
+ "metrics_port": 8081
},
"metricsPort": 8081,
"metricsArgs": {
diff --git a/tools/run_tests/stress_test/configs/opt.json b/tools/run_tests/stress_test/configs/opt.json
index 75505186f2..f45b824048 100644
--- a/tools/run_tests/stress_test/configs/opt.json
+++ b/tools/run_tests/stress_test/configs/opt.json
@@ -16,8 +16,7 @@
"num_channels_per_server":5,
"num_stubs_per_channel":10,
"test_cases": "empty_unary:1,large_unary:1,client_streaming:1,server_streaming:1,empty_stream:1",
- "metrics_port": 8081,
- "metrics_collection_interval_secs": 60
+ "metrics_port": 8081
},
"metricsPort": 8081,
"metricsArgs": {
diff --git a/tools/run_tests/stress_test/configs/tsan.json b/tools/run_tests/stress_test/configs/tsan.json
index a7ec08313d..6ef3bdf7ea 100644
--- a/tools/run_tests/stress_test/configs/tsan.json
+++ b/tools/run_tests/stress_test/configs/tsan.json
@@ -16,8 +16,7 @@
"num_channels_per_server":5,
"num_stubs_per_channel":10,
"test_cases": "empty_unary:1,large_unary:1,client_streaming:1,server_streaming:1,empty_stream:1",
- "metrics_port": 8081,
- "metrics_collection_interval_secs":120
+ "metrics_port": 8081
},
"metricsPort": 8081,
"metricsArgs": {