aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--BUILD61
-rw-r--r--CMakeLists.txt40
-rw-r--r--Makefile53
-rw-r--r--build.yaml58
-rw-r--r--config.m47
-rw-r--r--config.w327
-rw-r--r--gRPC-C++.podspec6
-rw-r--r--gRPC-Core.podspec18
-rw-r--r--grpc.gemspec12
-rw-r--r--grpc.gyp16
-rw-r--r--include/grpc/grpc.h5
-rw-r--r--include/grpcpp/impl/codegen/completion_queue.h1
-rw-r--r--package.xml12
-rw-r--r--src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.cc140
-rw-r--r--src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.h29
-rw-r--r--src/core/ext/filters/client_channel/lb_policy/xds/xds.cc33
-rw-r--r--src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc (renamed from src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.cc)2
-rw-r--r--src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h (renamed from src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.h)6
-rw-r--r--src/core/ext/transport/chttp2/transport/parsing.cc6
-rw-r--r--src/core/lib/iomgr/error.cc47
-rw-r--r--src/core/lib/iomgr/error.h33
-rw-r--r--src/core/lib/iomgr/error_internal.h2
-rw-r--r--src/core/lib/iomgr/socket_utils_common_posix.cc5
-rw-r--r--src/core/lib/surface/completion_queue.cc7
-rw-r--r--src/core/lib/transport/error_utils.cc6
-rw-r--r--src/core/plugin_registry/grpc_plugin_registry.cc4
-rw-r--r--src/core/plugin_registry/grpc_unsecure_plugin_registry.cc4
-rw-r--r--src/cpp/server/health/default_health_check_service.cc449
-rw-r--r--src/cpp/server/health/default_health_check_service.h234
-rw-r--r--src/cpp/server/health/health.pb.c1
-rw-r--r--src/cpp/server/health/health.pb.h7
-rw-r--r--src/cpp/server/server_cc.cc32
-rw-r--r--src/csharp/.editorconfig23
-rw-r--r--src/csharp/Grpc.Core.Tests/SanityTest.cs1
-rw-r--r--src/csharp/Grpc.Tools.Tests/CSharpGeneratorTest.cs85
-rw-r--r--src/csharp/Grpc.Tools.Tests/CppGeneratorTest.cs88
-rw-r--r--src/csharp/Grpc.Tools.Tests/DepFileUtilTest.cs146
-rw-r--r--src/csharp/Grpc.Tools.Tests/GeneratorTest.cs55
-rw-r--r--src/csharp/Grpc.Tools.Tests/Grpc.Tools.Tests.csproj78
-rw-r--r--src/csharp/Grpc.Tools.Tests/NUnitMain.cs33
-rw-r--r--src/csharp/Grpc.Tools.Tests/ProtoCompileBasicTest.cs76
-rw-r--r--src/csharp/Grpc.Tools.Tests/ProtoCompileCommandLineGeneratorTest.cs179
-rw-r--r--src/csharp/Grpc.Tools.Tests/ProtoCompileCommandLinePrinterTest.cs51
-rw-r--r--src/csharp/Grpc.Tools.Tests/ProtoToolsPlatformTaskTest.cs139
-rw-r--r--src/csharp/Grpc.Tools.Tests/Utils.cs46
-rw-r--r--src/csharp/Grpc.Tools.nuspec33
-rw-r--r--src/csharp/Grpc.Tools/Common.cs114
-rw-r--r--src/csharp/Grpc.Tools/DepFileUtil.cs273
-rw-r--r--src/csharp/Grpc.Tools/GeneratorServices.cs194
-rw-r--r--src/csharp/Grpc.Tools/Grpc.Tools.csproj101
-rw-r--r--src/csharp/Grpc.Tools/ProtoCompile.cs441
-rw-r--r--src/csharp/Grpc.Tools/ProtoCompilerOutputs.cs86
-rw-r--r--src/csharp/Grpc.Tools/ProtoReadDependencies.cs78
-rw-r--r--src/csharp/Grpc.Tools/ProtoToolsPlatform.cs63
-rw-r--r--src/csharp/Grpc.Tools/build/Grpc.Tools.props11
-rw-r--r--src/csharp/Grpc.Tools/build/Grpc.Tools.targets11
-rw-r--r--src/csharp/Grpc.Tools/build/_grpc/Grpc.CSharp.xml30
-rw-r--r--src/csharp/Grpc.Tools/build/_grpc/README3
-rw-r--r--src/csharp/Grpc.Tools/build/_grpc/_Grpc.Tools.props6
-rw-r--r--src/csharp/Grpc.Tools/build/_grpc/_Grpc.Tools.targets48
-rw-r--r--src/csharp/Grpc.Tools/build/_protobuf/Google.Protobuf.Tools.props24
-rw-r--r--src/csharp/Grpc.Tools/build/_protobuf/Google.Protobuf.Tools.targets384
-rw-r--r--src/csharp/Grpc.Tools/build/_protobuf/Protobuf.CSharp.xml99
-rw-r--r--src/csharp/Grpc.Tools/build/_protobuf/README1
-rw-r--r--src/csharp/Grpc.Tools/build/native/Grpc.Tools.props17
-rw-r--r--src/csharp/Grpc.sln12
-rwxr-xr-xsrc/csharp/build_packages_dotnetcli.bat2
-rw-r--r--src/csharp/tests.json10
-rw-r--r--src/objective-c/GRPCClient/private/GRPCHost.m5
-rw-r--r--src/proto/grpc/health/v1/health.proto20
-rw-r--r--src/python/grpcio/grpc_core_dependencies.py6
-rw-r--r--src/ruby/spec/pb/codegen/grpc/testing/package_options.proto (renamed from src/proto/grpc/testing/package_options.proto)0
-rw-r--r--src/ruby/spec/pb/codegen/package_option_spec.rb5
-rwxr-xr-xtemplates/src/csharp/build_packages_dotnetcli.bat.template2
-rw-r--r--templates/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile.template2
-rw-r--r--test/core/memory_usage/memory_usage_test.cc4
-rw-r--r--test/cpp/end2end/health_service_end2end_test.cc76
-rw-r--r--test/cpp/microbenchmarks/BUILD9
-rw-r--r--test/cpp/microbenchmarks/bm_call_create.cc1
-rwxr-xr-xtools/distrib/check_nanopb_output.sh18
-rw-r--r--tools/dockerfile/interoptest/grpc_interop_go/Dockerfile2
-rw-r--r--tools/doxygen/Doxyfile.core.internal8
-rwxr-xr-xtools/gce/create_linux_kokoro_performance_worker_from_image.sh38
-rwxr-xr-xtools/internal_ci/linux/grpc_e2e_performance_singlevm.sh1
-rwxr-xr-xtools/internal_ci/linux/grpc_performance_profile_daily.sh4
-rwxr-xr-xtools/internal_ci/linux/run_performance_profile_hourly.sh4
-rw-r--r--tools/run_tests/generated/sources_and_headers.json105
87 files changed, 4116 insertions, 578 deletions
diff --git a/BUILD b/BUILD
index 71d7b7d09e..4a6928ac4f 100644
--- a/BUILD
+++ b/BUILD
@@ -279,6 +279,7 @@ grpc_cc_library(
deps = [
"grpc_common",
"grpc_lb_policy_grpclb",
+ "grpc_lb_policy_xds",
],
)
@@ -294,6 +295,7 @@ grpc_cc_library(
deps = [
"grpc_common",
"grpc_lb_policy_grpclb_secure",
+ "grpc_lb_policy_xds_secure",
"grpc_secure",
"grpc_transport_chttp2_client_secure",
"grpc_transport_chttp2_server_secure",
@@ -1199,6 +1201,24 @@ grpc_cc_library(
)
grpc_cc_library(
+ name = "grpclb_proto",
+ srcs = [
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c",
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c",
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c",
+ ],
+ hdrs = [
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h",
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h",
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h",
+ ],
+ external_deps = [
+ "nanopb",
+ ],
+ language = "c++",
+)
+
+grpc_cc_library(
name = "grpc_lb_policy_grpclb",
srcs = [
"src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc",
@@ -1206,9 +1226,6 @@ grpc_cc_library(
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.cc",
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc",
"src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c",
],
hdrs = [
"src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h",
@@ -1216,9 +1233,6 @@ grpc_cc_library(
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h",
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h",
"src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h",
],
external_deps = [
"nanopb",
@@ -1228,6 +1242,7 @@ grpc_cc_library(
"grpc_base",
"grpc_client_channel",
"grpc_resolver_fake",
+ "grpclb_proto",
],
)
@@ -1239,9 +1254,6 @@ grpc_cc_library(
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc",
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc",
"src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c",
],
hdrs = [
"src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h",
@@ -1249,9 +1261,6 @@ grpc_cc_library(
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h",
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h",
"src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h",
],
external_deps = [
"nanopb",
@@ -1262,30 +1271,23 @@ grpc_cc_library(
"grpc_client_channel",
"grpc_resolver_fake",
"grpc_secure",
+ "grpclb_proto",
],
)
grpc_cc_library(
name = "grpc_lb_policy_xds",
srcs = [
- "src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.cc",
"src/core/ext/filters/client_channel/lb_policy/xds/xds.cc",
"src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.cc",
"src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc",
- "src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.cc",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc",
],
hdrs = [
- "src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.h",
"src/core/ext/filters/client_channel/lb_policy/xds/xds.h",
"src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h",
"src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h",
- "src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h",
],
external_deps = [
"nanopb",
@@ -1295,30 +1297,23 @@ grpc_cc_library(
"grpc_base",
"grpc_client_channel",
"grpc_resolver_fake",
+ "grpclb_proto",
],
)
grpc_cc_library(
name = "grpc_lb_policy_xds_secure",
srcs = [
- "src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.cc",
"src/core/ext/filters/client_channel/lb_policy/xds/xds.cc",
"src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc",
"src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc",
- "src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.cc",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc",
],
hdrs = [
- "src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.h",
"src/core/ext/filters/client_channel/lb_policy/xds/xds.h",
"src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h",
"src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h",
- "src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h",
],
external_deps = [
"nanopb",
@@ -1329,6 +1324,7 @@ grpc_cc_library(
"grpc_client_channel",
"grpc_resolver_fake",
"grpc_secure",
+ "grpclb_proto",
],
)
@@ -1586,6 +1582,7 @@ grpc_cc_library(
],
hdrs = [
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds.h",
"src/core/lib/security/context/security_context.h",
"src/core/lib/security/credentials/alts/alts_credentials.h",
"src/core/lib/security/credentials/composite/composite_credentials.h",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1732773244..e56c64abde 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -359,8 +359,8 @@ add_dependencies(buildtests_c json_stream_error_test)
add_dependencies(buildtests_c json_test)
add_dependencies(buildtests_c lame_client_test)
add_dependencies(buildtests_c load_file_test)
-add_dependencies(buildtests_c memory_profile_client)
-add_dependencies(buildtests_c memory_profile_server)
+add_dependencies(buildtests_c memory_usage_client)
+add_dependencies(buildtests_c memory_usage_server)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_c memory_usage_test)
endif()
@@ -1264,10 +1264,14 @@ add_library(grpc
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc
src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc
+ src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c
src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c
src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
- src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
+ src/core/ext/filters/client_channel/lb_policy/xds/xds.cc
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc
src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
@@ -2617,12 +2621,16 @@ add_library(grpc_unsecure
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.cc
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc
src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc
- src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c
- src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c
- src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
third_party/nanopb/pb_common.c
third_party/nanopb/pb_decode.c
third_party/nanopb/pb_encode.c
+ src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c
+ src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c
+ src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
+ src/core/ext/filters/client_channel/lb_policy/xds/xds.cc
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.cc
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc
src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
src/core/ext/filters/census/grpc_context.cc
@@ -8756,12 +8764,12 @@ target_link_libraries(load_file_test
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
-add_executable(memory_profile_client
+add_executable(memory_usage_client
test/core/memory_usage/client.cc
)
-target_include_directories(memory_profile_client
+target_include_directories(memory_usage_client
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
@@ -8774,7 +8782,7 @@ target_include_directories(memory_profile_client
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
-target_link_libraries(memory_profile_client
+target_link_libraries(memory_usage_client
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc
@@ -8784,19 +8792,19 @@ target_link_libraries(memory_profile_client
# avoid dependency on libstdc++
if (_gRPC_CORE_NOSTDCXX_FLAGS)
- set_target_properties(memory_profile_client PROPERTIES LINKER_LANGUAGE C)
- target_compile_options(memory_profile_client PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ set_target_properties(memory_usage_client PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(memory_usage_client PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
-add_executable(memory_profile_server
+add_executable(memory_usage_server
test/core/memory_usage/server.cc
)
-target_include_directories(memory_profile_server
+target_include_directories(memory_usage_server
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
@@ -8809,7 +8817,7 @@ target_include_directories(memory_profile_server
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
-target_link_libraries(memory_profile_server
+target_link_libraries(memory_usage_server
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc
@@ -8819,8 +8827,8 @@ target_link_libraries(memory_profile_server
# avoid dependency on libstdc++
if (_gRPC_CORE_NOSTDCXX_FLAGS)
- set_target_properties(memory_profile_server PROPERTIES LINKER_LANGUAGE C)
- target_compile_options(memory_profile_server PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
+ set_target_properties(memory_usage_server PROPERTIES LINKER_LANGUAGE C)
+ target_compile_options(memory_usage_server PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
endif()
endif (gRPC_BUILD_TESTS)
diff --git a/Makefile b/Makefile
index 824b5217da..fe320fa9dc 100644
--- a/Makefile
+++ b/Makefile
@@ -1064,8 +1064,8 @@ json_test: $(BINDIR)/$(CONFIG)/json_test
lame_client_test: $(BINDIR)/$(CONFIG)/lame_client_test
load_file_test: $(BINDIR)/$(CONFIG)/load_file_test
low_level_ping_pong_benchmark: $(BINDIR)/$(CONFIG)/low_level_ping_pong_benchmark
-memory_profile_client: $(BINDIR)/$(CONFIG)/memory_profile_client
-memory_profile_server: $(BINDIR)/$(CONFIG)/memory_profile_server
+memory_usage_client: $(BINDIR)/$(CONFIG)/memory_usage_client
+memory_usage_server: $(BINDIR)/$(CONFIG)/memory_usage_server
memory_usage_test: $(BINDIR)/$(CONFIG)/memory_usage_test
message_compress_test: $(BINDIR)/$(CONFIG)/message_compress_test
minimal_stack_is_minimal_test: $(BINDIR)/$(CONFIG)/minimal_stack_is_minimal_test
@@ -1511,8 +1511,8 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/json_test \
$(BINDIR)/$(CONFIG)/lame_client_test \
$(BINDIR)/$(CONFIG)/load_file_test \
- $(BINDIR)/$(CONFIG)/memory_profile_client \
- $(BINDIR)/$(CONFIG)/memory_profile_server \
+ $(BINDIR)/$(CONFIG)/memory_usage_client \
+ $(BINDIR)/$(CONFIG)/memory_usage_server \
$(BINDIR)/$(CONFIG)/memory_usage_test \
$(BINDIR)/$(CONFIG)/message_compress_test \
$(BINDIR)/$(CONFIG)/minimal_stack_is_minimal_test \
@@ -3732,10 +3732,14 @@ LIBGRPC_SRC = \
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc \
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc \
src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc \
+ src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc \
src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c \
src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c \
src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c \
- src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc \
+ src/core/ext/filters/client_channel/lb_policy/xds/xds.cc \
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc \
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc \
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc \
src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc \
src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc \
@@ -5031,12 +5035,16 @@ LIBGRPC_UNSECURE_SRC = \
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.cc \
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc \
src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc \
- src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c \
- src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c \
- src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c \
third_party/nanopb/pb_common.c \
third_party/nanopb/pb_decode.c \
third_party/nanopb/pb_encode.c \
+ src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c \
+ src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c \
+ src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c \
+ src/core/ext/filters/client_channel/lb_policy/xds/xds.cc \
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.cc \
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc \
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc \
src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc \
src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc \
src/core/ext/filters/census/grpc_context.cc \
@@ -13476,66 +13484,66 @@ endif
endif
-MEMORY_PROFILE_CLIENT_SRC = \
+MEMORY_USAGE_CLIENT_SRC = \
test/core/memory_usage/client.cc \
-MEMORY_PROFILE_CLIENT_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(MEMORY_PROFILE_CLIENT_SRC))))
+MEMORY_USAGE_CLIENT_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(MEMORY_USAGE_CLIENT_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
-$(BINDIR)/$(CONFIG)/memory_profile_client: openssl_dep_error
+$(BINDIR)/$(CONFIG)/memory_usage_client: openssl_dep_error
else
-$(BINDIR)/$(CONFIG)/memory_profile_client: $(MEMORY_PROFILE_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(BINDIR)/$(CONFIG)/memory_usage_client: $(MEMORY_USAGE_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
- $(Q) $(LD) $(LDFLAGS) $(MEMORY_PROFILE_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/memory_profile_client
+ $(Q) $(LD) $(LDFLAGS) $(MEMORY_USAGE_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/memory_usage_client
endif
$(OBJDIR)/$(CONFIG)/test/core/memory_usage/client.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-deps_memory_profile_client: $(MEMORY_PROFILE_CLIENT_OBJS:.o=.dep)
+deps_memory_usage_client: $(MEMORY_USAGE_CLIENT_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
--include $(MEMORY_PROFILE_CLIENT_OBJS:.o=.dep)
+-include $(MEMORY_USAGE_CLIENT_OBJS:.o=.dep)
endif
endif
-MEMORY_PROFILE_SERVER_SRC = \
+MEMORY_USAGE_SERVER_SRC = \
test/core/memory_usage/server.cc \
-MEMORY_PROFILE_SERVER_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(MEMORY_PROFILE_SERVER_SRC))))
+MEMORY_USAGE_SERVER_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(MEMORY_USAGE_SERVER_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
-$(BINDIR)/$(CONFIG)/memory_profile_server: openssl_dep_error
+$(BINDIR)/$(CONFIG)/memory_usage_server: openssl_dep_error
else
-$(BINDIR)/$(CONFIG)/memory_profile_server: $(MEMORY_PROFILE_SERVER_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(BINDIR)/$(CONFIG)/memory_usage_server: $(MEMORY_USAGE_SERVER_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
- $(Q) $(LD) $(LDFLAGS) $(MEMORY_PROFILE_SERVER_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/memory_profile_server
+ $(Q) $(LD) $(LDFLAGS) $(MEMORY_USAGE_SERVER_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/memory_usage_server
endif
$(OBJDIR)/$(CONFIG)/test/core/memory_usage/server.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-deps_memory_profile_server: $(MEMORY_PROFILE_SERVER_OBJS:.o=.dep)
+deps_memory_usage_server: $(MEMORY_USAGE_SERVER_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
--include $(MEMORY_PROFILE_SERVER_OBJS:.o=.dep)
+-include $(MEMORY_USAGE_SERVER_OBJS:.o=.dep)
endif
endif
@@ -24804,6 +24812,7 @@ ifneq ($(OPENSSL_DEP),)
# installing headers to their final destination on the drive. We need this
# otherwise parallel compilation will fail if a source is compiled first.
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc: $(OPENSSL_DEP)
+src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc: $(OPENSSL_DEP)
src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc: $(OPENSSL_DEP)
src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc: $(OPENSSL_DEP)
src/core/ext/transport/cronet/client/secure/cronet_channel_create.cc: $(OPENSSL_DEP)
diff --git a/build.yaml b/build.yaml
index 31474ac90b..9386048e21 100644
--- a/build.yaml
+++ b/build.yaml
@@ -655,24 +655,19 @@ filegroups:
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h
- src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h
src:
- src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.cc
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc
- src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
plugin: grpc_lb_policy_grpclb
uses:
- grpc_base
- grpc_client_channel
- nanopb
- grpc_resolver_fake
+ - grpclb_proto
- name: grpc_lb_policy_grpclb_secure
headers:
- src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h
@@ -680,18 +675,12 @@ filegroups:
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h
- src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h
src:
- src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc
- src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
plugin: grpc_lb_policy_grpclb
uses:
- grpc_base
@@ -699,6 +688,7 @@ filegroups:
- grpc_client_channel
- nanopb
- grpc_resolver_fake
+ - grpclb_proto
- name: grpc_lb_policy_pick_first
src:
- src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
@@ -717,48 +707,33 @@ filegroups:
- grpc_lb_subchannel_list
- name: grpc_lb_policy_xds
headers:
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h
- - src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.h
- - src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.h
- src/core/ext/filters/client_channel/lb_policy/xds/xds.h
- src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h
- src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h
+ - src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h
src:
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
- - src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.cc
- - src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.cc
- src/core/ext/filters/client_channel/lb_policy/xds/xds.cc
- src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.cc
- src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc
+ - src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc
plugin: grpc_lb_policy_xds
uses:
- grpc_base
- grpc_client_channel
- nanopb
- grpc_resolver_fake
+ - grpclb_proto
- name: grpc_lb_policy_xds_secure
headers:
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h
- - src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.h
- - src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.h
- src/core/ext/filters/client_channel/lb_policy/xds/xds.h
- src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h
- src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h
+ - src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h
src:
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c
- - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
- - src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.cc
- - src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.cc
- src/core/ext/filters/client_channel/lb_policy/xds/xds.cc
- src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc
- src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc
+ - src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc
plugin: grpc_lb_policy_xds
uses:
- grpc_base
@@ -766,6 +741,7 @@ filegroups:
- grpc_client_channel
- nanopb
- grpc_resolver_fake
+ - grpclb_proto
- name: grpc_lb_subchannel_list
headers:
- src/core/ext/filters/client_channel/lb_policy/subchannel_list.h
@@ -833,6 +809,7 @@ filegroups:
- include/grpc/grpc_security.h
headers:
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h
+ - src/core/ext/filters/client_channel/lb_policy/xds/xds.h
- src/core/lib/security/context/security_context.h
- src/core/lib/security/credentials/alts/alts_credentials.h
- src/core/lib/security/credentials/composite/composite_credentials.h
@@ -1119,6 +1096,17 @@ filegroups:
uses:
- grpc_base
- grpc_server_backward_compatibility
+- name: grpclb_proto
+ headers:
+ - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h
+ - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h
+ - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h
+ src:
+ - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c
+ - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c
+ - src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
+ uses:
+ - nanopb
- name: nanopb
src:
- third_party/nanopb/pb_common.c
@@ -1514,6 +1502,7 @@ libs:
- grpc_transport_chttp2_client_insecure
- grpc_transport_inproc
- grpc_lb_policy_grpclb_secure
+ - grpc_lb_policy_xds_secure
- grpc_lb_policy_pick_first
- grpc_lb_policy_round_robin
- grpc_resolver_dns_ares
@@ -1593,6 +1582,7 @@ libs:
- grpc_resolver_sockaddr
- grpc_resolver_fake
- grpc_lb_policy_grpclb
+ - grpc_lb_policy_xds
- grpc_lb_policy_pick_first
- grpc_lb_policy_round_robin
- census
@@ -3151,7 +3141,7 @@ targets:
- mac
- linux
- posix
-- name: memory_profile_client
+- name: memory_usage_client
build: test
run: false
language: c
@@ -3163,7 +3153,7 @@ targets:
- gpr_test_util
- gpr
uses_polling: false
-- name: memory_profile_server
+- name: memory_usage_server
build: test
run: false
language: c
diff --git a/config.m4 b/config.m4
index b9862f34ab..9b758b3f14 100644
--- a/config.m4
+++ b/config.m4
@@ -374,10 +374,14 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc \
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc \
src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc \
+ src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc \
src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c \
src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c \
src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c \
- src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc \
+ src/core/ext/filters/client_channel/lb_policy/xds/xds.cc \
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc \
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc \
+ src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc \
src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc \
src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc \
@@ -668,6 +672,7 @@ if test "$PHP_GRPC" != "no"; then
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/pick_first)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/round_robin)
+ PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/xds)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/dns/c_ares)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/dns/native)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/fake)
diff --git a/config.w32 b/config.w32
index 90a51057c4..a1bada1c61 100644
--- a/config.w32
+++ b/config.w32
@@ -349,10 +349,14 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\filters\\client_channel\\lb_policy\\grpclb\\grpclb_channel_secure.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\grpclb\\grpclb_client_stats.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\grpclb\\load_balancer_api.cc " +
+ "src\\core\\ext\\filters\\client_channel\\resolver\\fake\\fake_resolver.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\grpclb\\proto\\grpc\\lb\\v1\\google\\protobuf\\duration.pb.c " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\grpclb\\proto\\grpc\\lb\\v1\\google\\protobuf\\timestamp.pb.c " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\grpclb\\proto\\grpc\\lb\\v1\\load_balancer.pb.c " +
- "src\\core\\ext\\filters\\client_channel\\resolver\\fake\\fake_resolver.cc " +
+ "src\\core\\ext\\filters\\client_channel\\lb_policy\\xds\\xds.cc " +
+ "src\\core\\ext\\filters\\client_channel\\lb_policy\\xds\\xds_channel_secure.cc " +
+ "src\\core\\ext\\filters\\client_channel\\lb_policy\\xds\\xds_client_stats.cc " +
+ "src\\core\\ext\\filters\\client_channel\\lb_policy\\xds\\xds_load_balancer_api.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\pick_first\\pick_first.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\round_robin\\round_robin.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\dns_resolver_ares.cc " +
@@ -678,6 +682,7 @@ if (PHP_GRPC != "no") {
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\lb_policy\\grpclb\\proto\\grpc\\lb\\v1\\google\\protobuf");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\lb_policy\\pick_first");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\lb_policy\\round_robin");
+ FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\lb_policy\\xds");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\resolver");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\resolver\\dns");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares");
diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec
index 3cc19d5908..1ab17006e3 100644
--- a/gRPC-C++.podspec
+++ b/gRPC-C++.podspec
@@ -269,6 +269,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/http/message_compress/message_compress_filter.h',
'src/core/ext/filters/http/server/http_server_filter.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds.h',
'src/core/lib/security/context/security_context.h',
'src/core/lib/security/credentials/alts/alts_credentials.h',
'src/core/lib/security/credentials/composite/composite_credentials.h',
@@ -495,10 +496,13 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h',
+ 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h',
- 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h',
'src/core/ext/filters/client_channel/lb_policy/subchannel_list.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h',
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 8bb2311414..8d63f67c34 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -276,6 +276,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/http/message_compress/message_compress_filter.h',
'src/core/ext/filters/http/server/http_server_filter.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds.h',
'src/core/lib/security/context/security_context.h',
'src/core/lib/security/credentials/alts/alts_credentials.h',
'src/core/lib/security/credentials/composite/composite_credentials.h',
@@ -502,10 +503,13 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h',
+ 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h',
- 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h',
'src/core/ext/filters/client_channel/lb_policy/subchannel_list.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h',
@@ -802,10 +806,14 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc',
'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc',
+ 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c',
- 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc',
'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc',
'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc',
@@ -877,6 +885,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/http/message_compress/message_compress_filter.h',
'src/core/ext/filters/http/server/http_server_filter.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds.h',
'src/core/lib/security/context/security_context.h',
'src/core/lib/security/credentials/alts/alts_credentials.h',
'src/core/lib/security/credentials/composite/composite_credentials.h',
@@ -1103,10 +1112,13 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h',
+ 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h',
- 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h',
'src/core/ext/filters/client_channel/lb_policy/subchannel_list.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index 81f93f4419..533bb90b75 100644
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -208,6 +208,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/http/message_compress/message_compress_filter.h )
s.files += %w( src/core/ext/filters/http/server/http_server_filter.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h )
+ s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds.h )
s.files += %w( src/core/lib/security/context/security_context.h )
s.files += %w( src/core/lib/security/credentials/alts/alts_credentials.h )
s.files += %w( src/core/lib/security/credentials/composite/composite_credentials.h )
@@ -438,10 +439,13 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h )
+ s.files += %w( src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h )
- s.files += %w( src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h )
+ s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h )
+ s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h )
+ s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/subchannel_list.h )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h )
@@ -741,10 +745,14 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc )
+ s.files += %w( src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c )
- s.files += %w( src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc )
+ s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds.cc )
+ s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc )
+ s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc )
+ s.files += %w( src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc )
diff --git a/grpc.gyp b/grpc.gyp
index 8e14b49cc4..36a458b139 100644
--- a/grpc.gyp
+++ b/grpc.gyp
@@ -566,10 +566,14 @@
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc',
'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc',
+ 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c',
- 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc',
'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc',
'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc',
@@ -1299,12 +1303,16 @@
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.cc',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc',
'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc',
- 'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c',
- 'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c',
- 'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c',
'third_party/nanopb/pb_common.c',
'third_party/nanopb/pb_decode.c',
'third_party/nanopb/pb_encode.c',
+ 'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c',
+ 'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c',
+ 'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc',
'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc',
'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc',
'src/core/ext/filters/census/grpc_context.cc',
diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h
index 02ab6e8ba4..514d9ddc4b 100644
--- a/include/grpc/grpc.h
+++ b/include/grpc/grpc.h
@@ -248,10 +248,13 @@ GRPCAPI void* grpc_call_arena_alloc(grpc_call* call, size_t size);
appropriate to call grpc_completion_queue_next or
grpc_completion_queue_pluck consequent to the failed grpc_call_start_batch
call.
+ If a call to grpc_call_start_batch with an empty batch returns
+ GRPC_CALL_OK, the tag is put in the completion queue immediately.
THREAD SAFETY: access to grpc_call_start_batch in multi-threaded environment
needs to be synchronized. As an optimization, you may synchronize batches
containing just send operations independently from batches containing just
- receive operations. */
+ receive operations. Access to grpc_call_start_batch with an empty batch is
+ thread-compatible. */
GRPCAPI grpc_call_error grpc_call_start_batch(grpc_call* call,
const grpc_op* ops, size_t nops,
void* tag, void* reserved);
diff --git a/include/grpcpp/impl/codegen/completion_queue.h b/include/grpcpp/impl/codegen/completion_queue.h
index f52f9a53be..a62d48abe7 100644
--- a/include/grpcpp/impl/codegen/completion_queue.h
+++ b/include/grpcpp/impl/codegen/completion_queue.h
@@ -387,6 +387,7 @@ class ServerCompletionQueue : public CompletionQueue {
grpc_cq_polling_type polling_type_;
friend class ServerBuilder;
+ friend class Server;
};
} // namespace grpc
diff --git a/package.xml b/package.xml
index be3fd0d4c2..0d40707786 100644
--- a/package.xml
+++ b/package.xml
@@ -213,6 +213,7 @@
<file baseinstalldir="/" name="src/core/ext/filters/http/message_compress/message_compress_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/http/server/http_server_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/context/security_context.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/alts/alts_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/composite/composite_credentials.h" role="src" />
@@ -443,10 +444,13 @@
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h" role="src" />
- <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/subchannel_list.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" role="src" />
@@ -746,10 +750,14 @@
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c" role="src" />
- <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds.cc" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc" role="src" />
diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.cc b/src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.cc
deleted file mode 100644
index d79453d008..0000000000
--- a/src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.cc
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- *
- * Copyright 2018 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#include "src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.h"
-
-#include <grpc/support/atm.h>
-#include <grpc/support/log.h>
-
-#include "src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h"
-#include "src/core/lib/iomgr/error.h"
-#include "src/core/lib/profiling/timers.h"
-
-static grpc_error* init_channel_elem(grpc_channel_element* elem,
- grpc_channel_element_args* args) {
- return GRPC_ERROR_NONE;
-}
-
-static void destroy_channel_elem(grpc_channel_element* elem) {}
-
-namespace {
-
-struct call_data {
- // Stats object to update.
- grpc_core::RefCountedPtr<grpc_core::XdsLbClientStats> client_stats;
- // State for intercepting send_initial_metadata.
- grpc_closure on_complete_for_send;
- grpc_closure* original_on_complete_for_send;
- bool send_initial_metadata_succeeded;
- // State for intercepting recv_initial_metadata.
- grpc_closure recv_initial_metadata_ready;
- grpc_closure* original_recv_initial_metadata_ready;
- bool recv_initial_metadata_succeeded;
-};
-
-} // namespace
-
-static void on_complete_for_send(void* arg, grpc_error* error) {
- call_data* calld = static_cast<call_data*>(arg);
- if (error == GRPC_ERROR_NONE) {
- calld->send_initial_metadata_succeeded = true;
- }
- GRPC_CLOSURE_RUN(calld->original_on_complete_for_send, GRPC_ERROR_REF(error));
-}
-
-static void recv_initial_metadata_ready(void* arg, grpc_error* error) {
- call_data* calld = static_cast<call_data*>(arg);
- if (error == GRPC_ERROR_NONE) {
- calld->recv_initial_metadata_succeeded = true;
- }
- GRPC_CLOSURE_RUN(calld->original_recv_initial_metadata_ready,
- GRPC_ERROR_REF(error));
-}
-
-static grpc_error* init_call_elem(grpc_call_element* elem,
- const grpc_call_element_args* args) {
- call_data* calld = static_cast<call_data*>(elem->call_data);
- // Get stats object from context and take a ref.
- GPR_ASSERT(args->context != nullptr);
- if (args->context[GRPC_GRPCLB_CLIENT_STATS].value != nullptr) {
- calld->client_stats = static_cast<grpc_core::XdsLbClientStats*>(
- args->context[GRPC_GRPCLB_CLIENT_STATS].value)
- ->Ref();
- // Record call started.
- calld->client_stats->AddCallStarted();
- }
- return GRPC_ERROR_NONE;
-}
-
-static void destroy_call_elem(grpc_call_element* elem,
- const grpc_call_final_info* final_info,
- grpc_closure* ignored) {
- call_data* calld = static_cast<call_data*>(elem->call_data);
- if (calld->client_stats != nullptr) {
- // Record call finished, optionally setting client_failed_to_send and
- // received.
- calld->client_stats->AddCallFinished(
- !calld->send_initial_metadata_succeeded /* client_failed_to_send */,
- calld->recv_initial_metadata_succeeded /* known_received */);
- // All done, so unref the stats object.
- // TODO(roth): Eliminate this once filter stack is converted to C++.
- calld->client_stats.reset();
- }
-}
-
-static void start_transport_stream_op_batch(
- grpc_call_element* elem, grpc_transport_stream_op_batch* batch) {
- call_data* calld = static_cast<call_data*>(elem->call_data);
- GPR_TIMER_SCOPE("clr_start_transport_stream_op_batch", 0);
- if (calld->client_stats != nullptr) {
- // Intercept send_initial_metadata.
- if (batch->send_initial_metadata) {
- calld->original_on_complete_for_send = batch->on_complete;
- GRPC_CLOSURE_INIT(&calld->on_complete_for_send, on_complete_for_send,
- calld, grpc_schedule_on_exec_ctx);
- batch->on_complete = &calld->on_complete_for_send;
- }
- // Intercept recv_initial_metadata.
- if (batch->recv_initial_metadata) {
- calld->original_recv_initial_metadata_ready =
- batch->payload->recv_initial_metadata.recv_initial_metadata_ready;
- GRPC_CLOSURE_INIT(&calld->recv_initial_metadata_ready,
- recv_initial_metadata_ready, calld,
- grpc_schedule_on_exec_ctx);
- batch->payload->recv_initial_metadata.recv_initial_metadata_ready =
- &calld->recv_initial_metadata_ready;
- }
- }
- // Chain to next filter.
- grpc_call_next_op(elem, batch);
-}
-
-const grpc_channel_filter xds_client_load_reporting_filter = {
- start_transport_stream_op_batch,
- grpc_channel_next_op,
- sizeof(call_data),
- init_call_elem,
- grpc_call_stack_ignore_set_pollset_or_pollset_set,
- destroy_call_elem,
- 0, // sizeof(channel_data)
- init_channel_elem,
- destroy_channel_elem,
- grpc_channel_next_get_info,
- "client_load_reporting"};
diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.h b/src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.h
deleted file mode 100644
index 31a799154c..0000000000
--- a/src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- *
- * Copyright 2018 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_CLIENT_LOAD_REPORTING_FILTER_H
-#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_CLIENT_LOAD_REPORTING_FILTER_H
-
-#include <grpc/support/port_platform.h>
-
-#include "src/core/lib/channel/channel_stack.h"
-
-extern const grpc_channel_filter xds_client_load_reporting_filter;
-
-#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_CLIENT_LOAD_REPORTING_FILTER_H \
- */
diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc b/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc
index e6c94167f6..7fb4cbdcd2 100644
--- a/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc
@@ -75,11 +75,10 @@
#include "src/core/ext/filters/client_channel/client_channel.h"
#include "src/core/ext/filters/client_channel/client_channel_factory.h"
-#include "src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.h"
-#include "src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.h"
#include "src/core/ext/filters/client_channel/lb_policy/xds/xds.h"
#include "src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h"
#include "src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h"
+#include "src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h"
#include "src/core/ext/filters/client_channel/lb_policy_factory.h"
#include "src/core/ext/filters/client_channel/lb_policy_registry.h"
#include "src/core/ext/filters/client_channel/parse_address.h"
@@ -673,7 +672,7 @@ bool XdsLb::BalancerCallState::LoadReportCountersAreZero(
request->client_stats.num_calls_finished_with_client_failed_to_send ==
0 &&
request->client_stats.num_calls_finished_known_received == 0 &&
- (drop_entries == nullptr || drop_entries->size() == 0);
+ (drop_entries == nullptr || drop_entries->empty());
}
void XdsLb::BalancerCallState::SendClientLoadReportLocked() {
@@ -1275,9 +1274,9 @@ grpc_connectivity_state XdsLb::CheckConnectivityLocked(
}
void XdsLb::NotifyOnStateChangeLocked(grpc_connectivity_state* current,
- grpc_closure* notify) {
+ grpc_closure* closure) {
grpc_connectivity_state_notify_on_state_change(&state_tracker_, current,
- notify);
+ closure);
}
void XdsLb::ProcessChannelArgsLocked(const grpc_channel_args& args) {
@@ -1483,7 +1482,6 @@ void XdsLb::OnBalancerChannelConnectivityChangedLocked(void* arg,
xdslb_policy->lb_call_backoff_.Reset();
xdslb_policy->StartBalancerCallLocked();
}
- [[fallthrough]];
// Fall through.
case GRPC_CHANNEL_SHUTDOWN:
done:
@@ -1861,34 +1859,11 @@ class XdsFactory : public LoadBalancingPolicyFactory {
// Plugin registration
//
-namespace {
-
-// Only add client_load_reporting filter if the grpclb LB policy is used.
-bool maybe_add_client_load_reporting_filter(grpc_channel_stack_builder* builder,
- void* arg) {
- const grpc_channel_args* args =
- grpc_channel_stack_builder_get_channel_arguments(builder);
- const grpc_arg* channel_arg =
- grpc_channel_args_find(args, GRPC_ARG_LB_POLICY_NAME);
- if (channel_arg != nullptr && channel_arg->type == GRPC_ARG_STRING &&
- strcmp(channel_arg->value.string, "grpclb") == 0) {
- return grpc_channel_stack_builder_append_filter(
- builder, (const grpc_channel_filter*)arg, nullptr, nullptr);
- }
- return true;
-}
-
-} // namespace
-
void grpc_lb_policy_xds_init() {
grpc_core::LoadBalancingPolicyRegistry::Builder::
RegisterLoadBalancingPolicyFactory(
grpc_core::UniquePtr<grpc_core::LoadBalancingPolicyFactory>(
grpc_core::New<grpc_core::XdsFactory>()));
- grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL,
- GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
- maybe_add_client_load_reporting_filter,
- (void*)&xds_client_load_reporting_filter);
}
void grpc_lb_policy_xds_shutdown() {}
diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.cc b/src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc
index 3bd2653635..79b7bdbe33 100644
--- a/src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc
@@ -20,7 +20,7 @@
#include "pb_decode.h"
#include "pb_encode.h"
-#include "src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.h"
+#include "src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h"
#include <grpc/support/alloc.h>
diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.h b/src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h
index 3f096af6d6..9d08defa7e 100644
--- a/src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.h
+++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h
@@ -16,8 +16,8 @@
*
*/
-#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_LOAD_BALANCER_API_H
-#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_LOAD_BALANCER_API_H
+#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_XDS_LOAD_BALANCER_API_H
+#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_XDS_LOAD_BALANCER_API_H
#include <grpc/support/port_platform.h>
@@ -85,5 +85,5 @@ grpc_millis xds_grpclb_duration_to_millis(xds_grpclb_duration* duration_pb);
/** Destroy \a initial_response */
void xds_grpclb_initial_response_destroy(xds_grpclb_initial_response* response);
-#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_LOAD_BALANCER_API_H \
+#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_XDS_XDS_LOAD_BALANCER_API_H \
*/
diff --git a/src/core/ext/transport/chttp2/transport/parsing.cc b/src/core/ext/transport/chttp2/transport/parsing.cc
index f532b084c9..1ff96d3cd3 100644
--- a/src/core/ext/transport/chttp2/transport/parsing.cc
+++ b/src/core/ext/transport/chttp2/transport/parsing.cc
@@ -368,6 +368,7 @@ static grpc_error* init_data_frame_parser(grpc_chttp2_transport* t) {
&s->data_parser, t->incoming_frame_flags, s->id, s);
}
error_handler:
+ intptr_t unused;
if (err == GRPC_ERROR_NONE) {
t->incoming_stream = s;
/* t->parser = grpc_chttp2_data_parser_parse;*/
@@ -375,7 +376,7 @@ error_handler:
t->parser_data = &s->data_parser;
t->ping_state.last_ping_sent_time = GRPC_MILLIS_INF_PAST;
return GRPC_ERROR_NONE;
- } else if (grpc_error_get_int(err, GRPC_ERROR_INT_STREAM_ID, nullptr)) {
+ } else if (grpc_error_get_int(err, GRPC_ERROR_INT_STREAM_ID, &unused)) {
/* handle stream errors by closing the stream */
if (s != nullptr) {
grpc_chttp2_mark_stream_closed(t, s, true, false, err);
@@ -756,9 +757,10 @@ static grpc_error* parse_frame_slice(grpc_chttp2_transport* t, grpc_slice slice,
int is_last) {
grpc_chttp2_stream* s = t->incoming_stream;
grpc_error* err = t->parser(t->parser_data, t, s, slice, is_last);
+ intptr_t unused;
if (GPR_LIKELY(err == GRPC_ERROR_NONE)) {
return err;
- } else if (grpc_error_get_int(err, GRPC_ERROR_INT_STREAM_ID, nullptr)) {
+ } else if (grpc_error_get_int(err, GRPC_ERROR_INT_STREAM_ID, &unused)) {
if (grpc_http_trace.enabled()) {
const char* msg = grpc_error_string(err);
gpr_log(GPR_ERROR, "%s", msg);
diff --git a/src/core/lib/iomgr/error.cc b/src/core/lib/iomgr/error.cc
index 146a539027..6ae077fd54 100644
--- a/src/core/lib/iomgr/error.cc
+++ b/src/core/lib/iomgr/error.cc
@@ -121,14 +121,8 @@ static const char* error_time_name(grpc_error_times key) {
GPR_UNREACHABLE_CODE(return "unknown");
}
-bool grpc_error_is_special(grpc_error* err) {
- return err == GRPC_ERROR_NONE || err == GRPC_ERROR_OOM ||
- err == GRPC_ERROR_CANCELLED;
-}
-
#ifndef NDEBUG
-grpc_error* grpc_error_ref(grpc_error* err, const char* file, int line) {
- if (grpc_error_is_special(err)) return err;
+grpc_error* grpc_error_do_ref(grpc_error* err, const char* file, int line) {
if (grpc_trace_error_refcount.enabled()) {
gpr_log(GPR_DEBUG, "%p: %" PRIdPTR " -> %" PRIdPTR " [%s:%d]", err,
gpr_atm_no_barrier_load(&err->atomics.refs.count),
@@ -138,8 +132,7 @@ grpc_error* grpc_error_ref(grpc_error* err, const char* file, int line) {
return err;
}
#else
-grpc_error* grpc_error_ref(grpc_error* err) {
- if (grpc_error_is_special(err)) return err;
+grpc_error* grpc_error_do_ref(grpc_error* err) {
gpr_ref(&err->atomics.refs);
return err;
}
@@ -177,8 +170,7 @@ static void error_destroy(grpc_error* err) {
}
#ifndef NDEBUG
-void grpc_error_unref(grpc_error* err, const char* file, int line) {
- if (grpc_error_is_special(err)) return;
+void grpc_error_do_unref(grpc_error* err, const char* file, int line) {
if (grpc_trace_error_refcount.enabled()) {
gpr_log(GPR_DEBUG, "%p: %" PRIdPTR " -> %" PRIdPTR " [%s:%d]", err,
gpr_atm_no_barrier_load(&err->atomics.refs.count),
@@ -189,8 +181,7 @@ void grpc_error_unref(grpc_error* err, const char* file, int line) {
}
}
#else
-void grpc_error_unref(grpc_error* err) {
- if (grpc_error_is_special(err)) return;
+void grpc_error_do_unref(grpc_error* err) {
if (gpr_unref(&err->atomics.refs)) {
error_destroy(err);
}
@@ -450,26 +441,23 @@ grpc_error* grpc_error_set_int(grpc_error* src, grpc_error_ints which,
}
typedef struct {
- grpc_error* error;
grpc_status_code code;
const char* msg;
} special_error_status_map;
static const special_error_status_map error_status_map[] = {
- {GRPC_ERROR_NONE, GRPC_STATUS_OK, ""},
- {GRPC_ERROR_CANCELLED, GRPC_STATUS_CANCELLED, "Cancelled"},
- {GRPC_ERROR_OOM, GRPC_STATUS_RESOURCE_EXHAUSTED, "Out of memory"},
+ {GRPC_STATUS_OK, ""}, // GRPC_ERROR_NONE
+ {GRPC_STATUS_INVALID_ARGUMENT, ""}, // GRPC_ERROR_RESERVED_1
+ {GRPC_STATUS_RESOURCE_EXHAUSTED, "Out of memory"}, // GRPC_ERROR_OOM
+ {GRPC_STATUS_INVALID_ARGUMENT, ""}, // GRPC_ERROR_RESERVED_2
+ {GRPC_STATUS_CANCELLED, "Cancelled"}, // GRPC_ERROR_CANCELLED
};
bool grpc_error_get_int(grpc_error* err, grpc_error_ints which, intptr_t* p) {
GPR_TIMER_SCOPE("grpc_error_get_int", 0);
if (grpc_error_is_special(err)) {
- for (size_t i = 0; i < GPR_ARRAY_SIZE(error_status_map); i++) {
- if (error_status_map[i].error == err) {
- if (which != GRPC_ERROR_INT_GRPC_STATUS) return false;
- if (p != nullptr) *p = error_status_map[i].code;
- return true;
- }
- }
+ if (which != GRPC_ERROR_INT_GRPC_STATUS) return false;
+ *p = error_status_map[reinterpret_cast<size_t>(err)].code;
+ return true;
}
uint8_t slot = err->ints[which];
if (slot != UINT8_MAX) {
@@ -490,13 +478,10 @@ grpc_error* grpc_error_set_str(grpc_error* src, grpc_error_strs which,
bool grpc_error_get_str(grpc_error* err, grpc_error_strs which,
grpc_slice* str) {
if (grpc_error_is_special(err)) {
- for (size_t i = 0; i < GPR_ARRAY_SIZE(error_status_map); i++) {
- if (error_status_map[i].error == err) {
- if (which != GRPC_ERROR_STR_GRPC_MESSAGE) return false;
- *str = grpc_slice_from_static_string(error_status_map[i].msg);
- return true;
- }
- }
+ if (which != GRPC_ERROR_STR_GRPC_MESSAGE) return false;
+ *str = grpc_slice_from_static_string(
+ error_status_map[reinterpret_cast<size_t>(err)].msg);
+ return true;
}
uint8_t slot = err->strs[which];
if (slot != UINT8_MAX) {
diff --git a/src/core/lib/iomgr/error.h b/src/core/lib/iomgr/error.h
index 49f4029bc2..cb740d5b01 100644
--- a/src/core/lib/iomgr/error.h
+++ b/src/core/lib/iomgr/error.h
@@ -120,8 +120,15 @@ typedef enum {
/// polling engines) can safely use the lower bit for themselves.
#define GRPC_ERROR_NONE ((grpc_error*)NULL)
+#define GRPC_ERROR_RESERVED_1 ((grpc_error*)1)
#define GRPC_ERROR_OOM ((grpc_error*)2)
+#define GRPC_ERROR_RESERVED_2 ((grpc_error*)3)
#define GRPC_ERROR_CANCELLED ((grpc_error*)4)
+#define GRPC_ERROR_SPECIAL_MAX GRPC_ERROR_CANCELLED
+
+inline bool grpc_error_is_special(struct grpc_error* err) {
+ return err <= GRPC_ERROR_SPECIAL_MAX;
+}
// debug only toggles that allow for a sanity to check that ensures we will
// never create any errors in the per-RPC hotpath.
@@ -158,19 +165,37 @@ grpc_error* grpc_error_create(const char* file, int line, grpc_slice desc,
errs, count)
#ifndef NDEBUG
-grpc_error* grpc_error_ref(grpc_error* err, const char* file, int line);
-void grpc_error_unref(grpc_error* err, const char* file, int line);
+grpc_error* grpc_error_do_ref(grpc_error* err, const char* file, int line);
+void grpc_error_do_unref(grpc_error* err, const char* file, int line);
+inline grpc_error* grpc_error_ref(grpc_error* err, const char* file, int line) {
+ if (grpc_error_is_special(err)) return err;
+ return grpc_error_do_ref(err, file, line);
+}
+inline void grpc_error_unref(grpc_error* err, const char* file, int line) {
+ if (grpc_error_is_special(err)) return;
+ grpc_error_do_unref(err, file, line);
+}
#define GRPC_ERROR_REF(err) grpc_error_ref(err, __FILE__, __LINE__)
#define GRPC_ERROR_UNREF(err) grpc_error_unref(err, __FILE__, __LINE__)
#else
-grpc_error* grpc_error_ref(grpc_error* err);
-void grpc_error_unref(grpc_error* err);
+grpc_error* grpc_error_do_ref(grpc_error* err);
+void grpc_error_do_unref(grpc_error* err);
+inline grpc_error* grpc_error_ref(grpc_error* err) {
+ if (grpc_error_is_special(err)) return err;
+ return grpc_error_do_ref(err);
+}
+inline void grpc_error_unref(grpc_error* err) {
+ if (grpc_error_is_special(err)) return;
+ grpc_error_do_unref(err);
+}
#define GRPC_ERROR_REF(err) grpc_error_ref(err)
#define GRPC_ERROR_UNREF(err) grpc_error_unref(err)
#endif
grpc_error* grpc_error_set_int(grpc_error* src, grpc_error_ints which,
intptr_t value) GRPC_MUST_USE_RESULT;
+/// It is an error to pass nullptr as `p`. Caller should allocate a dummy
+/// intptr_t for `p`, even if the value of `p` is not used.
bool grpc_error_get_int(grpc_error* error, grpc_error_ints which, intptr_t* p);
/// This call takes ownership of the slice; the error is responsible for
/// eventually unref-ing it.
diff --git a/src/core/lib/iomgr/error_internal.h b/src/core/lib/iomgr/error_internal.h
index 7fde347abd..8027396019 100644
--- a/src/core/lib/iomgr/error_internal.h
+++ b/src/core/lib/iomgr/error_internal.h
@@ -58,6 +58,4 @@ struct grpc_error {
intptr_t arena[0];
};
-bool grpc_error_is_special(struct grpc_error* err);
-
#endif /* GRPC_CORE_LIB_IOMGR_ERROR_INTERNAL_H */
diff --git a/src/core/lib/iomgr/socket_utils_common_posix.cc b/src/core/lib/iomgr/socket_utils_common_posix.cc
index 50674b0845..bdfc1d70c3 100644
--- a/src/core/lib/iomgr/socket_utils_common_posix.cc
+++ b/src/core/lib/iomgr/socket_utils_common_posix.cc
@@ -307,7 +307,10 @@ grpc_error* grpc_set_socket_tcp_user_timeout(
}
}
#else
- gpr_log(GPR_INFO, "TCP_USER_TIMEOUT not supported for this platform");
+ extern grpc_core::TraceFlag grpc_tcp_trace;
+ if (grpc_tcp_trace.enabled()) {
+ gpr_log(GPR_INFO, "TCP_USER_TIMEOUT not supported for this platform");
+ }
#endif /* GRPC_HAVE_TCP_USER_TIMEOUT */
return GRPC_ERROR_NONE;
}
diff --git a/src/core/lib/surface/completion_queue.cc b/src/core/lib/surface/completion_queue.cc
index 5dc9991f70..b81ae73b4d 100644
--- a/src/core/lib/surface/completion_queue.cc
+++ b/src/core/lib/surface/completion_queue.cc
@@ -79,6 +79,7 @@ typedef struct non_polling_worker {
typedef struct {
gpr_mu mu;
+ bool kicked_without_poller;
non_polling_worker* root;
grpc_closure* shutdown;
} non_polling_poller;
@@ -103,6 +104,10 @@ static grpc_error* non_polling_poller_work(grpc_pollset* pollset,
grpc_millis deadline) {
non_polling_poller* npp = reinterpret_cast<non_polling_poller*>(pollset);
if (npp->shutdown) return GRPC_ERROR_NONE;
+ if (npp->kicked_without_poller) {
+ npp->kicked_without_poller = false;
+ return GRPC_ERROR_NONE;
+ }
non_polling_worker w;
gpr_cv_init(&w.cv);
if (worker != nullptr) *worker = reinterpret_cast<grpc_pollset_worker*>(&w);
@@ -148,6 +153,8 @@ static grpc_error* non_polling_poller_kick(
w->kicked = true;
gpr_cv_signal(&w->cv);
}
+ } else {
+ p->kicked_without_poller = true;
}
return GRPC_ERROR_NONE;
}
diff --git a/src/core/lib/transport/error_utils.cc b/src/core/lib/transport/error_utils.cc
index 2eff8b2916..558f1d494c 100644
--- a/src/core/lib/transport/error_utils.cc
+++ b/src/core/lib/transport/error_utils.cc
@@ -26,8 +26,9 @@
static grpc_error* recursively_find_error_with_field(grpc_error* error,
grpc_error_ints which) {
+ intptr_t unused;
// If the error itself has a status code, return it.
- if (grpc_error_get_int(error, which, nullptr)) {
+ if (grpc_error_get_int(error, which, &unused)) {
return error;
}
if (grpc_error_is_special(error)) return nullptr;
@@ -102,7 +103,8 @@ void grpc_error_get_status(grpc_error* error, grpc_millis deadline,
}
bool grpc_error_has_clear_grpc_status(grpc_error* error) {
- if (grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, nullptr)) {
+ intptr_t unused;
+ if (grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, &unused)) {
return true;
}
uint8_t slot = error->first_err;
diff --git a/src/core/plugin_registry/grpc_plugin_registry.cc b/src/core/plugin_registry/grpc_plugin_registry.cc
index fb523a173d..94c2493d5e 100644
--- a/src/core/plugin_registry/grpc_plugin_registry.cc
+++ b/src/core/plugin_registry/grpc_plugin_registry.cc
@@ -36,6 +36,8 @@ void grpc_resolver_fake_init(void);
void grpc_resolver_fake_shutdown(void);
void grpc_lb_policy_grpclb_init(void);
void grpc_lb_policy_grpclb_shutdown(void);
+void grpc_lb_policy_xds_init(void);
+void grpc_lb_policy_xds_shutdown(void);
void grpc_lb_policy_pick_first_init(void);
void grpc_lb_policy_pick_first_shutdown(void);
void grpc_lb_policy_round_robin_init(void);
@@ -72,6 +74,8 @@ void grpc_register_built_in_plugins(void) {
grpc_resolver_fake_shutdown);
grpc_register_plugin(grpc_lb_policy_grpclb_init,
grpc_lb_policy_grpclb_shutdown);
+ grpc_register_plugin(grpc_lb_policy_xds_init,
+ grpc_lb_policy_xds_shutdown);
grpc_register_plugin(grpc_lb_policy_pick_first_init,
grpc_lb_policy_pick_first_shutdown);
grpc_register_plugin(grpc_lb_policy_round_robin_init,
diff --git a/src/core/plugin_registry/grpc_unsecure_plugin_registry.cc b/src/core/plugin_registry/grpc_unsecure_plugin_registry.cc
index 80214aebe2..5749ab6b95 100644
--- a/src/core/plugin_registry/grpc_unsecure_plugin_registry.cc
+++ b/src/core/plugin_registry/grpc_unsecure_plugin_registry.cc
@@ -40,6 +40,8 @@ void grpc_resolver_fake_init(void);
void grpc_resolver_fake_shutdown(void);
void grpc_lb_policy_grpclb_init(void);
void grpc_lb_policy_grpclb_shutdown(void);
+void grpc_lb_policy_xds_init(void);
+void grpc_lb_policy_xds_shutdown(void);
void grpc_lb_policy_pick_first_init(void);
void grpc_lb_policy_pick_first_shutdown(void);
void grpc_lb_policy_round_robin_init(void);
@@ -74,6 +76,8 @@ void grpc_register_built_in_plugins(void) {
grpc_resolver_fake_shutdown);
grpc_register_plugin(grpc_lb_policy_grpclb_init,
grpc_lb_policy_grpclb_shutdown);
+ grpc_register_plugin(grpc_lb_policy_xds_init,
+ grpc_lb_policy_xds_shutdown);
grpc_register_plugin(grpc_lb_policy_pick_first_init,
grpc_lb_policy_pick_first_shutdown);
grpc_register_plugin(grpc_lb_policy_round_robin_init,
diff --git a/src/cpp/server/health/default_health_check_service.cc b/src/cpp/server/health/default_health_check_service.cc
index bfda67d086..0c03fdf17a 100644
--- a/src/cpp/server/health/default_health_check_service.cc
+++ b/src/cpp/server/health/default_health_check_service.cc
@@ -30,29 +30,159 @@
#include "src/cpp/server/health/health.pb.h"
namespace grpc {
+
+//
+// DefaultHealthCheckService
+//
+
+DefaultHealthCheckService::DefaultHealthCheckService() {
+ services_map_[""].SetServingStatus(SERVING);
+}
+
+void DefaultHealthCheckService::SetServingStatus(
+ const grpc::string& service_name, bool serving) {
+ std::unique_lock<std::mutex> lock(mu_);
+ services_map_[service_name].SetServingStatus(serving ? SERVING : NOT_SERVING);
+}
+
+void DefaultHealthCheckService::SetServingStatus(bool serving) {
+ const ServingStatus status = serving ? SERVING : NOT_SERVING;
+ std::unique_lock<std::mutex> lock(mu_);
+ for (auto& p : services_map_) {
+ ServiceData& service_data = p.second;
+ service_data.SetServingStatus(status);
+ }
+}
+
+DefaultHealthCheckService::ServingStatus
+DefaultHealthCheckService::GetServingStatus(
+ const grpc::string& service_name) const {
+ std::lock_guard<std::mutex> lock(mu_);
+ auto it = services_map_.find(service_name);
+ if (it == services_map_.end()) {
+ return NOT_FOUND;
+ }
+ const ServiceData& service_data = it->second;
+ return service_data.GetServingStatus();
+}
+
+void DefaultHealthCheckService::RegisterCallHandler(
+ const grpc::string& service_name,
+ std::shared_ptr<HealthCheckServiceImpl::CallHandler> handler) {
+ std::unique_lock<std::mutex> lock(mu_);
+ ServiceData& service_data = services_map_[service_name];
+ service_data.AddCallHandler(handler /* copies ref */);
+ HealthCheckServiceImpl::CallHandler* h = handler.get();
+ h->SendHealth(std::move(handler), service_data.GetServingStatus());
+}
+
+void DefaultHealthCheckService::UnregisterCallHandler(
+ const grpc::string& service_name,
+ std::shared_ptr<HealthCheckServiceImpl::CallHandler> handler) {
+ std::unique_lock<std::mutex> lock(mu_);
+ auto it = services_map_.find(service_name);
+ if (it == services_map_.end()) return;
+ ServiceData& service_data = it->second;
+ service_data.RemoveCallHandler(std::move(handler));
+ if (service_data.Unused()) {
+ services_map_.erase(it);
+ }
+}
+
+DefaultHealthCheckService::HealthCheckServiceImpl*
+DefaultHealthCheckService::GetHealthCheckService(
+ std::unique_ptr<ServerCompletionQueue> cq) {
+ GPR_ASSERT(impl_ == nullptr);
+ impl_.reset(new HealthCheckServiceImpl(this, std::move(cq)));
+ return impl_.get();
+}
+
+//
+// DefaultHealthCheckService::ServiceData
+//
+
+void DefaultHealthCheckService::ServiceData::SetServingStatus(
+ ServingStatus status) {
+ status_ = status;
+ for (auto& call_handler : call_handlers_) {
+ call_handler->SendHealth(call_handler /* copies ref */, status);
+ }
+}
+
+void DefaultHealthCheckService::ServiceData::AddCallHandler(
+ std::shared_ptr<HealthCheckServiceImpl::CallHandler> handler) {
+ call_handlers_.insert(std::move(handler));
+}
+
+void DefaultHealthCheckService::ServiceData::RemoveCallHandler(
+ std::shared_ptr<HealthCheckServiceImpl::CallHandler> handler) {
+ call_handlers_.erase(handler);
+}
+
+//
+// DefaultHealthCheckService::HealthCheckServiceImpl
+//
+
namespace {
const char kHealthCheckMethodName[] = "/grpc.health.v1.Health/Check";
+const char kHealthWatchMethodName[] = "/grpc.health.v1.Health/Watch";
} // namespace
DefaultHealthCheckService::HealthCheckServiceImpl::HealthCheckServiceImpl(
- DefaultHealthCheckService* service)
- : service_(service), method_(nullptr) {
- internal::MethodHandler* handler =
- new internal::RpcMethodHandler<HealthCheckServiceImpl, ByteBuffer,
- ByteBuffer>(
- std::mem_fn(&HealthCheckServiceImpl::Check), this);
- method_ = new internal::RpcServiceMethod(
- kHealthCheckMethodName, internal::RpcMethod::NORMAL_RPC, handler);
- AddMethod(method_);
-}
-
-Status DefaultHealthCheckService::HealthCheckServiceImpl::Check(
- ServerContext* context, const ByteBuffer* request, ByteBuffer* response) {
- // Decode request.
- std::vector<Slice> slices;
- if (!request->Dump(&slices).ok()) {
- return Status(StatusCode::INVALID_ARGUMENT, "");
+ DefaultHealthCheckService* database,
+ std::unique_ptr<ServerCompletionQueue> cq)
+ : database_(database), cq_(std::move(cq)) {
+ // Add Check() method.
+ AddMethod(new internal::RpcServiceMethod(
+ kHealthCheckMethodName, internal::RpcMethod::NORMAL_RPC, nullptr));
+ // Add Watch() method.
+ AddMethod(new internal::RpcServiceMethod(
+ kHealthWatchMethodName, internal::RpcMethod::SERVER_STREAMING, nullptr));
+ // Create serving thread.
+ thread_ = std::unique_ptr<::grpc_core::Thread>(
+ new ::grpc_core::Thread("grpc_health_check_service", Serve, this));
+}
+
+DefaultHealthCheckService::HealthCheckServiceImpl::~HealthCheckServiceImpl() {
+ // We will reach here after the server starts shutting down.
+ shutdown_ = true;
+ {
+ std::unique_lock<std::mutex> lock(cq_shutdown_mu_);
+ cq_->Shutdown();
}
+ thread_->Join();
+}
+
+void DefaultHealthCheckService::HealthCheckServiceImpl::StartServingThread() {
+ // Request the calls we're interested in.
+ // We do this before starting the serving thread, so that we know it's
+ // done before server startup is complete.
+ CheckCallHandler::CreateAndStart(cq_.get(), database_, this);
+ WatchCallHandler::CreateAndStart(cq_.get(), database_, this);
+ // Start serving thread.
+ thread_->Start();
+}
+
+void DefaultHealthCheckService::HealthCheckServiceImpl::Serve(void* arg) {
+ HealthCheckServiceImpl* service =
+ reinterpret_cast<HealthCheckServiceImpl*>(arg);
+ void* tag;
+ bool ok;
+ while (true) {
+ if (!service->cq_->Next(&tag, &ok)) {
+ // The completion queue is shutting down.
+ GPR_ASSERT(service->shutdown_);
+ break;
+ }
+ auto* next_step = static_cast<CallableTag*>(tag);
+ next_step->Run(ok);
+ }
+}
+
+bool DefaultHealthCheckService::HealthCheckServiceImpl::DecodeRequest(
+ const ByteBuffer& request, grpc::string* service_name) {
+ std::vector<Slice> slices;
+ if (!request.Dump(&slices).ok()) return false;
uint8_t* request_bytes = nullptr;
bool request_bytes_owned = false;
size_t request_size = 0;
@@ -64,14 +194,13 @@ Status DefaultHealthCheckService::HealthCheckServiceImpl::Check(
request_size = slices[0].size();
} else {
request_bytes_owned = true;
- request_bytes = static_cast<uint8_t*>(gpr_malloc(request->Length()));
+ request_bytes = static_cast<uint8_t*>(gpr_malloc(request.Length()));
uint8_t* copy_to = request_bytes;
for (size_t i = 0; i < slices.size(); i++) {
memcpy(copy_to, slices[i].begin(), slices[i].size());
copy_to += slices[i].size();
}
}
-
if (request_bytes != nullptr) {
pb_istream_t istream = pb_istream_from_buffer(request_bytes, request_size);
bool decode_status = pb_decode(
@@ -79,26 +208,22 @@ Status DefaultHealthCheckService::HealthCheckServiceImpl::Check(
if (request_bytes_owned) {
gpr_free(request_bytes);
}
- if (!decode_status) {
- return Status(StatusCode::INVALID_ARGUMENT, "");
- }
- }
-
- // Check status from the associated default health checking service.
- DefaultHealthCheckService::ServingStatus serving_status =
- service_->GetServingStatus(
- request_struct.has_service ? request_struct.service : "");
- if (serving_status == DefaultHealthCheckService::NOT_FOUND) {
- return Status(StatusCode::NOT_FOUND, "");
+ if (!decode_status) return false;
}
+ *service_name = request_struct.has_service ? request_struct.service : "";
+ return true;
+}
- // Encode response
+bool DefaultHealthCheckService::HealthCheckServiceImpl::EncodeResponse(
+ ServingStatus status, ByteBuffer* response) {
grpc_health_v1_HealthCheckResponse response_struct;
response_struct.has_status = true;
response_struct.status =
- serving_status == DefaultHealthCheckService::SERVING
- ? grpc_health_v1_HealthCheckResponse_ServingStatus_SERVING
- : grpc_health_v1_HealthCheckResponse_ServingStatus_NOT_SERVING;
+ status == NOT_FOUND
+ ? grpc_health_v1_HealthCheckResponse_ServingStatus_SERVICE_UNKNOWN
+ : status == SERVING
+ ? grpc_health_v1_HealthCheckResponse_ServingStatus_SERVING
+ : grpc_health_v1_HealthCheckResponse_ServingStatus_NOT_SERVING;
pb_ostream_t ostream;
memset(&ostream, 0, sizeof(ostream));
pb_encode(&ostream, grpc_health_v1_HealthCheckResponse_fields,
@@ -108,48 +233,250 @@ Status DefaultHealthCheckService::HealthCheckServiceImpl::Check(
GRPC_SLICE_LENGTH(response_slice));
bool encode_status = pb_encode(
&ostream, grpc_health_v1_HealthCheckResponse_fields, &response_struct);
- if (!encode_status) {
- return Status(StatusCode::INTERNAL, "Failed to encode response.");
- }
+ if (!encode_status) return false;
Slice encoded_response(response_slice, Slice::STEAL_REF);
ByteBuffer response_buffer(&encoded_response, 1);
response->Swap(&response_buffer);
- return Status::OK;
+ return true;
}
-DefaultHealthCheckService::DefaultHealthCheckService() {
- services_map_.emplace("", true);
+//
+// DefaultHealthCheckService::HealthCheckServiceImpl::CheckCallHandler
+//
+
+void DefaultHealthCheckService::HealthCheckServiceImpl::CheckCallHandler::
+ CreateAndStart(ServerCompletionQueue* cq,
+ DefaultHealthCheckService* database,
+ HealthCheckServiceImpl* service) {
+ std::shared_ptr<CallHandler> self =
+ std::make_shared<CheckCallHandler>(cq, database, service);
+ CheckCallHandler* handler = static_cast<CheckCallHandler*>(self.get());
+ {
+ std::unique_lock<std::mutex> lock(service->cq_shutdown_mu_);
+ if (service->shutdown_) return;
+ // Request a Check() call.
+ handler->next_ =
+ CallableTag(std::bind(&CheckCallHandler::OnCallReceived, handler,
+ std::placeholders::_1, std::placeholders::_2),
+ std::move(self));
+ service->RequestAsyncUnary(0, &handler->ctx_, &handler->request_,
+ &handler->writer_, cq, cq, &handler->next_);
+ }
}
-void DefaultHealthCheckService::SetServingStatus(
- const grpc::string& service_name, bool serving) {
- std::lock_guard<std::mutex> lock(mu_);
- services_map_[service_name] = serving;
+DefaultHealthCheckService::HealthCheckServiceImpl::CheckCallHandler::
+ CheckCallHandler(ServerCompletionQueue* cq,
+ DefaultHealthCheckService* database,
+ HealthCheckServiceImpl* service)
+ : cq_(cq), database_(database), service_(service), writer_(&ctx_) {}
+
+void DefaultHealthCheckService::HealthCheckServiceImpl::CheckCallHandler::
+ OnCallReceived(std::shared_ptr<CallHandler> self, bool ok) {
+ if (!ok) {
+ // The value of ok being false means that the server is shutting down.
+ return;
+ }
+ // Spawn a new handler instance to serve the next new client. Every handler
+ // instance will deallocate itself when it's done.
+ CreateAndStart(cq_, database_, service_);
+ // Process request.
+ gpr_log(GPR_DEBUG, "[HCS %p] Health check started for handler %p", service_,
+ this);
+ grpc::string service_name;
+ grpc::Status status = Status::OK;
+ ByteBuffer response;
+ if (!service_->DecodeRequest(request_, &service_name)) {
+ status = Status(StatusCode::INVALID_ARGUMENT, "could not parse request");
+ } else {
+ ServingStatus serving_status = database_->GetServingStatus(service_name);
+ if (serving_status == NOT_FOUND) {
+ status = Status(StatusCode::NOT_FOUND, "service name unknown");
+ } else if (!service_->EncodeResponse(serving_status, &response)) {
+ status = Status(StatusCode::INTERNAL, "could not encode response");
+ }
+ }
+ // Send response.
+ {
+ std::unique_lock<std::mutex> lock(service_->cq_shutdown_mu_);
+ if (!service_->shutdown_) {
+ next_ =
+ CallableTag(std::bind(&CheckCallHandler::OnFinishDone, this,
+ std::placeholders::_1, std::placeholders::_2),
+ std::move(self));
+ if (status.ok()) {
+ writer_.Finish(response, status, &next_);
+ } else {
+ writer_.FinishWithError(status, &next_);
+ }
+ }
+ }
}
-void DefaultHealthCheckService::SetServingStatus(bool serving) {
- std::lock_guard<std::mutex> lock(mu_);
- for (auto iter = services_map_.begin(); iter != services_map_.end(); ++iter) {
- iter->second = serving;
+void DefaultHealthCheckService::HealthCheckServiceImpl::CheckCallHandler::
+ OnFinishDone(std::shared_ptr<CallHandler> self, bool ok) {
+ if (ok) {
+ gpr_log(GPR_DEBUG, "[HCS %p] Health check call finished for handler %p",
+ service_, this);
}
}
-DefaultHealthCheckService::ServingStatus
-DefaultHealthCheckService::GetServingStatus(
- const grpc::string& service_name) const {
- std::lock_guard<std::mutex> lock(mu_);
- const auto& iter = services_map_.find(service_name);
- if (iter == services_map_.end()) {
- return NOT_FOUND;
+//
+// DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler
+//
+
+void DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler::
+ CreateAndStart(ServerCompletionQueue* cq,
+ DefaultHealthCheckService* database,
+ HealthCheckServiceImpl* service) {
+ std::shared_ptr<CallHandler> self =
+ std::make_shared<WatchCallHandler>(cq, database, service);
+ WatchCallHandler* handler = static_cast<WatchCallHandler*>(self.get());
+ {
+ std::unique_lock<std::mutex> lock(service->cq_shutdown_mu_);
+ if (service->shutdown_) return;
+ // Request AsyncNotifyWhenDone().
+ handler->on_done_notified_ =
+ CallableTag(std::bind(&WatchCallHandler::OnDoneNotified, handler,
+ std::placeholders::_1, std::placeholders::_2),
+ self /* copies ref */);
+ handler->ctx_.AsyncNotifyWhenDone(&handler->on_done_notified_);
+ // Request a Watch() call.
+ handler->next_ =
+ CallableTag(std::bind(&WatchCallHandler::OnCallReceived, handler,
+ std::placeholders::_1, std::placeholders::_2),
+ std::move(self));
+ service->RequestAsyncServerStreaming(1, &handler->ctx_, &handler->request_,
+ &handler->stream_, cq, cq,
+ &handler->next_);
}
- return iter->second ? SERVING : NOT_SERVING;
}
-DefaultHealthCheckService::HealthCheckServiceImpl*
-DefaultHealthCheckService::GetHealthCheckService() {
- GPR_ASSERT(impl_ == nullptr);
- impl_.reset(new HealthCheckServiceImpl(this));
- return impl_.get();
+DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler::
+ WatchCallHandler(ServerCompletionQueue* cq,
+ DefaultHealthCheckService* database,
+ HealthCheckServiceImpl* service)
+ : cq_(cq), database_(database), service_(service), stream_(&ctx_) {}
+
+void DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler::
+ OnCallReceived(std::shared_ptr<CallHandler> self, bool ok) {
+ if (!ok) {
+ // Server shutting down.
+ //
+ // AsyncNotifyWhenDone() needs to be called before the call starts, but the
+ // tag will not pop out if the call never starts (
+ // https://github.com/grpc/grpc/issues/10136). So we need to manually
+ // release the ownership of the handler in this case.
+ GPR_ASSERT(on_done_notified_.ReleaseHandler() != nullptr);
+ return;
+ }
+ // Spawn a new handler instance to serve the next new client. Every handler
+ // instance will deallocate itself when it's done.
+ CreateAndStart(cq_, database_, service_);
+ // Parse request.
+ if (!service_->DecodeRequest(request_, &service_name_)) {
+ SendFinish(std::move(self),
+ Status(StatusCode::INVALID_ARGUMENT, "could not parse request"));
+ return;
+ }
+ // Register the call for updates to the service.
+ gpr_log(GPR_DEBUG,
+ "[HCS %p] Health watch started for service \"%s\" (handler: %p)",
+ service_, service_name_.c_str(), this);
+ database_->RegisterCallHandler(service_name_, std::move(self));
+}
+
+void DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler::
+ SendHealth(std::shared_ptr<CallHandler> self, ServingStatus status) {
+ std::unique_lock<std::mutex> lock(send_mu_);
+ // If there's already a send in flight, cache the new status, and
+ // we'll start a new send for it when the one in flight completes.
+ if (send_in_flight_) {
+ pending_status_ = status;
+ return;
+ }
+ // Start a send.
+ SendHealthLocked(std::move(self), status);
+}
+
+void DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler::
+ SendHealthLocked(std::shared_ptr<CallHandler> self, ServingStatus status) {
+ send_in_flight_ = true;
+ // Construct response.
+ ByteBuffer response;
+ bool success = service_->EncodeResponse(status, &response);
+ // Grab shutdown lock and send response.
+ std::unique_lock<std::mutex> cq_lock(service_->cq_shutdown_mu_);
+ if (service_->shutdown_) {
+ SendFinishLocked(std::move(self), Status::CANCELLED);
+ return;
+ }
+ if (!success) {
+ SendFinishLocked(std::move(self),
+ Status(StatusCode::INTERNAL, "could not encode response"));
+ return;
+ }
+ next_ = CallableTag(std::bind(&WatchCallHandler::OnSendHealthDone, this,
+ std::placeholders::_1, std::placeholders::_2),
+ std::move(self));
+ stream_.Write(response, &next_);
+}
+
+void DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler::
+ OnSendHealthDone(std::shared_ptr<CallHandler> self, bool ok) {
+ if (!ok) {
+ SendFinish(std::move(self), Status::CANCELLED);
+ return;
+ }
+ std::unique_lock<std::mutex> lock(send_mu_);
+ send_in_flight_ = false;
+ // If we got a new status since we started the last send, start a
+ // new send for it.
+ if (pending_status_ != NOT_FOUND) {
+ auto status = pending_status_;
+ pending_status_ = NOT_FOUND;
+ SendHealthLocked(std::move(self), status);
+ }
+}
+
+void DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler::
+ SendFinish(std::shared_ptr<CallHandler> self, const Status& status) {
+ if (finish_called_) return;
+ std::unique_lock<std::mutex> cq_lock(service_->cq_shutdown_mu_);
+ if (!service_->shutdown_) return;
+ SendFinishLocked(std::move(self), status);
+}
+
+void DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler::
+ SendFinishLocked(std::shared_ptr<CallHandler> self, const Status& status) {
+ on_finish_done_ =
+ CallableTag(std::bind(&WatchCallHandler::OnFinishDone, this,
+ std::placeholders::_1, std::placeholders::_2),
+ std::move(self));
+ stream_.Finish(status, &on_finish_done_);
+ finish_called_ = true;
+}
+
+void DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler::
+ OnFinishDone(std::shared_ptr<CallHandler> self, bool ok) {
+ if (ok) {
+ gpr_log(GPR_DEBUG,
+ "[HCS %p] Health watch call finished (service_name: \"%s\", "
+ "handler: %p).",
+ service_, service_name_.c_str(), this);
+ }
+}
+
+// TODO(roth): This method currently assumes that there will be only one
+// thread polling the cq and invoking the corresponding callbacks. If
+// that changes, we will need to add synchronization here.
+void DefaultHealthCheckService::HealthCheckServiceImpl::WatchCallHandler::
+ OnDoneNotified(std::shared_ptr<CallHandler> self, bool ok) {
+ GPR_ASSERT(ok);
+ gpr_log(GPR_DEBUG,
+ "[HCS %p] Healt watch call is notified done (handler: %p, "
+ "is_cancelled: %d).",
+ service_, this, static_cast<int>(ctx_.IsCancelled()));
+ SendFinish(std::move(self), Status::CANCELLED);
}
} // namespace grpc
diff --git a/src/cpp/server/health/default_health_check_service.h b/src/cpp/server/health/default_health_check_service.h
index a1ce5aa64e..3bab76b6b0 100644
--- a/src/cpp/server/health/default_health_check_service.h
+++ b/src/cpp/server/health/default_health_check_service.h
@@ -19,42 +19,260 @@
#ifndef GRPC_INTERNAL_CPP_SERVER_DEFAULT_HEALTH_CHECK_SERVICE_H
#define GRPC_INTERNAL_CPP_SERVER_DEFAULT_HEALTH_CHECK_SERVICE_H
+#include <atomic>
#include <mutex>
+#include <set>
+#include <grpc/support/log.h>
+#include <grpcpp/grpcpp.h>
#include <grpcpp/health_check_service_interface.h>
+#include <grpcpp/impl/codegen/async_generic_service.h>
+#include <grpcpp/impl/codegen/async_unary_call.h>
#include <grpcpp/impl/codegen/service_type.h>
#include <grpcpp/support/byte_buffer.h>
+#include "src/core/lib/gprpp/thd.h"
+
namespace grpc {
// Default implementation of HealthCheckServiceInterface. Server will create and
// own it.
class DefaultHealthCheckService final : public HealthCheckServiceInterface {
public:
+ enum ServingStatus { NOT_FOUND, SERVING, NOT_SERVING };
+
// The service impl to register with the server.
class HealthCheckServiceImpl : public Service {
public:
- explicit HealthCheckServiceImpl(DefaultHealthCheckService* service);
+ // Base class for call handlers.
+ class CallHandler {
+ public:
+ virtual ~CallHandler() = default;
+ virtual void SendHealth(std::shared_ptr<CallHandler> self,
+ ServingStatus status) = 0;
+ };
- Status Check(ServerContext* context, const ByteBuffer* request,
- ByteBuffer* response);
+ HealthCheckServiceImpl(DefaultHealthCheckService* database,
+ std::unique_ptr<ServerCompletionQueue> cq);
+
+ ~HealthCheckServiceImpl();
+
+ void StartServingThread();
private:
- const DefaultHealthCheckService* const service_;
- internal::RpcServiceMethod* method_;
+ // A tag that can be called with a bool argument. It's tailored for
+ // CallHandler's use. Before being used, it should be constructed with a
+ // method of CallHandler and a shared pointer to the handler. The
+ // shared pointer will be moved to the invoked function and the function
+ // can only be invoked once. That makes ref counting of the handler easier,
+ // because the shared pointer is not bound to the function and can be gone
+ // once the invoked function returns (if not used any more).
+ class CallableTag {
+ public:
+ using HandlerFunction =
+ std::function<void(std::shared_ptr<CallHandler>, bool)>;
+
+ CallableTag() {}
+
+ CallableTag(HandlerFunction func, std::shared_ptr<CallHandler> handler)
+ : handler_function_(std::move(func)), handler_(std::move(handler)) {
+ GPR_ASSERT(handler_function_ != nullptr);
+ GPR_ASSERT(handler_ != nullptr);
+ }
+
+ // Runs the tag. This should be called only once. The handler is no
+ // longer owned by this tag after this method is invoked.
+ void Run(bool ok) {
+ GPR_ASSERT(handler_function_ != nullptr);
+ GPR_ASSERT(handler_ != nullptr);
+ handler_function_(std::move(handler_), ok);
+ }
+
+ // Releases and returns the shared pointer to the handler.
+ std::shared_ptr<CallHandler> ReleaseHandler() {
+ return std::move(handler_);
+ }
+
+ private:
+ HandlerFunction handler_function_ = nullptr;
+ std::shared_ptr<CallHandler> handler_;
+ };
+
+ // Call handler for Check method.
+ // Each handler takes care of one call. It contains per-call data and it
+ // will access the members of the parent class (i.e.,
+ // DefaultHealthCheckService) for per-service health data.
+ class CheckCallHandler : public CallHandler {
+ public:
+ // Instantiates a CheckCallHandler and requests the next health check
+ // call. The handler object will manage its own lifetime, so no action is
+ // needed from the caller any more regarding that object.
+ static void CreateAndStart(ServerCompletionQueue* cq,
+ DefaultHealthCheckService* database,
+ HealthCheckServiceImpl* service);
+
+ // This ctor is public because we want to use std::make_shared<> in
+ // CreateAndStart(). This ctor shouldn't be used elsewhere.
+ CheckCallHandler(ServerCompletionQueue* cq,
+ DefaultHealthCheckService* database,
+ HealthCheckServiceImpl* service);
+
+ // Not used for Check.
+ void SendHealth(std::shared_ptr<CallHandler> self,
+ ServingStatus status) override {}
+
+ private:
+ // Called when we receive a call.
+ // Spawns a new handler so that we can keep servicing future calls.
+ void OnCallReceived(std::shared_ptr<CallHandler> self, bool ok);
+
+ // Called when Finish() is done.
+ void OnFinishDone(std::shared_ptr<CallHandler> self, bool ok);
+
+ // The members passed down from HealthCheckServiceImpl.
+ ServerCompletionQueue* cq_;
+ DefaultHealthCheckService* database_;
+ HealthCheckServiceImpl* service_;
+
+ ByteBuffer request_;
+ GenericServerAsyncResponseWriter writer_;
+ ServerContext ctx_;
+
+ CallableTag next_;
+ };
+
+ // Call handler for Watch method.
+ // Each handler takes care of one call. It contains per-call data and it
+ // will access the members of the parent class (i.e.,
+ // DefaultHealthCheckService) for per-service health data.
+ class WatchCallHandler : public CallHandler {
+ public:
+ // Instantiates a WatchCallHandler and requests the next health check
+ // call. The handler object will manage its own lifetime, so no action is
+ // needed from the caller any more regarding that object.
+ static void CreateAndStart(ServerCompletionQueue* cq,
+ DefaultHealthCheckService* database,
+ HealthCheckServiceImpl* service);
+
+ // This ctor is public because we want to use std::make_shared<> in
+ // CreateAndStart(). This ctor shouldn't be used elsewhere.
+ WatchCallHandler(ServerCompletionQueue* cq,
+ DefaultHealthCheckService* database,
+ HealthCheckServiceImpl* service);
+
+ void SendHealth(std::shared_ptr<CallHandler> self,
+ ServingStatus status) override;
+
+ private:
+ // Called when we receive a call.
+ // Spawns a new handler so that we can keep servicing future calls.
+ void OnCallReceived(std::shared_ptr<CallHandler> self, bool ok);
+
+ // Requires holding send_mu_.
+ void SendHealthLocked(std::shared_ptr<CallHandler> self,
+ ServingStatus status);
+
+ // When sending a health result finishes.
+ void OnSendHealthDone(std::shared_ptr<CallHandler> self, bool ok);
+
+ void SendFinish(std::shared_ptr<CallHandler> self, const Status& status);
+
+ // Requires holding service_->cq_shutdown_mu_.
+ void SendFinishLocked(std::shared_ptr<CallHandler> self,
+ const Status& status);
+
+ // Called when Finish() is done.
+ void OnFinishDone(std::shared_ptr<CallHandler> self, bool ok);
+
+ // Called when AsyncNotifyWhenDone() notifies us.
+ void OnDoneNotified(std::shared_ptr<CallHandler> self, bool ok);
+
+ // The members passed down from HealthCheckServiceImpl.
+ ServerCompletionQueue* cq_;
+ DefaultHealthCheckService* database_;
+ HealthCheckServiceImpl* service_;
+
+ ByteBuffer request_;
+ grpc::string service_name_;
+ GenericServerAsyncWriter stream_;
+ ServerContext ctx_;
+
+ std::mutex send_mu_;
+ bool send_in_flight_ = false; // Guarded by mu_.
+ ServingStatus pending_status_ = NOT_FOUND; // Guarded by mu_.
+
+ bool finish_called_ = false;
+ CallableTag next_;
+ CallableTag on_done_notified_;
+ CallableTag on_finish_done_;
+ };
+
+ // Handles the incoming requests and drives the completion queue in a loop.
+ static void Serve(void* arg);
+
+ // Returns true on success.
+ static bool DecodeRequest(const ByteBuffer& request,
+ grpc::string* service_name);
+ static bool EncodeResponse(ServingStatus status, ByteBuffer* response);
+
+ // Needed to appease Windows compilers, which don't seem to allow
+ // nested classes to access protected members in the parent's
+ // superclass.
+ using Service::RequestAsyncServerStreaming;
+ using Service::RequestAsyncUnary;
+
+ DefaultHealthCheckService* database_;
+ std::unique_ptr<ServerCompletionQueue> cq_;
+
+ // To synchronize the operations related to shutdown state of cq_, so that
+ // we don't enqueue new tags into cq_ after it is already shut down.
+ std::mutex cq_shutdown_mu_;
+ std::atomic_bool shutdown_{false};
+ std::unique_ptr<::grpc_core::Thread> thread_;
};
DefaultHealthCheckService();
+
void SetServingStatus(const grpc::string& service_name,
bool serving) override;
void SetServingStatus(bool serving) override;
- enum ServingStatus { NOT_FOUND, SERVING, NOT_SERVING };
+
ServingStatus GetServingStatus(const grpc::string& service_name) const;
- HealthCheckServiceImpl* GetHealthCheckService();
+
+ HealthCheckServiceImpl* GetHealthCheckService(
+ std::unique_ptr<ServerCompletionQueue> cq);
private:
+ // Stores the current serving status of a service and any call
+ // handlers registered for updates when the service's status changes.
+ class ServiceData {
+ public:
+ void SetServingStatus(ServingStatus status);
+ ServingStatus GetServingStatus() const { return status_; }
+ void AddCallHandler(
+ std::shared_ptr<HealthCheckServiceImpl::CallHandler> handler);
+ void RemoveCallHandler(
+ std::shared_ptr<HealthCheckServiceImpl::CallHandler> handler);
+ bool Unused() const {
+ return call_handlers_.empty() && status_ == NOT_FOUND;
+ }
+
+ private:
+ ServingStatus status_ = NOT_FOUND;
+ std::set<std::shared_ptr<HealthCheckServiceImpl::CallHandler>>
+ call_handlers_;
+ };
+
+ void RegisterCallHandler(
+ const grpc::string& service_name,
+ std::shared_ptr<HealthCheckServiceImpl::CallHandler> handler);
+
+ void UnregisterCallHandler(
+ const grpc::string& service_name,
+ std::shared_ptr<HealthCheckServiceImpl::CallHandler> handler);
+
mutable std::mutex mu_;
- std::map<grpc::string, bool> services_map_;
+ std::map<grpc::string, ServiceData> services_map_; // Guarded by mu_.
std::unique_ptr<HealthCheckServiceImpl> impl_;
};
diff --git a/src/cpp/server/health/health.pb.c b/src/cpp/server/health/health.pb.c
index 09bd98a3d9..5c214c7160 100644
--- a/src/cpp/server/health/health.pb.c
+++ b/src/cpp/server/health/health.pb.c
@@ -2,7 +2,6 @@
/* Generated by nanopb-0.3.7-dev */
#include "src/cpp/server/health/health.pb.h"
-
/* @@protoc_insertion_point(includes) */
#if PB_PROTO_HEADER_VERSION != 30
#error Regenerate this file with the current version of nanopb generator.
diff --git a/src/cpp/server/health/health.pb.h b/src/cpp/server/health/health.pb.h
index 29e1f3bacb..9d54ccd618 100644
--- a/src/cpp/server/health/health.pb.h
+++ b/src/cpp/server/health/health.pb.h
@@ -17,11 +17,12 @@ extern "C" {
typedef enum _grpc_health_v1_HealthCheckResponse_ServingStatus {
grpc_health_v1_HealthCheckResponse_ServingStatus_UNKNOWN = 0,
grpc_health_v1_HealthCheckResponse_ServingStatus_SERVING = 1,
- grpc_health_v1_HealthCheckResponse_ServingStatus_NOT_SERVING = 2
+ grpc_health_v1_HealthCheckResponse_ServingStatus_NOT_SERVING = 2,
+ grpc_health_v1_HealthCheckResponse_ServingStatus_SERVICE_UNKNOWN = 3
} grpc_health_v1_HealthCheckResponse_ServingStatus;
#define _grpc_health_v1_HealthCheckResponse_ServingStatus_MIN grpc_health_v1_HealthCheckResponse_ServingStatus_UNKNOWN
-#define _grpc_health_v1_HealthCheckResponse_ServingStatus_MAX grpc_health_v1_HealthCheckResponse_ServingStatus_NOT_SERVING
-#define _grpc_health_v1_HealthCheckResponse_ServingStatus_ARRAYSIZE ((grpc_health_v1_HealthCheckResponse_ServingStatus)(grpc_health_v1_HealthCheckResponse_ServingStatus_NOT_SERVING+1))
+#define _grpc_health_v1_HealthCheckResponse_ServingStatus_MAX grpc_health_v1_HealthCheckResponse_ServingStatus_SERVICE_UNKNOWN
+#define _grpc_health_v1_HealthCheckResponse_ServingStatus_ARRAYSIZE ((grpc_health_v1_HealthCheckResponse_ServingStatus)(grpc_health_v1_HealthCheckResponse_ServingStatus_SERVICE_UNKNOWN+1))
/* Struct definitions */
typedef struct _grpc_health_v1_HealthCheckRequest {
diff --git a/src/cpp/server/server_cc.cc b/src/cpp/server/server_cc.cc
index 7c764f4bce..373a925059 100644
--- a/src/cpp/server/server_cc.cc
+++ b/src/cpp/server/server_cc.cc
@@ -380,7 +380,6 @@ class Server::SyncRequestThreadManager : public ThreadManager {
int cq_timeout_msec_;
std::vector<std::unique_ptr<SyncRequest>> sync_requests_;
std::unique_ptr<internal::RpcServiceMethod> unknown_method_;
- std::unique_ptr<internal::RpcServiceMethod> health_check_;
std::shared_ptr<Server::GlobalCallbacks> global_callbacks_;
};
@@ -573,16 +572,24 @@ void Server::Start(ServerCompletionQueue** cqs, size_t num_cqs) {
// Only create default health check service when user did not provide an
// explicit one.
+ ServerCompletionQueue* health_check_cq = nullptr;
+ DefaultHealthCheckService::HealthCheckServiceImpl*
+ default_health_check_service_impl = nullptr;
if (health_check_service_ == nullptr && !health_check_service_disabled_ &&
DefaultHealthCheckServiceEnabled()) {
- if (sync_server_cqs_ == nullptr || sync_server_cqs_->empty()) {
- gpr_log(GPR_INFO,
- "Default health check service disabled at async-only server.");
- } else {
- auto* default_hc_service = new DefaultHealthCheckService;
- health_check_service_.reset(default_hc_service);
- RegisterService(nullptr, default_hc_service->GetHealthCheckService());
- }
+ auto* default_hc_service = new DefaultHealthCheckService;
+ health_check_service_.reset(default_hc_service);
+ // We create a non-polling CQ to avoid impacting application
+ // performance. This ensures that we don't introduce thread hops
+ // for application requests that wind up on this CQ, which is polled
+ // in its own thread.
+ health_check_cq = new ServerCompletionQueue(GRPC_CQ_NON_POLLING);
+ grpc_server_register_completion_queue(server_, health_check_cq->cq(),
+ nullptr);
+ default_health_check_service_impl =
+ default_hc_service->GetHealthCheckService(
+ std::unique_ptr<ServerCompletionQueue>(health_check_cq));
+ RegisterService(nullptr, default_health_check_service_impl);
}
grpc_server_start(server_);
@@ -597,6 +604,9 @@ void Server::Start(ServerCompletionQueue** cqs, size_t num_cqs) {
new UnimplementedAsyncRequest(this, cqs[i]);
}
}
+ if (health_check_cq != nullptr) {
+ new UnimplementedAsyncRequest(this, health_check_cq);
+ }
}
// If this server has any support for synchronous methods (has any sync
@@ -609,6 +619,10 @@ void Server::Start(ServerCompletionQueue** cqs, size_t num_cqs) {
for (auto it = sync_req_mgrs_.begin(); it != sync_req_mgrs_.end(); it++) {
(*it)->Start();
}
+
+ if (default_health_check_service_impl != nullptr) {
+ default_health_check_service_impl->StartServingThread();
+ }
}
void Server::ShutdownInternal(gpr_timespec deadline) {
diff --git a/src/csharp/.editorconfig b/src/csharp/.editorconfig
index fabce7f5ba..c9a2c48a7d 100644
--- a/src/csharp/.editorconfig
+++ b/src/csharp/.editorconfig
@@ -6,3 +6,26 @@ indent_style = space
indent_size = 4
insert_final_newline = true
tab_width = 4
+
+; https://docs.microsoft.com/visualstudio/ide/editorconfig-code-style-settings-reference
+[*.cs]
+dotnet_sort_system_directives_first = true
+csharp_new_line_before_open_brace = accessors, anonymous_methods, control_blocks, events, indexers, local_functions, methods, properties, types
+csharp_new_line_before_else = true
+csharp_new_line_before_catch = true
+csharp_new_line_before_finally = true
+csharp_indent_case_contents = true
+csharp_indent_switch_labels = true
+csharp_space_after_cast = false
+csharp_space_after_keywords_in_control_flow_statements = true
+csharp_space_between_method_declaration_parameter_list_parentheses = false
+csharp_space_between_method_call_parameter_list_parentheses = false
+csharp_space_between_parentheses = false
+csharp_space_before_colon_in_inheritance_clause = true
+csharp_space_after_colon_in_inheritance_clause = true
+csharp_space_around_binary_operators = before_and_after
+csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
+csharp_space_between_method_call_name_and_opening_parenthesis = false
+csharp_space_between_method_call_empty_parameter_list_parentheses = false
+csharp_preserve_single_line_statements = true
+csharp_preserve_single_line_blocks = true
diff --git a/src/csharp/Grpc.Core.Tests/SanityTest.cs b/src/csharp/Grpc.Core.Tests/SanityTest.cs
index eaad409ec0..0904453b6e 100644
--- a/src/csharp/Grpc.Core.Tests/SanityTest.cs
+++ b/src/csharp/Grpc.Core.Tests/SanityTest.cs
@@ -102,6 +102,7 @@ namespace Grpc.Core.Tests
"Grpc.HealthCheck.Tests",
"Grpc.IntegrationTesting",
"Grpc.Reflection.Tests",
+ "Grpc.Tools.Tests",
};
foreach (var assemblyName in otherAssemblies)
{
diff --git a/src/csharp/Grpc.Tools.Tests/CSharpGeneratorTest.cs b/src/csharp/Grpc.Tools.Tests/CSharpGeneratorTest.cs
new file mode 100644
index 0000000000..e4c9b2fa84
--- /dev/null
+++ b/src/csharp/Grpc.Tools.Tests/CSharpGeneratorTest.cs
@@ -0,0 +1,85 @@
+#region Copyright notice and license
+
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using NUnit.Framework;
+
+namespace Grpc.Tools.Tests
+{
+ public class CSharpGeneratorTest : GeneratorTest
+ {
+ GeneratorServices _generator;
+
+ [SetUp]
+ public new void SetUp()
+ {
+ _generator = GeneratorServices.GetForLanguage("CSharp", _log);
+ }
+
+ [TestCase("foo.proto", "Foo.cs", "FooGrpc.cs")]
+ [TestCase("sub/foo.proto", "Foo.cs", "FooGrpc.cs")]
+ [TestCase("one_two.proto", "OneTwo.cs", "OneTwoGrpc.cs")]
+ [TestCase("__one_two!.proto", "OneTwo!.cs", "OneTwo!Grpc.cs")]
+ [TestCase("one(two).proto", "One(two).cs", "One(two)Grpc.cs")]
+ [TestCase("one_(two).proto", "One(two).cs", "One(two)Grpc.cs")]
+ [TestCase("one two.proto", "One two.cs", "One twoGrpc.cs")]
+ [TestCase("one_ two.proto", "One two.cs", "One twoGrpc.cs")]
+ [TestCase("one .proto", "One .cs", "One Grpc.cs")]
+ public void NameMangling(string proto, string expectCs, string expectGrpcCs)
+ {
+ var poss = _generator.GetPossibleOutputs(Utils.MakeItem(proto, "grpcservices", "both"));
+ Assert.AreEqual(2, poss.Length);
+ Assert.Contains(expectCs, poss);
+ Assert.Contains(expectGrpcCs, poss);
+ }
+
+ [Test]
+ public void NoGrpcOneOutput()
+ {
+ var poss = _generator.GetPossibleOutputs(Utils.MakeItem("foo.proto"));
+ Assert.AreEqual(1, poss.Length);
+ }
+
+ [TestCase("none")]
+ [TestCase("")]
+ public void GrpcNoneOneOutput(string grpc)
+ {
+ var item = Utils.MakeItem("foo.proto", "grpcservices", grpc);
+ var poss = _generator.GetPossibleOutputs(item);
+ Assert.AreEqual(1, poss.Length);
+ }
+
+ [TestCase("client")]
+ [TestCase("server")]
+ [TestCase("both")]
+ public void GrpcEnabledTwoOutputs(string grpc)
+ {
+ var item = Utils.MakeItem("foo.proto", "grpcservices", grpc);
+ var poss = _generator.GetPossibleOutputs(item);
+ Assert.AreEqual(2, poss.Length);
+ }
+
+ [Test]
+ public void OutputDirMetadataRecognized()
+ {
+ var item = Utils.MakeItem("foo.proto", "OutputDir", "out");
+ var poss = _generator.GetPossibleOutputs(item);
+ Assert.AreEqual(1, poss.Length);
+ Assert.That(poss[0], Is.EqualTo("out/Foo.cs") | Is.EqualTo("out\\Foo.cs"));
+ }
+ };
+}
diff --git a/src/csharp/Grpc.Tools.Tests/CppGeneratorTest.cs b/src/csharp/Grpc.Tools.Tests/CppGeneratorTest.cs
new file mode 100644
index 0000000000..bd0405a03a
--- /dev/null
+++ b/src/csharp/Grpc.Tools.Tests/CppGeneratorTest.cs
@@ -0,0 +1,88 @@
+#region Copyright notice and license
+
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System.IO;
+using NUnit.Framework;
+
+namespace Grpc.Tools.Tests
+{
+ public class CppGeneratorTest : GeneratorTest
+ {
+ GeneratorServices _generator;
+
+ [SetUp]
+ public new void SetUp()
+ {
+ _generator = GeneratorServices.GetForLanguage("Cpp", _log);
+ }
+
+ [TestCase("foo.proto", "", "foo")]
+ [TestCase("foo.proto", ".", "foo")]
+ [TestCase("foo.proto", "./", "foo")]
+ [TestCase("sub/foo.proto", "", "sub/foo")]
+ [TestCase("root/sub/foo.proto", "root", "sub/foo")]
+ [TestCase("root/sub/foo.proto", "root", "sub/foo")]
+ [TestCase("/root/sub/foo.proto", "/root", "sub/foo")]
+ public void RelativeDirectoryCompute(string proto, string root, string expectStem)
+ {
+ if (Path.DirectorySeparatorChar == '\\')
+ expectStem = expectStem.Replace('/', '\\');
+ var poss = _generator.GetPossibleOutputs(Utils.MakeItem(proto, "ProtoRoot", root));
+ Assert.AreEqual(2, poss.Length);
+ Assert.Contains(expectStem + ".pb.cc", poss);
+ Assert.Contains(expectStem + ".pb.h", poss);
+ }
+
+ [Test]
+ public void NoGrpcTwoOutputs()
+ {
+ var poss = _generator.GetPossibleOutputs(Utils.MakeItem("foo.proto"));
+ Assert.AreEqual(2, poss.Length);
+ }
+
+ [TestCase("false")]
+ [TestCase("")]
+ public void GrpcDisabledTwoOutput(string grpc)
+ {
+ var item = Utils.MakeItem("foo.proto", "grpcservices", grpc);
+ var poss = _generator.GetPossibleOutputs(item);
+ Assert.AreEqual(2, poss.Length);
+ }
+
+ [TestCase("true")]
+ public void GrpcEnabledFourOutputs(string grpc)
+ {
+ var item = Utils.MakeItem("foo.proto", "grpcservices", grpc);
+ var poss = _generator.GetPossibleOutputs(item);
+ Assert.AreEqual(4, poss.Length);
+ Assert.Contains("foo.pb.cc", poss);
+ Assert.Contains("foo.pb.h", poss);
+ Assert.Contains("foo_grpc.pb.cc", poss);
+ Assert.Contains("foo_grpc.pb.h", poss);
+ }
+
+ [Test]
+ public void OutputDirMetadataRecognized()
+ {
+ var item = Utils.MakeItem("foo.proto", "OutputDir", "out");
+ var poss = _generator.GetPossibleOutputs(item);
+ Assert.AreEqual(2, poss.Length);
+ Assert.That(Path.GetDirectoryName(poss[0]), Is.EqualTo("out"));
+ }
+ };
+}
diff --git a/src/csharp/Grpc.Tools.Tests/DepFileUtilTest.cs b/src/csharp/Grpc.Tools.Tests/DepFileUtilTest.cs
new file mode 100644
index 0000000000..e89a8f4b5d
--- /dev/null
+++ b/src/csharp/Grpc.Tools.Tests/DepFileUtilTest.cs
@@ -0,0 +1,146 @@
+#region Copyright notice and license
+
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System.IO;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+using NUnit.Framework;
+
+namespace Grpc.Tools.Tests
+{
+ public class DepFileUtilTest
+ {
+
+ [Test]
+ public void HashString64Hex_IsSane()
+ {
+ string hashFoo1 = DepFileUtil.HashString64Hex("foo");
+ string hashEmpty = DepFileUtil.HashString64Hex("");
+ string hashFoo2 = DepFileUtil.HashString64Hex("foo");
+
+ StringAssert.IsMatch("^[a-f0-9]{16}$", hashFoo1);
+ Assert.AreEqual(hashFoo1, hashFoo2);
+ Assert.AreNotEqual(hashFoo1, hashEmpty);
+ }
+
+ [Test]
+ public void GetDepFilenameForProto_IsSane()
+ {
+ StringAssert.IsMatch(@"^out[\\/][a-f0-9]{16}_foo.protodep$",
+ DepFileUtil.GetDepFilenameForProto("out", "foo.proto"));
+ StringAssert.IsMatch(@"^[a-f0-9]{16}_foo.protodep$",
+ DepFileUtil.GetDepFilenameForProto("", "foo.proto"));
+ }
+
+ [Test]
+ public void GetDepFilenameForProto_HashesDir()
+ {
+ string PickHash(string fname) =>
+ DepFileUtil.GetDepFilenameForProto("", fname).Substring(0, 16);
+
+ string same1 = PickHash("dir1/dir2/foo.proto");
+ string same2 = PickHash("dir1/dir2/proto.foo");
+ string same3 = PickHash("dir1/dir2/proto");
+ string same4 = PickHash("dir1/dir2/.proto");
+ string unsame1 = PickHash("dir2/foo.proto");
+ string unsame2 = PickHash("/dir2/foo.proto");
+
+ Assert.AreEqual(same1, same2);
+ Assert.AreEqual(same1, same3);
+ Assert.AreEqual(same1, same4);
+ Assert.AreNotEqual(same1, unsame1);
+ Assert.AreNotEqual(unsame1, unsame2);
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Full file reading tests
+
+ // Generated by protoc on Windows. Slashes vary.
+ const string depFile1 =
+ @"C:\projects\foo\src\./foo.grpc.pb.cc \
+C:\projects\foo\src\./foo.grpc.pb.h \
+C:\projects\foo\src\./foo.pb.cc \
+ C:\projects\foo\src\./foo.pb.h: C:/usr/include/google/protobuf/wrappers.proto\
+ C:/usr/include/google/protobuf/any.proto\
+C:/usr/include/google/protobuf/source_context.proto\
+ C:/usr/include/google/protobuf/type.proto\
+ foo.proto";
+
+ // This has a nasty output directory with a space.
+ const string depFile2 =
+ @"obj\Release x64\net45\/Foo.cs \
+obj\Release x64\net45\/FooGrpc.cs: C:/usr/include/google/protobuf/wrappers.proto\
+ C:/projects/foo/src//foo.proto";
+
+ [Test]
+ public void ReadDependencyInput_FullFile1()
+ {
+ string[] deps = ReadDependencyInputFromFileData(depFile1, "foo.proto");
+
+ Assert.NotNull(deps);
+ Assert.That(deps, Has.Length.InRange(4, 5)); // foo.proto may or may not be listed.
+ Assert.That(deps, Has.One.EndsWith("wrappers.proto"));
+ Assert.That(deps, Has.One.EndsWith("type.proto"));
+ Assert.That(deps, Has.None.StartWith(" "));
+ }
+
+ [Test]
+ public void ReadDependencyInput_FullFile2()
+ {
+ string[] deps = ReadDependencyInputFromFileData(depFile2, "C:/projects/foo/src/foo.proto");
+
+ Assert.NotNull(deps);
+ Assert.That(deps, Has.Length.InRange(1, 2));
+ Assert.That(deps, Has.One.EndsWith("wrappers.proto"));
+ Assert.That(deps, Has.None.StartWith(" "));
+ }
+
+ [Test]
+ public void ReadDependencyInput_FullFileUnparsable()
+ {
+ string[] deps = ReadDependencyInputFromFileData("a:/foo.proto", "/foo.proto");
+ Assert.NotNull(deps);
+ Assert.Zero(deps.Length);
+ }
+
+ // NB in our tests files are put into the temp directory but all have
+ // different names. Avoid adding files with the same directory path and
+ // name, or add reasonable handling for it if required. Tests are run in
+ // parallel and will collide otherwise.
+ private string[] ReadDependencyInputFromFileData(string fileData, string protoName)
+ {
+ string tempPath = Path.GetTempPath();
+ string tempfile = DepFileUtil.GetDepFilenameForProto(tempPath, protoName);
+ try
+ {
+ File.WriteAllText(tempfile, fileData);
+ var mockEng = new Moq.Mock<IBuildEngine>();
+ var log = new TaskLoggingHelper(mockEng.Object, "x");
+ return DepFileUtil.ReadDependencyInputs(tempPath, protoName, log);
+ }
+ finally
+ {
+ try
+ {
+ File.Delete(tempfile);
+ }
+ catch { }
+ }
+ }
+ };
+}
diff --git a/src/csharp/Grpc.Tools.Tests/GeneratorTest.cs b/src/csharp/Grpc.Tools.Tests/GeneratorTest.cs
new file mode 100644
index 0000000000..8a8fc81aba
--- /dev/null
+++ b/src/csharp/Grpc.Tools.Tests/GeneratorTest.cs
@@ -0,0 +1,55 @@
+#region Copyright notice and license
+
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+using Moq;
+using NUnit.Framework;
+
+namespace Grpc.Tools.Tests
+{
+ public class GeneratorTest
+ {
+ protected Mock<IBuildEngine> _mockEngine;
+ protected TaskLoggingHelper _log;
+
+ [SetUp]
+ public void SetUp()
+ {
+ _mockEngine = new Mock<IBuildEngine>();
+ _log = new TaskLoggingHelper(_mockEngine.Object, "dummy");
+ }
+
+ [TestCase("csharp")]
+ [TestCase("CSharp")]
+ [TestCase("cpp")]
+ public void ValidLanguages(string lang)
+ {
+ Assert.IsNotNull(GeneratorServices.GetForLanguage(lang, _log));
+ _mockEngine.Verify(me => me.LogErrorEvent(It.IsAny<BuildErrorEventArgs>()), Times.Never);
+ }
+
+ [TestCase("")]
+ [TestCase("COBOL")]
+ public void InvalidLanguages(string lang)
+ {
+ Assert.IsNull(GeneratorServices.GetForLanguage(lang, _log));
+ _mockEngine.Verify(me => me.LogErrorEvent(It.IsAny<BuildErrorEventArgs>()), Times.Once);
+ }
+ };
+}
diff --git a/src/csharp/Grpc.Tools.Tests/Grpc.Tools.Tests.csproj b/src/csharp/Grpc.Tools.Tests/Grpc.Tools.Tests.csproj
new file mode 100644
index 0000000000..a2d4874eec
--- /dev/null
+++ b/src/csharp/Grpc.Tools.Tests/Grpc.Tools.Tests.csproj
@@ -0,0 +1,78 @@
+<Project Sdk="Microsoft.NET.Sdk" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+
+ <Import Project="..\Grpc.Core\Version.csproj.include" />
+
+ <PropertyGroup>
+ <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
+ <OutputType>Exe</OutputType>
+ </PropertyGroup>
+
+ <Import Project="..\Grpc.Core\SourceLink.csproj.include" />
+
+ <!-- This is copied verbatim from Grpc.Core/Common.csproj.include. Other settings
+ in that file conflict with the intent of this build, as it cannot be signed,
+ and may not compile Grpc.Core/Version.cs, as that file references constants
+ in Grpc.Core.dll.
+ TODO(kkm): Refactor imports. -->
+ <PropertyGroup Condition=" '$(OS)' != 'Windows_NT' and '$(MSBuildRuntimeType)' == 'Core' ">
+ <!-- Use Mono reference assemblies in SDK build: https://github.com/dotnet/sdk/issues/335 -->
+ <FrameworkPathOverride Condition="Exists('/usr/lib/mono/4.5-api')">/usr/lib/mono/4.5-api</FrameworkPathOverride>
+ <FrameworkPathOverride Condition="Exists('/usr/local/lib/mono/4.5-api')">/usr/local/lib/mono/4.5-api</FrameworkPathOverride>
+ <FrameworkPathOverride Condition="Exists('/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/4.5-api')">/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/4.5-api</FrameworkPathOverride>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="..\Grpc.Tools\Grpc.Tools.csproj" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <PackageReference Include="Moq" Version="4.8.3" />
+ <PackageReference Include="NUnit; NUnitLite" Version="3.10.1" />
+ <PackageReference Include="System.Runtime.InteropServices.RuntimeInformation" Version="4.3.0" />
+ </ItemGroup>
+
+ <PropertyGroup Condition=" '$(TargetFramework)' != 'net45' ">
+ <DefineConstants>$(DefineConstants);NETCORE</DefineConstants>
+ </PropertyGroup>
+
+ <ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
+ <Reference Include="Microsoft.Build.Framework; Microsoft.Build.Utilities.v4.0" />
+ </ItemGroup>
+
+ <ItemGroup Condition=" '$(TargetFramework)' != 'net45' ">
+ <PackageReference Include="Microsoft.Build.Framework; Microsoft.Build.Utilities.Core" Version="15.6.*" />
+ </ItemGroup>
+
+ <!-- Groups below is a hack to allow the test to run under Mono Framework build.
+ ========================================================================== -->
+
+ <!-- Mono unfortunately comes with broken Microsoft.Build.* assemblies installed in
+ the GAC, but fortunately searches for runtime assemblies in a different order
+ than Windows CLR host: the GAC assemblies have the lowest search priority, (see
+ https://www.mono-project.com/docs/advanced/assemblies-and-the-gac/), not the
+ highest as is in Windows (documented at
+ https://docs.microsoft.com/dotnet/framework/deployment/how-the-runtime-locates-assemblies).
+ To run the tests under Mono, we need correct assemblies in the same directory as
+ the test executable. Correct versions are in the MSBuild directory under Mono. -->
+ <ItemGroup Condition=" '$(TargetFramework)' == 'net45' and '$(OS)' != 'Windows_NT' ">
+ <None Include="$(_MSBuildAssemblyPath)/Microsoft.Build.Framework.dll;
+ $(_MSBuildAssemblyPath)/Microsoft.Build.Utilities.v4.0.dll;
+ $(_MSBuildAssemblyPath)/Microsoft.Build.Utilities.Core.dll"
+ CopyToOutputDirectory="Always" Visible="false" />
+ </ItemGroup>
+ <PropertyGroup Condition=" '$(TargetFramework)' == 'net45' and '$(OS)' != 'Windows_NT' ">
+ <!-- The None items are included into assembly candidate resolution by default, and
+ we do not want that, as they are not valid as reference assemblies (the version of
+ Microsoft.Build.Utilities.v4.0 is a pure facade for Microsoft.Build.Utilities.Core,
+ and does not define any types at all). Exclude them from assembly resolution. See
+ https://github.com/Microsoft/msbuild/blob/50639058f/documentation/wiki/ResolveAssemblyReference.md -->
+ <AssemblySearchPaths>{HintPathFromItem};{TargetFrameworkDirectory};{RawFileName}</AssemblySearchPaths>
+ <!-- Mono knows better where its MSBuild is. -->
+ <_MSBuildAssemblyPath Condition=" '$(MSBuildRuntimeType)' != 'Core' "
+ >$(MSBuildToolsPath)</_MSBuildAssemblyPath>
+ <!-- Under dotnet, make the best guess we can. -->
+ <_MSBuildAssemblyPath Condition=" '$(MSBuildRuntimeType)' == 'Core' "
+ >$(FrameworkPathOverride)/../msbuild/$(MSBuildToolsVersion)/bin</_MSBuildAssemblyPath>
+ </PropertyGroup>
+
+</Project>
diff --git a/src/csharp/Grpc.Tools.Tests/NUnitMain.cs b/src/csharp/Grpc.Tools.Tests/NUnitMain.cs
new file mode 100644
index 0000000000..418c33820e
--- /dev/null
+++ b/src/csharp/Grpc.Tools.Tests/NUnitMain.cs
@@ -0,0 +1,33 @@
+#region Copyright notice and license
+
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System.Reflection;
+using NUnitLite;
+
+namespace Grpc.Tools.Tests
+{
+ static class NUnitMain
+ {
+ public static int Main(string[] args) =>
+#if NETCOREAPP1_0 || NETCOREAPP1_1
+ new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args);
+#else
+ new AutoRun().Execute(args);
+#endif
+ };
+}
diff --git a/src/csharp/Grpc.Tools.Tests/ProtoCompileBasicTest.cs b/src/csharp/Grpc.Tools.Tests/ProtoCompileBasicTest.cs
new file mode 100644
index 0000000000..ea763f4e40
--- /dev/null
+++ b/src/csharp/Grpc.Tools.Tests/ProtoCompileBasicTest.cs
@@ -0,0 +1,76 @@
+#region Copyright notice and license
+
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System.Reflection; // UWYU: Object.GetType() extension.
+using Microsoft.Build.Framework;
+using Moq;
+using NUnit.Framework;
+
+namespace Grpc.Tools.Tests
+{
+ public class ProtoCompileBasicTest
+ {
+ // Mock task class that stops right before invoking protoc.
+ public class ProtoCompileTestable : ProtoCompile
+ {
+ public string LastPathToTool { get; private set; }
+ public string[] LastResponseFile { get; private set; }
+
+ protected override int ExecuteTool(string pathToTool,
+ string response,
+ string commandLine)
+ {
+ // We should never be using command line commands.
+ Assert.That(commandLine, Is.Null | Is.Empty);
+
+ // Must receive a path to tool
+ Assert.That(pathToTool, Is.Not.Null & Is.Not.Empty);
+ Assert.That(response, Is.Not.Null & Does.EndWith("\n"));
+
+ LastPathToTool = pathToTool;
+ LastResponseFile = response.Remove(response.Length - 1).Split('\n');
+
+ // Do not run the tool, but pretend it ran successfully.
+ return 0;
+ }
+ };
+
+ protected Mock<IBuildEngine> _mockEngine;
+ protected ProtoCompileTestable _task;
+
+ [SetUp]
+ public void SetUp()
+ {
+ _mockEngine = new Mock<IBuildEngine>();
+ _task = new ProtoCompileTestable {
+ BuildEngine = _mockEngine.Object
+ };
+ }
+
+ [TestCase("ProtoBuf")]
+ [TestCase("Generator")]
+ [TestCase("OutputDir")]
+ [Description("We trust MSBuild to initialize these properties.")]
+ public void RequiredAttributePresentOnProperty(string prop)
+ {
+ var pinfo = _task.GetType()?.GetProperty(prop);
+ Assert.NotNull(pinfo);
+ Assert.That(pinfo, Has.Attribute<RequiredAttribute>());
+ }
+ };
+}
diff --git a/src/csharp/Grpc.Tools.Tests/ProtoCompileCommandLineGeneratorTest.cs b/src/csharp/Grpc.Tools.Tests/ProtoCompileCommandLineGeneratorTest.cs
new file mode 100644
index 0000000000..cac7146634
--- /dev/null
+++ b/src/csharp/Grpc.Tools.Tests/ProtoCompileCommandLineGeneratorTest.cs
@@ -0,0 +1,179 @@
+#region Copyright notice and license
+
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System.IO;
+using Microsoft.Build.Framework;
+using Moq;
+using NUnit.Framework;
+
+namespace Grpc.Tools.Tests
+{
+ public class ProtoCompileCommandLineGeneratorTest : ProtoCompileBasicTest
+ {
+ [SetUp]
+ public new void SetUp()
+ {
+ _task.Generator = "csharp";
+ _task.OutputDir = "outdir";
+ _task.ProtoBuf = Utils.MakeSimpleItems("a.proto");
+ }
+
+ void ExecuteExpectSuccess()
+ {
+ _mockEngine
+ .Setup(me => me.LogErrorEvent(It.IsAny<BuildErrorEventArgs>()))
+ .Callback((BuildErrorEventArgs e) =>
+ Assert.Fail($"Error logged by build engine:\n{e.Message}"));
+ bool result = _task.Execute();
+ Assert.IsTrue(result);
+ }
+
+ [Test]
+ public void MinimalCompile()
+ {
+ ExecuteExpectSuccess();
+ Assert.That(_task.LastPathToTool, Does.Match(@"protoc(.exe)?$"));
+ Assert.That(_task.LastResponseFile, Is.EqualTo(new[] {
+ "--csharp_out=outdir", "a.proto" }));
+ }
+
+ [Test]
+ public void CompileTwoFiles()
+ {
+ _task.ProtoBuf = Utils.MakeSimpleItems("a.proto", "foo/b.proto");
+ ExecuteExpectSuccess();
+ Assert.That(_task.LastResponseFile, Is.EqualTo(new[] {
+ "--csharp_out=outdir", "a.proto", "foo/b.proto" }));
+ }
+
+ [Test]
+ public void CompileWithProtoPaths()
+ {
+ _task.ProtoPath = new[] { "/path1", "/path2" };
+ ExecuteExpectSuccess();
+ Assert.That(_task.LastResponseFile, Is.EqualTo(new[] {
+ "--csharp_out=outdir", "--proto_path=/path1",
+ "--proto_path=/path2", "a.proto" }));
+ }
+
+ [TestCase("Cpp")]
+ [TestCase("CSharp")]
+ [TestCase("Java")]
+ [TestCase("Javanano")]
+ [TestCase("Js")]
+ [TestCase("Objc")]
+ [TestCase("Php")]
+ [TestCase("Python")]
+ [TestCase("Ruby")]
+ public void CompileWithOptions(string gen)
+ {
+ _task.Generator = gen;
+ _task.OutputOptions = new[] { "foo", "bar" };
+ ExecuteExpectSuccess();
+ gen = gen.ToLowerInvariant();
+ Assert.That(_task.LastResponseFile, Is.EqualTo(new[] {
+ $"--{gen}_out=outdir", $"--{gen}_opt=foo,bar", "a.proto" }));
+ }
+
+ [Test]
+ public void OutputDependencyFile()
+ {
+ _task.DependencyOut = "foo/my.protodep";
+ // Task fails trying to read the non-generated file; we ignore that.
+ _task.Execute();
+ Assert.That(_task.LastResponseFile,
+ Does.Contain("--dependency_out=foo/my.protodep"));
+ }
+
+ [Test]
+ public void OutputDependencyWithProtoDepDir()
+ {
+ _task.ProtoDepDir = "foo";
+ // Task fails trying to read the non-generated file; we ignore that.
+ _task.Execute();
+ Assert.That(_task.LastResponseFile,
+ Has.One.Match(@"^--dependency_out=foo[/\\].+_a.protodep$"));
+ }
+
+ [Test]
+ public void GenerateGrpc()
+ {
+ _task.GrpcPluginExe = "/foo/grpcgen";
+ ExecuteExpectSuccess();
+ Assert.That(_task.LastResponseFile, Is.SupersetOf(new[] {
+ "--csharp_out=outdir", "--grpc_out=outdir",
+ "--plugin=protoc-gen-grpc=/foo/grpcgen" }));
+ }
+
+ [Test]
+ public void GenerateGrpcWithOutDir()
+ {
+ _task.GrpcPluginExe = "/foo/grpcgen";
+ _task.GrpcOutputDir = "gen-out";
+ ExecuteExpectSuccess();
+ Assert.That(_task.LastResponseFile, Is.SupersetOf(new[] {
+ "--csharp_out=outdir", "--grpc_out=gen-out" }));
+ }
+
+ [Test]
+ public void GenerateGrpcWithOptions()
+ {
+ _task.GrpcPluginExe = "/foo/grpcgen";
+ _task.GrpcOutputOptions = new[] { "baz", "quux" };
+ ExecuteExpectSuccess();
+ Assert.That(_task.LastResponseFile,
+ Does.Contain("--grpc_opt=baz,quux"));
+ }
+
+ [Test]
+ public void DirectoryArgumentsSlashTrimmed()
+ {
+ _task.GrpcPluginExe = "/foo/grpcgen";
+ _task.GrpcOutputDir = "gen-out/";
+ _task.OutputDir = "outdir/";
+ _task.ProtoPath = new[] { "/path1/", "/path2/" };
+ ExecuteExpectSuccess();
+ Assert.That(_task.LastResponseFile, Is.SupersetOf(new[] {
+ "--proto_path=/path1", "--proto_path=/path2",
+ "--csharp_out=outdir", "--grpc_out=gen-out" }));
+ }
+
+ [TestCase(".", ".")]
+ [TestCase("/", "/")]
+ [TestCase("//", "/")]
+ [TestCase("/foo/", "/foo")]
+ [TestCase("/foo", "/foo")]
+ [TestCase("foo/", "foo")]
+ [TestCase("foo//", "foo")]
+ [TestCase("foo/\\", "foo")]
+ [TestCase("foo\\/", "foo")]
+ [TestCase("C:\\foo", "C:\\foo")]
+ [TestCase("C:", "C:")]
+ [TestCase("C:\\", "C:\\")]
+ [TestCase("C:\\\\", "C:\\")]
+ public void DirectorySlashTrimmingCases(string given, string expect)
+ {
+ if (Path.DirectorySeparatorChar == '/')
+ expect = expect.Replace('\\', '/');
+ _task.OutputDir = given;
+ ExecuteExpectSuccess();
+ Assert.That(_task.LastResponseFile,
+ Does.Contain("--csharp_out=" + expect));
+ }
+ };
+}
diff --git a/src/csharp/Grpc.Tools.Tests/ProtoCompileCommandLinePrinterTest.cs b/src/csharp/Grpc.Tools.Tests/ProtoCompileCommandLinePrinterTest.cs
new file mode 100644
index 0000000000..1773dcb875
--- /dev/null
+++ b/src/csharp/Grpc.Tools.Tests/ProtoCompileCommandLinePrinterTest.cs
@@ -0,0 +1,51 @@
+#region Copyright notice and license
+
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using Microsoft.Build.Framework;
+using Moq;
+using NUnit.Framework;
+
+namespace Grpc.Tools.Tests
+{
+ public class ProtoCompileCommandLinePrinterTest : ProtoCompileBasicTest
+ {
+ [SetUp]
+ public new void SetUp()
+ {
+ _task.Generator = "csharp";
+ _task.OutputDir = "outdir";
+ _task.ProtoBuf = Utils.MakeSimpleItems("a.proto");
+
+ _mockEngine
+ .Setup(me => me.LogMessageEvent(It.IsAny<BuildMessageEventArgs>()))
+ .Callback((BuildMessageEventArgs e) =>
+ Assert.Fail($"Error logged by build engine:\n{e.Message}"))
+ .Verifiable("Command line was not output by the task.");
+ }
+
+ void ExecuteExpectSuccess()
+ {
+ _mockEngine
+ .Setup(me => me.LogErrorEvent(It.IsAny<BuildErrorEventArgs>()))
+ .Callback((BuildErrorEventArgs e) =>
+ Assert.Fail($"Error logged by build engine:\n{e.Message}"));
+ bool result = _task.Execute();
+ Assert.IsTrue(result);
+ }
+ };
+}
diff --git a/src/csharp/Grpc.Tools.Tests/ProtoToolsPlatformTaskTest.cs b/src/csharp/Grpc.Tools.Tests/ProtoToolsPlatformTaskTest.cs
new file mode 100644
index 0000000000..54723b74fc
--- /dev/null
+++ b/src/csharp/Grpc.Tools.Tests/ProtoToolsPlatformTaskTest.cs
@@ -0,0 +1,139 @@
+#region Copyright notice and license
+
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System.Runtime.InteropServices; // For NETCORE tests.
+using Microsoft.Build.Framework;
+using Moq;
+using NUnit.Framework;
+
+namespace Grpc.Tools.Tests
+{
+ public class ProtoToolsPlatformTaskTest
+ {
+ ProtoToolsPlatform _task;
+ int _cpuMatched, _osMatched;
+
+ [OneTimeSetUp]
+ public void SetUp()
+ {
+ var mockEng = new Mock<IBuildEngine>();
+ _task = new ProtoToolsPlatform() { BuildEngine = mockEng.Object };
+ _task.Execute();
+ }
+
+ [OneTimeTearDown]
+ public void TearDown()
+ {
+ Assert.AreEqual(1, _cpuMatched, "CPU type detection failed");
+ Assert.AreEqual(1, _osMatched, "OS detection failed");
+ }
+
+#if NETCORE
+ // PlatformAttribute not yet available in NUnit, coming soon:
+ // https://github.com/nunit/nunit/pull/3003.
+ // Use same test case names as under the full framework.
+ [Test]
+ public void CpuIsX86()
+ {
+ if (RuntimeInformation.OSArchitecture == Architecture.X86)
+ {
+ _cpuMatched++;
+ Assert.AreEqual("x86", _task.Cpu);
+ }
+ }
+
+ [Test]
+ public void CpuIsX64()
+ {
+ if (RuntimeInformation.OSArchitecture == Architecture.X64)
+ {
+ _cpuMatched++;
+ Assert.AreEqual("x64", _task.Cpu);
+ }
+ }
+
+ [Test]
+ public void OsIsWindows()
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ _osMatched++;
+ Assert.AreEqual("windows", _task.Os);
+ }
+ }
+
+ [Test]
+ public void OsIsLinux()
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ {
+ _osMatched++;
+ Assert.AreEqual("linux", _task.Os);
+ }
+ }
+
+ [Test]
+ public void OsIsMacOsX()
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ {
+ _osMatched++;
+ Assert.AreEqual("macosx", _task.Os);
+ }
+ }
+
+#else // !NETCORE, i.e. full framework.
+
+ [Test, Platform("32-Bit")]
+ public void CpuIsX86()
+ {
+ _cpuMatched++;
+ Assert.AreEqual("x86", _task.Cpu);
+ }
+
+ [Test, Platform("64-Bit")]
+ public void CpuIsX64()
+ {
+ _cpuMatched++;
+ Assert.AreEqual("x64", _task.Cpu);
+ }
+
+ [Test, Platform("Win")]
+ public void OsIsWindows()
+ {
+ _osMatched++;
+ Assert.AreEqual("windows", _task.Os);
+ }
+
+ [Test, Platform("Linux")]
+ public void OsIsLinux()
+ {
+ _osMatched++;
+ Assert.AreEqual("linux", _task.Os);
+ }
+
+ [Test, Platform("MacOSX")]
+ public void OsIsMacOsX()
+ {
+ _osMatched++;
+ Assert.AreEqual("macosx", _task.Os);
+ }
+
+#endif // NETCORE
+ };
+}
diff --git a/src/csharp/Grpc.Tools.Tests/Utils.cs b/src/csharp/Grpc.Tools.Tests/Utils.cs
new file mode 100644
index 0000000000..6e0f1cffd5
--- /dev/null
+++ b/src/csharp/Grpc.Tools.Tests/Utils.cs
@@ -0,0 +1,46 @@
+#region Copyright notice and license
+
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System.Linq;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+namespace Grpc.Tools.Tests
+{
+ static class Utils
+ {
+ // Build an item with a name from args[0] and metadata key-value pairs
+ // from the rest of args, interleaved.
+ // This does not do any checking, and expects an odd number of args.
+ public static ITaskItem MakeItem(params string[] args)
+ {
+ var item = new TaskItem(args[0]);
+ for (int i = 1; i < args.Length; i += 2)
+ {
+ item.SetMetadata(args[i], args[i + 1]);
+ }
+ return item;
+ }
+
+ // Return an array of items from given itemspecs.
+ public static ITaskItem[] MakeSimpleItems(params string[] specs)
+ {
+ return specs.Select(s => new TaskItem(s)).ToArray();
+ }
+ };
+}
diff --git a/src/csharp/Grpc.Tools.nuspec b/src/csharp/Grpc.Tools.nuspec
deleted file mode 100644
index 0cae5572fd..0000000000
--- a/src/csharp/Grpc.Tools.nuspec
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<package>
- <metadata>
- <id>Grpc.Tools</id>
- <title>gRPC C# Tools</title>
- <summary>Tools for C# implementation of gRPC - an RPC library and framework</summary>
- <description>Precompiled protobuf compiler and gRPC protobuf compiler plugin for generating gRPC client/server C# code. Binaries are available for Windows, Linux and MacOS.</description>
- <version>$version$</version>
- <authors>Google Inc.</authors>
- <owners>grpc-packages</owners>
- <licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
- <projectUrl>https://github.com/grpc/grpc</projectUrl>
- <requireLicenseAcceptance>false</requireLicenseAcceptance>
- <releaseNotes>Release $version$</releaseNotes>
- <copyright>Copyright 2015, Google Inc.</copyright>
- <tags>gRPC RPC Protocol HTTP/2</tags>
- </metadata>
- <files>
- <!-- forward slashes in src path enable building on Linux -->
- <file src="protoc_plugins/protoc_windows_x86/protoc.exe" target="tools/windows_x86/protoc.exe" />
- <file src="protoc_plugins/protoc_windows_x86/grpc_csharp_plugin.exe" target="tools/windows_x86/grpc_csharp_plugin.exe" />
- <file src="protoc_plugins/protoc_windows_x64/protoc.exe" target="tools/windows_x64/protoc.exe" />
- <file src="protoc_plugins/protoc_windows_x64/grpc_csharp_plugin.exe" target="tools/windows_x64/grpc_csharp_plugin.exe" />
- <file src="protoc_plugins/protoc_linux_x86/protoc" target="tools/linux_x86/protoc" />
- <file src="protoc_plugins/protoc_linux_x86/grpc_csharp_plugin" target="tools/linux_x86/grpc_csharp_plugin" />
- <file src="protoc_plugins/protoc_linux_x64/protoc" target="tools/linux_x64/protoc" />
- <file src="protoc_plugins/protoc_linux_x64/grpc_csharp_plugin" target="tools/linux_x64/grpc_csharp_plugin" />
- <file src="protoc_plugins/protoc_macos_x86/protoc" target="tools/macosx_x86/protoc" />
- <file src="protoc_plugins/protoc_macos_x86/grpc_csharp_plugin" target="tools/macosx_x86/grpc_csharp_plugin" />
- <file src="protoc_plugins/protoc_macos_x64/protoc" target="tools/macosx_x64/protoc" />
- <file src="protoc_plugins/protoc_macos_x64/grpc_csharp_plugin" target="tools/macosx_x64/grpc_csharp_plugin" />
- </files>
-</package>
diff --git a/src/csharp/Grpc.Tools/Common.cs b/src/csharp/Grpc.Tools/Common.cs
new file mode 100644
index 0000000000..e6acdd6393
--- /dev/null
+++ b/src/csharp/Grpc.Tools/Common.cs
@@ -0,0 +1,114 @@
+#region Copyright notice and license
+
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System;
+using System.IO;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Security;
+
+[assembly: InternalsVisibleTo("Grpc.Tools.Tests")]
+
+namespace Grpc.Tools
+{
+ // Metadata names (MSBuild item attributes) that we refer to often.
+ static class Metadata
+ {
+ // On output dependency lists.
+ public static string Source = "Source";
+ // On ProtoBuf items.
+ public static string ProtoRoot = "ProtoRoot";
+ public static string OutputDir = "OutputDir";
+ public static string GrpcServices = "GrpcServices";
+ public static string GrpcOutputDir = "GrpcOutputDir";
+ };
+
+ // A few flags used to control the behavior under various platforms.
+ internal static class Platform
+ {
+ public enum OsKind { Unknown, Windows, Linux, MacOsX };
+ public static readonly OsKind Os;
+
+ public enum CpuKind { Unknown, X86, X64 };
+ public static readonly CpuKind Cpu;
+
+ // This is not necessarily true, but good enough. BCL lacks a per-FS
+ // API to determine file case sensitivity.
+ public static bool IsFsCaseInsensitive => Os == OsKind.Windows;
+ public static bool IsWindows => Os == OsKind.Windows;
+
+ static Platform()
+ {
+#if NETCORE
+ Os = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? OsKind.Windows
+ : RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? OsKind.Linux
+ : RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? OsKind.MacOsX
+ : OsKind.Unknown;
+
+ switch (RuntimeInformation.OSArchitecture)
+ {
+ case Architecture.X86: Cpu = CpuKind.X86; break;
+ case Architecture.X64: Cpu = CpuKind.X64; break;
+ // We do not have build tools for other architectures.
+ default: Cpu = CpuKind.Unknown; break;
+ }
+#else
+ // Running under either Mono or full MS framework.
+ Os = OsKind.Windows;
+ if (Type.GetType("Mono.Runtime", throwOnError: false) != null)
+ {
+ // Congratulations. We are running under Mono.
+ var plat = Environment.OSVersion.Platform;
+ if (plat == PlatformID.MacOSX)
+ {
+ Os = OsKind.MacOsX;
+ }
+ else if (plat == PlatformID.Unix || (int)plat == 128)
+ {
+ // This is how Mono detects OSX internally.
+ Os = File.Exists("/usr/lib/libc.dylib") ? OsKind.MacOsX : OsKind.Linux;
+ }
+ }
+
+ // Hope we are not building on ARM under Xamarin!
+ Cpu = Environment.Is64BitOperatingSystem ? CpuKind.X64 : CpuKind.X86;
+#endif
+ }
+ };
+
+ // Exception handling helpers.
+ static class Exceptions
+ {
+ // Returns true iff the exception indicates an error from an I/O call. See
+ // https://github.com/Microsoft/msbuild/blob/v15.4.8.50001/src/Shared/ExceptionHandling.cs#L101
+ static public bool IsIoRelated(Exception ex) =>
+ ex is IOException ||
+ (ex is ArgumentException && !(ex is ArgumentNullException)) ||
+ ex is SecurityException ||
+ ex is UnauthorizedAccessException ||
+ ex is NotSupportedException;
+ };
+
+ // String helpers.
+ static class Strings
+ {
+ // Compare string to argument using OrdinalIgnoreCase comparison.
+ public static bool EqualNoCase(this string a, string b) =>
+ string.Equals(a, b, StringComparison.OrdinalIgnoreCase);
+ }
+}
diff --git a/src/csharp/Grpc.Tools/DepFileUtil.cs b/src/csharp/Grpc.Tools/DepFileUtil.cs
new file mode 100644
index 0000000000..440d3d535c
--- /dev/null
+++ b/src/csharp/Grpc.Tools/DepFileUtil.cs
@@ -0,0 +1,273 @@
+#region Copyright notice and license
+
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+namespace Grpc.Tools
+{
+ internal static class DepFileUtil
+ {
+ /*
+ Sample dependency files. Notable features we have to deal with:
+ * Slash doubling, must normalize them.
+ * Spaces in file names. Cannot just "unwrap" the line on backslash at eof;
+ rather, treat every line as containing one file name except for one with
+ the ':' separator, as containing exactly two.
+ * Deal with ':' also being drive letter separator (second example).
+
+ obj\Release\net45\/Foo.cs \
+ obj\Release\net45\/FooGrpc.cs: C:/foo/include/google/protobuf/wrappers.proto\
+ C:/projects/foo/src//foo.proto
+
+ C:\projects\foo\src\./foo.grpc.pb.cc \
+ C:\projects\foo\src\./foo.grpc.pb.h \
+ C:\projects\foo\src\./foo.pb.cc \
+ C:\projects\foo\src\./foo.pb.h: C:/foo/include/google/protobuf/wrappers.proto\
+ C:/foo/include/google/protobuf/any.proto\
+ C:/foo/include/google/protobuf/source_context.proto\
+ C:/foo/include/google/protobuf/type.proto\
+ foo.proto
+ */
+
+ /// <summary>
+ /// Read file names from the dependency file to the right of ':'
+ /// </summary>
+ /// <param name="protoDepDir">Relative path to the dependency cache, e. g. "out"</param>
+ /// <param name="proto">Relative path to the proto item, e. g. "foo/file.proto"</param>
+ /// <param name="log">A <see cref="TaskLoggingHelper"/> for logging</param>
+ /// <returns>
+ /// Array of the proto file <b>input</b> dependencies as written by protoc, or empty
+ /// array if the dependency file does not exist or cannot be parsed.
+ /// </returns>
+ public static string[] ReadDependencyInputs(string protoDepDir, string proto,
+ TaskLoggingHelper log)
+ {
+ string depFilename = GetDepFilenameForProto(protoDepDir, proto);
+ string[] lines = ReadDepFileLines(depFilename, false, log);
+ if (lines.Length == 0)
+ {
+ return lines;
+ }
+
+ var result = new List<string>();
+ bool skip = true;
+ foreach (string line in lines)
+ {
+ // Start at the only line separating dependency outputs from inputs.
+ int ix = skip ? FindLineSeparator(line) : -1;
+ skip = skip && ix < 0;
+ if (skip) { continue; }
+ string file = ExtractFilenameFromLine(line, ix + 1, line.Length);
+ if (file == "")
+ {
+ log.LogMessage(MessageImportance.Low,
+ $"Skipping unparsable dependency file {depFilename}.\nLine with error: '{line}'");
+ return new string[0];
+ }
+
+ // Do not bend over backwards trying not to include a proto into its
+ // own list of dependencies. Since a file is not older than self,
+ // it is safe to add; this is purely a memory optimization.
+ if (file != proto)
+ {
+ result.Add(file);
+ }
+ }
+ return result.ToArray();
+ }
+
+ /// <summary>
+ /// Read file names from the dependency file to the left of ':'
+ /// </summary>
+ /// <param name="depFilename">Path to dependency file written by protoc</param>
+ /// <param name="log">A <see cref="TaskLoggingHelper"/> for logging</param>
+ /// <returns>
+ /// Array of the protoc-generated outputs from the given dependency file
+ /// written by protoc, or empty array if the file does not exist or cannot
+ /// be parsed.
+ /// </returns>
+ /// <remarks>
+ /// Since this is called after a protoc invocation, an unparsable or missing
+ /// file causes an error-level message to be logged.
+ /// </remarks>
+ public static string[] ReadDependencyOutputs(string depFilename,
+ TaskLoggingHelper log)
+ {
+ string[] lines = ReadDepFileLines(depFilename, true, log);
+ if (lines.Length == 0)
+ {
+ return lines;
+ }
+
+ var result = new List<string>();
+ foreach (string line in lines)
+ {
+ int ix = FindLineSeparator(line);
+ string file = ExtractFilenameFromLine(line, 0, ix >= 0 ? ix : line.Length);
+ if (file == "")
+ {
+ log.LogError("Unable to parse generated dependency file {0}.\n" +
+ "Line with error: '{1}'", depFilename, line);
+ return new string[0];
+ }
+ result.Add(file);
+
+ // If this is the line with the separator, do not read further.
+ if (ix >= 0) { break; }
+ }
+ return result.ToArray();
+ }
+
+ /// <summary>
+ /// Construct relative dependency file name from directory hash and file name
+ /// </summary>
+ /// <param name="protoDepDir">Relative path to the dependency cache, e. g. "out"</param>
+ /// <param name="proto">Relative path to the proto item, e. g. "foo/file.proto"</param>
+ /// <returns>
+ /// Full relative path to the dependency file, e. g.
+ /// "out/deadbeef12345678_file.protodep"
+ /// </returns>
+ /// <remarks>
+ /// Since a project may contain proto files with the same filename but in different
+ /// directories, a unique filename for the dependency file is constructed based on the
+ /// proto file name both name and directory. The directory path can be arbitrary,
+ /// for example, it can be outside of the project, or an absolute path including
+ /// a drive letter, or a UNC network path. A name constructed from such a path by,
+ /// for example, replacing disallowed name characters with an underscore, may well
+ /// be over filesystem's allowed path length, since it will be located under the
+ /// project and solution directories, which are also some level deep from the root.
+ /// Instead of creating long and unwieldy names for these proto sources, we cache
+ /// the full path of the name without the filename, and append the filename to it,
+ /// as in e. g. "foo/file.proto" will yield the name "deadbeef12345678_file", where
+ /// "deadbeef12345678" is a presumed hash value of the string "foo/". This allows
+ /// the file names be short, unique (up to a hash collision), and still allowing
+ /// the user to guess their provenance.
+ /// </remarks>
+ public static string GetDepFilenameForProto(string protoDepDir, string proto)
+ {
+ string dirname = Path.GetDirectoryName(proto);
+ if (Platform.IsFsCaseInsensitive)
+ {
+ dirname = dirname.ToLowerInvariant();
+ }
+ string dirhash = HashString64Hex(dirname);
+ string filename = Path.GetFileNameWithoutExtension(proto);
+ return Path.Combine(protoDepDir, $"{dirhash}_{filename}.protodep");
+ }
+
+ // Get a 64-bit hash for a directory string. We treat it as if it were
+ // unique, since there are not so many distinct proto paths in a project.
+ // We take the first 64 bit of the string SHA1.
+ // Internal for tests access only.
+ internal static string HashString64Hex(string str)
+ {
+ using (var sha1 = System.Security.Cryptography.SHA1.Create())
+ {
+ byte[] hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(str));
+ var hashstr = new StringBuilder(16);
+ for (int i = 0; i < 8; i++)
+ {
+ hashstr.Append(hash[i].ToString("x2"));
+ }
+ return hashstr.ToString();
+ }
+ }
+
+ // Extract filename between 'beg' (inclusive) and 'end' (exclusive) from
+ // line 'line', skipping over trailing and leading whitespace, and, when
+ // 'end' is immediately past end of line 'line', also final '\' (used
+ // as a line continuation token in the dep file).
+ // Returns an empty string if the filename cannot be extracted.
+ static string ExtractFilenameFromLine(string line, int beg, int end)
+ {
+ while (beg < end && char.IsWhiteSpace(line[beg])) beg++;
+ if (beg < end && end == line.Length && line[end - 1] == '\\') end--;
+ while (beg < end && char.IsWhiteSpace(line[end - 1])) end--;
+ if (beg == end) return "";
+
+ string filename = line.Substring(beg, end - beg);
+ try
+ {
+ // Normalize file name.
+ return Path.Combine(Path.GetDirectoryName(filename), Path.GetFileName(filename));
+ }
+ catch (Exception ex) when (Exceptions.IsIoRelated(ex))
+ {
+ return "";
+ }
+ }
+
+ // Finds the index of the ':' separating dependency clauses in the line,
+ // not taking Windows drive spec into account. Returns the index of the
+ // separating ':', or -1 if no separator found.
+ static int FindLineSeparator(string line)
+ {
+ // Mind this case where the first ':' is not separator:
+ // C:\foo\bar\.pb.h: C:/protobuf/wrappers.proto\
+ int ix = line.IndexOf(':');
+ if (ix <= 0 || ix == line.Length - 1
+ || (line[ix + 1] != '/' && line[ix + 1] != '\\')
+ || !char.IsLetter(line[ix - 1]))
+ {
+ return ix; // Not a windows drive: no letter before ':', or no '\' after.
+ }
+ for (int j = ix - 1; --j >= 0;)
+ {
+ if (!char.IsWhiteSpace(line[j]))
+ {
+ return ix; // Not space or BOL only before "X:/".
+ }
+ }
+ return line.IndexOf(':', ix + 1);
+ }
+
+ // Read entire dependency file. The 'required' parameter controls error
+ // logging behavior in case the file not found. We require this file when
+ // compiling, but reading it is optional when computing dependencies.
+ static string[] ReadDepFileLines(string filename, bool required,
+ TaskLoggingHelper log)
+ {
+ try
+ {
+ var result = File.ReadAllLines(filename);
+ if (!required)
+ {
+ log.LogMessage(MessageImportance.Low, $"Using dependency file {filename}");
+ }
+ return result;
+ }
+ catch (Exception ex) when (Exceptions.IsIoRelated(ex))
+ {
+ if (required)
+ {
+ log.LogError($"Unable to load {filename}: {ex.GetType().Name}: {ex.Message}");
+ }
+ else
+ {
+ log.LogMessage(MessageImportance.Low, $"Skipping {filename}: {ex.Message}");
+ }
+ return new string[0];
+ }
+ }
+ };
+}
diff --git a/src/csharp/Grpc.Tools/GeneratorServices.cs b/src/csharp/Grpc.Tools/GeneratorServices.cs
new file mode 100644
index 0000000000..536ec43c83
--- /dev/null
+++ b/src/csharp/Grpc.Tools/GeneratorServices.cs
@@ -0,0 +1,194 @@
+#region Copyright notice and license
+
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System;
+using System.IO;
+using System.Text;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+namespace Grpc.Tools
+{
+ // Abstract class for language-specific analysis behavior, such
+ // as guessing the generated files the same way protoc does.
+ internal abstract class GeneratorServices
+ {
+ protected readonly TaskLoggingHelper Log;
+ protected GeneratorServices(TaskLoggingHelper log) { Log = log; }
+
+ // Obtain a service for the given language (csharp, cpp).
+ public static GeneratorServices GetForLanguage(string lang, TaskLoggingHelper log)
+ {
+ if (lang.EqualNoCase("csharp")) { return new CSharpGeneratorServices(log); }
+ if (lang.EqualNoCase("cpp")) { return new CppGeneratorServices(log); }
+
+ log.LogError("Invalid value '{0}' for task property 'Generator'. " +
+ "Supported generator languages: CSharp, Cpp.", lang);
+ return null;
+ }
+
+ // Guess whether item's metadata suggests gRPC stub generation.
+ // When "gRPCServices" is not defined, assume gRPC is not used.
+ // When defined, C# uses "none" to skip gRPC, C++ uses "false", so
+ // recognize both. Since the value is tightly coupled to the scripts,
+ // we do not try to validate the value; scripts take care of that.
+ // It is safe to assume that gRPC is requested for any other value.
+ protected bool GrpcOutputPossible(ITaskItem proto)
+ {
+ string gsm = proto.GetMetadata(Metadata.GrpcServices);
+ return !gsm.EqualNoCase("") && !gsm.EqualNoCase("none")
+ && !gsm.EqualNoCase("false");
+ }
+
+ public abstract string[] GetPossibleOutputs(ITaskItem proto);
+ };
+
+ // C# generator services.
+ internal class CSharpGeneratorServices : GeneratorServices
+ {
+ public CSharpGeneratorServices(TaskLoggingHelper log) : base(log) { }
+
+ public override string[] GetPossibleOutputs(ITaskItem protoItem)
+ {
+ bool doGrpc = GrpcOutputPossible(protoItem);
+ string filename = LowerUnderscoreToUpperCamel(
+ Path.GetFileNameWithoutExtension(protoItem.ItemSpec));
+
+ var outputs = new string[doGrpc ? 2 : 1];
+ string outdir = protoItem.GetMetadata(Metadata.OutputDir);
+ string fileStem = Path.Combine(outdir, filename);
+ outputs[0] = fileStem + ".cs";
+ if (doGrpc)
+ {
+ // Override outdir if kGrpcOutputDir present, default to proto output.
+ outdir = protoItem.GetMetadata(Metadata.GrpcOutputDir);
+ if (outdir != "")
+ {
+ fileStem = Path.Combine(outdir, filename);
+ }
+ outputs[1] = fileStem + "Grpc.cs";
+ }
+ return outputs;
+ }
+
+ string LowerUnderscoreToUpperCamel(string str)
+ {
+ // See src/compiler/generator_helpers.h:118
+ var result = new StringBuilder(str.Length, str.Length);
+ bool cap = true;
+ foreach (char c in str)
+ {
+ if (c == '_')
+ {
+ cap = true;
+ }
+ else if (cap)
+ {
+ result.Append(char.ToUpperInvariant(c));
+ cap = false;
+ }
+ else
+ {
+ result.Append(c);
+ }
+ }
+ return result.ToString();
+ }
+ };
+
+ // C++ generator services.
+ internal class CppGeneratorServices : GeneratorServices
+ {
+ public CppGeneratorServices(TaskLoggingHelper log) : base(log) { }
+
+ public override string[] GetPossibleOutputs(ITaskItem protoItem)
+ {
+ bool doGrpc = GrpcOutputPossible(protoItem);
+ string root = protoItem.GetMetadata(Metadata.ProtoRoot);
+ string proto = protoItem.ItemSpec;
+ string filename = Path.GetFileNameWithoutExtension(proto);
+ // E. g., ("foo/", "foo/bar/x.proto") => "bar"
+ string relative = GetRelativeDir(root, proto);
+
+ var outputs = new string[doGrpc ? 4 : 2];
+ string outdir = protoItem.GetMetadata(Metadata.OutputDir);
+ string fileStem = Path.Combine(outdir, relative, filename);
+ outputs[0] = fileStem + ".pb.cc";
+ outputs[1] = fileStem + ".pb.h";
+ if (doGrpc)
+ {
+ // Override outdir if kGrpcOutputDir present, default to proto output.
+ outdir = protoItem.GetMetadata(Metadata.GrpcOutputDir);
+ if (outdir != "")
+ {
+ fileStem = Path.Combine(outdir, relative, filename);
+ }
+ outputs[2] = fileStem + "_grpc.pb.cc";
+ outputs[3] = fileStem + "_grpc.pb.h";
+ }
+ return outputs;
+ }
+
+ // Calculate part of proto path relative to root. Protoc is very picky
+ // about them matching exactly, so can be we. Expect root be exact prefix
+ // to proto, minus some slash normalization.
+ string GetRelativeDir(string root, string proto)
+ {
+ string protoDir = Path.GetDirectoryName(proto);
+ string rootDir = EndWithSlash(Path.GetDirectoryName(EndWithSlash(root)));
+ if (rootDir == s_dotSlash)
+ {
+ // Special case, otherwise we can return "./" instead of "" below!
+ return protoDir;
+ }
+ if (Platform.IsFsCaseInsensitive)
+ {
+ protoDir = protoDir.ToLowerInvariant();
+ rootDir = rootDir.ToLowerInvariant();
+ }
+ protoDir = EndWithSlash(protoDir);
+ if (!protoDir.StartsWith(rootDir))
+ {
+ Log.LogWarning("ProtoBuf item '{0}' has the ProtoRoot metadata '{1}' " +
+ "which is not prefix to its path. Cannot compute relative path.",
+ proto, root);
+ return "";
+ }
+ return protoDir.Substring(rootDir.Length);
+ }
+
+ // './' or '.\', normalized per system.
+ static string s_dotSlash = "." + Path.DirectorySeparatorChar;
+
+ static string EndWithSlash(string str)
+ {
+ if (str == "")
+ {
+ return s_dotSlash;
+ }
+ else if (str[str.Length - 1] != '\\' && str[str.Length - 1] != '/')
+ {
+ return str + Path.DirectorySeparatorChar;
+ }
+ else
+ {
+ return str;
+ }
+ }
+ };
+}
diff --git a/src/csharp/Grpc.Tools/Grpc.Tools.csproj b/src/csharp/Grpc.Tools/Grpc.Tools.csproj
new file mode 100644
index 0000000000..61fa75a4ec
--- /dev/null
+++ b/src/csharp/Grpc.Tools/Grpc.Tools.csproj
@@ -0,0 +1,101 @@
+<Project Sdk="Microsoft.NET.Sdk" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+
+ <Import Project="..\Grpc.Core\Version.csproj.include" />
+
+ <PropertyGroup>
+ <AssemblyName>Protobuf.MSBuild</AssemblyName>
+ <Version>$(GrpcCsharpVersion)</Version>
+ <!-- If changing targets, change also paths in Google.Protobuf.Tools.targets. -->
+ <TargetFrameworks>net45;netstandard1.3</TargetFrameworks>
+ </PropertyGroup>
+
+ <!-- This is copied verbatim from Grpc.Core/Common.csproj.include. Other settings
+ in that file conflict with the intent of this build, as it cannot be signed,
+ and may not compile Grpc.Core/Version.cs, as that file references constants
+ in Grpc.Core.dll.
+ TODO(kkm): Refactor imports. -->
+ <PropertyGroup Condition=" '$(OS)' != 'Windows_NT' and '$(MSBuildRuntimeType)' == 'Core' ">
+ <!-- Use Mono reference assemblies in SDK build: https://github.com/dotnet/sdk/issues/335 -->
+ <FrameworkPathOverride Condition="Exists('/usr/lib/mono/4.5-api')">/usr/lib/mono/4.5-api</FrameworkPathOverride>
+ <FrameworkPathOverride Condition="Exists('/usr/local/lib/mono/4.5-api')">/usr/local/lib/mono/4.5-api</FrameworkPathOverride>
+ <FrameworkPathOverride Condition="Exists('/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/4.5-api')">/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/4.5-api</FrameworkPathOverride>
+ </PropertyGroup>
+
+ <PropertyGroup Label="Asset root folders. TODO(kkm): Change with package separation.">
+ <!-- TODO(kkm): Rework whole section when splitting packages. -->
+ <!-- GRPC: ../../third_party/protobuf/src/google/protobuf/ -->
+ <!-- GPB: ../src/google/protobuf/ -->
+ <Assets_ProtoInclude>../../../third_party/protobuf/src/google/protobuf/</Assets_ProtoInclude>
+
+ <!-- GPB: ../protoc/ -->
+ <!-- GRPC: ../protoc_plugins/protoc_ -->
+ <Assets_ProtoCompiler>../protoc_plugins/protoc_</Assets_ProtoCompiler>
+
+ <!-- GRPC: ../protoc_plugins/ -->
+ <Assets_GrpcPlugins>../protoc_plugins/</Assets_GrpcPlugins>
+ </PropertyGroup>
+
+ <PropertyGroup Condition=" '$(TargetFramework)' != 'net45' ">
+ <DefineConstants>$(DefineConstants);NETCORE</DefineConstants>
+ </PropertyGroup>
+
+ <PropertyGroup Label="NuGet package definition" Condition=" '$(Configuration)' == 'Release' ">
+ <!-- TODO(kkm): Change to "build\" after splitting. -->
+ <BuildOutputTargetFolder>build\_protobuf\</BuildOutputTargetFolder>
+ <DevelopmentDependency>true</DevelopmentDependency>
+ <NoPackageAnalysis>true</NoPackageAnalysis>
+ <PackageId>Grpc.Tools</PackageId>
+ <Description>gRPC and Protocol Buffer compiler for managed C# and native C++ projects.
+
+Add this package to a project that contains .proto files to be compiled to code.
+It contains the compilers, include files and project system integration for gRPC
+and Protocol buffer service description files necessary to build them on Windows,
+Linux and MacOS. Managed runtime is supplied separately in the Grpc.Core package.</Description>
+ <Copyright>Copyright 2018 gRPC authors</Copyright>
+ <Authors>gRPC authors</Authors>
+ <PackageLicenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</PackageLicenseUrl>
+ <PackageProjectUrl>https://github.com/grpc/grpc</PackageProjectUrl>
+ <PackageTags>gRPC RPC protocol HTTP/2</PackageTags>
+ </PropertyGroup>
+
+ <ItemGroup Label="NuGet package assets">
+ <None Pack="true" PackagePath="build\" Include="build\**\*.xml; build\**\*.props; build\**\*.targets;" />
+
+ <!-- Protobuf assets (for Google.Protobuf.Tools) -->
+ <_ProtoAssetName Include="any;api;descriptor;duration;empty;field_mask;
+ source_context;struct;timestamp;type;wrappers" />
+ <_Asset PackagePath="build/native/include/google/protobuf/" Include="@(_ProtoAssetName->'$(Assets_ProtoInclude)%(Identity).proto')" />
+
+ <!-- TODO(kkm): GPB builds assets into "macosx", GRPC into "macos". -->
+ <!-- TODO(kkm): Do not place non-tools under tools/, use build/native/bin/. -->
+ <!-- TODO(kkm): Do not package windows x64 builds (#13098). -->
+ <_Asset PackagePath="tools/windows_x86/protoc.exe" Include="$(Assets_ProtoCompiler)windows_x86/protoc.exe" />
+ <_Asset PackagePath="tools/windows_x64/protoc.exe" Include="$(Assets_ProtoCompiler)windows_x64/protoc.exe" />
+ <_Asset PackagePath="tools/linux_x86/protoc" Include="$(Assets_ProtoCompiler)linux_x86/protoc" />
+ <_Asset PackagePath="tools/linux_x64/protoc" Include="$(Assets_ProtoCompiler)linux_x64/protoc" />
+ <_Asset PackagePath="tools/macosx_x86/protoc" Include="$(Assets_ProtoCompiler)macos_x86/protoc" /> <!-- GPB: macosx-->
+ <_Asset PackagePath="tools/macosx_x64/protoc" Include="$(Assets_ProtoCompiler)macos_x64/protoc" /> <!-- GPB: macosx-->
+
+ <!-- gRPC assets (for Grpc.Tools) -->
+ <_Asset PackagePath="tools/windows_x86/grpc_csharp_plugin.exe" Include="$(Assets_GrpcPlugins)protoc_windows_x86/grpc_csharp_plugin.exe" />
+ <_Asset PackagePath="tools/windows_x64/grpc_csharp_plugin.exe" Include="$(Assets_GrpcPlugins)protoc_windows_x64/grpc_csharp_plugin.exe" />
+ <_Asset PackagePath="tools/linux_x86/grpc_csharp_plugin" Include="$(Assets_GrpcPlugins)protoc_linux_x86/grpc_csharp_plugin" />
+ <_Asset PackagePath="tools/linux_x64/grpc_csharp_plugin" Include="$(Assets_GrpcPlugins)protoc_linux_x64/grpc_csharp_plugin" />
+ <_Asset PackagePath="tools/macosx_x86/grpc_csharp_plugin" Include="$(Assets_GrpcPlugins)protoc_macos_x86/grpc_csharp_plugin" />
+ <_Asset PackagePath="tools/macosx_x64/grpc_csharp_plugin" Include="$(Assets_GrpcPlugins)protoc_macos_x64/grpc_csharp_plugin" />
+
+ <None Include="@(_Asset)" Pack="true" Visible="false" />
+ </ItemGroup>
+
+ <ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
+ <Reference Include="Microsoft.Build.Framework; Microsoft.Build.Utilities.v4.0" Pack="false" />
+ </ItemGroup>
+
+ <ItemGroup Condition=" '$(TargetFramework)' != 'net45' ">
+ <PackageReference Include="Microsoft.Build.Framework; Microsoft.Build.Utilities.Core" Version="15.6.*" />
+ <!-- Set PrivateAssets="All" on all items, even those implicitly added,
+ so that they do not become dependencies of this package. -->
+ <PackageReference Update="@(PackageReference)" PrivateAssets="All" />
+ </ItemGroup>
+
+</Project>
diff --git a/src/csharp/Grpc.Tools/ProtoCompile.cs b/src/csharp/Grpc.Tools/ProtoCompile.cs
new file mode 100644
index 0000000000..93608e1ac0
--- /dev/null
+++ b/src/csharp/Grpc.Tools/ProtoCompile.cs
@@ -0,0 +1,441 @@
+#region Copyright notice and license
+
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System.Text;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+namespace Grpc.Tools
+{
+ /// <summary>
+ /// Run Google proto compiler (protoc).
+ ///
+ /// After a successful run, the task reads the dependency file if specified
+ /// to be saved by the compiler, and returns its output files.
+ ///
+ /// This task (unlike PrepareProtoCompile) does not attempt to guess anything
+ /// about language-specific behavior of protoc, and therefore can be used for
+ /// any language outputs.
+ /// </summary>
+ public class ProtoCompile : ToolTask
+ {
+ /*
+
+ Usage: /home/kkm/work/protobuf/src/.libs/lt-protoc [OPTION] PROTO_FILES
+ Parse PROTO_FILES and generate output based on the options given:
+ -IPATH, --proto_path=PATH Specify the directory in which to search for
+ imports. May be specified multiple times;
+ directories will be searched in order. If not
+ given, the current working directory is used.
+ --version Show version info and exit.
+ -h, --help Show this text and exit.
+ --encode=MESSAGE_TYPE Read a text-format message of the given type
+ from standard input and write it in binary
+ to standard output. The message type must
+ be defined in PROTO_FILES or their imports.
+ --decode=MESSAGE_TYPE Read a binary message of the given type from
+ standard input and write it in text format
+ to standard output. The message type must
+ be defined in PROTO_FILES or their imports.
+ --decode_raw Read an arbitrary protocol message from
+ standard input and write the raw tag/value
+ pairs in text format to standard output. No
+ PROTO_FILES should be given when using this
+ flag.
+ --descriptor_set_in=FILES Specifies a delimited list of FILES
+ each containing a FileDescriptorSet (a
+ protocol buffer defined in descriptor.proto).
+ The FileDescriptor for each of the PROTO_FILES
+ provided will be loaded from these
+ FileDescriptorSets. If a FileDescriptor
+ appears multiple times, the first occurrence
+ will be used.
+ -oFILE, Writes a FileDescriptorSet (a protocol buffer,
+ --descriptor_set_out=FILE defined in descriptor.proto) containing all of
+ the input files to FILE.
+ --include_imports When using --descriptor_set_out, also include
+ all dependencies of the input files in the
+ set, so that the set is self-contained.
+ --include_source_info When using --descriptor_set_out, do not strip
+ SourceCodeInfo from the FileDescriptorProto.
+ This results in vastly larger descriptors that
+ include information about the original
+ location of each decl in the source file as
+ well as surrounding comments.
+ --dependency_out=FILE Write a dependency output file in the format
+ expected by make. This writes the transitive
+ set of input file paths to FILE
+ --error_format=FORMAT Set the format in which to print errors.
+ FORMAT may be 'gcc' (the default) or 'msvs'
+ (Microsoft Visual Studio format).
+ --print_free_field_numbers Print the free field numbers of the messages
+ defined in the given proto files. Groups share
+ the same field number space with the parent
+ message. Extension ranges are counted as
+ occupied fields numbers.
+
+ --plugin=EXECUTABLE Specifies a plugin executable to use.
+ Normally, protoc searches the PATH for
+ plugins, but you may specify additional
+ executables not in the path using this flag.
+ Additionally, EXECUTABLE may be of the form
+ NAME=PATH, in which case the given plugin name
+ is mapped to the given executable even if
+ the executable's own name differs.
+ --cpp_out=OUT_DIR Generate C++ header and source.
+ --csharp_out=OUT_DIR Generate C# source file.
+ --java_out=OUT_DIR Generate Java source file.
+ --javanano_out=OUT_DIR Generate Java Nano source file.
+ --js_out=OUT_DIR Generate JavaScript source.
+ --objc_out=OUT_DIR Generate Objective C header and source.
+ --php_out=OUT_DIR Generate PHP source file.
+ --python_out=OUT_DIR Generate Python source file.
+ --ruby_out=OUT_DIR Generate Ruby source file.
+ @<filename> Read options and filenames from file. If a
+ relative file path is specified, the file
+ will be searched in the working directory.
+ The --proto_path option will not affect how
+ this argument file is searched. Content of
+ the file will be expanded in the position of
+ @<filename> as in the argument list. Note
+ that shell expansion is not applied to the
+ content of the file (i.e., you cannot use
+ quotes, wildcards, escapes, commands, etc.).
+ Each line corresponds to a single argument,
+ even if it contains spaces.
+ */
+ static string[] s_supportedGenerators = new[] { "cpp", "csharp", "java",
+ "javanano", "js", "objc",
+ "php", "python", "ruby" };
+
+ /// <summary>
+ /// Code generator.
+ /// </summary>
+ [Required]
+ public string Generator { get; set; }
+
+ /// <summary>
+ /// Protobuf files to compile.
+ /// </summary>
+ [Required]
+ public ITaskItem[] ProtoBuf { get; set; }
+
+ /// <summary>
+ /// Directory where protoc dependency files are cached. If provided, dependency
+ /// output filename is autogenerated from source directory hash and file name.
+ /// Mutually exclusive with DependencyOut.
+ /// Switch: --dependency_out (with autogenerated file name).
+ /// </summary>
+ public string ProtoDepDir { get; set; }
+
+ /// <summary>
+ /// Dependency file full name. Mutually exclusive with ProtoDepDir.
+ /// Autogenerated file name is available in this property after execution.
+ /// Switch: --dependency_out.
+ /// </summary>
+ [Output]
+ public string DependencyOut { get; set; }
+
+ /// <summary>
+ /// The directories to search for imports. Directories will be searched
+ /// in order. If not given, the current working directory is used.
+ /// Switch: --proto_path.
+ /// </summary>
+ public string[] ProtoPath { get; set; }
+
+ /// <summary>
+ /// Generated code directory. The generator property determines the language.
+ /// Switch: --GEN-out= (for different generators GEN).
+ /// </summary>
+ [Required]
+ public string OutputDir { get; set; }
+
+ /// <summary>
+ /// Codegen options. See also OptionsFromMetadata.
+ /// Switch: --GEN_out= (for different generators GEN).
+ /// </summary>
+ public string[] OutputOptions { get; set; }
+
+ /// <summary>
+ /// Full path to the gRPC plugin executable. If specified, gRPC generation
+ /// is enabled for the files.
+ /// Switch: --plugin=protoc-gen-grpc=
+ /// </summary>
+ public string GrpcPluginExe { get; set; }
+
+ /// <summary>
+ /// Generated gRPC directory. The generator property determines the
+ /// language. If gRPC is enabled but this is not given, OutputDir is used.
+ /// Switch: --grpc_out=
+ /// </summary>
+ public string GrpcOutputDir { get; set; }
+
+ /// <summary>
+ /// gRPC Codegen options. See also OptionsFromMetadata.
+ /// --grpc_opt=opt1,opt2=val (comma-separated).
+ /// </summary>
+ public string[] GrpcOutputOptions { get; set; }
+
+ /// <summary>
+ /// List of files written in addition to generated outputs. Includes a
+ /// single item for the dependency file if written.
+ /// </summary>
+ [Output]
+ public ITaskItem[] AdditionalFileWrites { get; private set; }
+
+ /// <summary>
+ /// List of language files generated by protoc. Empty unless DependencyOut
+ /// or ProtoDepDir is set, since the file writes are extracted from protoc
+ /// dependency output file.
+ /// </summary>
+ [Output]
+ public ITaskItem[] GeneratedFiles { get; private set; }
+
+ // Hide this property from MSBuild, we should never use a shell script.
+ private new bool UseCommandProcessor { get; set; }
+
+ protected override string ToolName => Platform.IsWindows ? "protoc.exe" : "protoc";
+
+ // Since we never try to really locate protoc.exe somehow, just try ToolExe
+ // as the full tool location. It will be either just protoc[.exe] from
+ // ToolName above if not set by the user, or a user-supplied full path. The
+ // base class will then resolve the former using system PATH.
+ protected override string GenerateFullPathToTool() => ToolExe;
+
+ // Log protoc errors with the High priority (bold white in MsBuild,
+ // printed with -v:n, and shown in the Output windows in VS).
+ protected override MessageImportance StandardErrorLoggingImportance => MessageImportance.High;
+
+ // Called by base class to validate arguments and make them consistent.
+ protected override bool ValidateParameters()
+ {
+ // Part of proto command line switches, must be lowercased.
+ Generator = Generator.ToLowerInvariant();
+ if (!System.Array.Exists(s_supportedGenerators, g => g == Generator))
+ {
+ Log.LogError("Invalid value for Generator='{0}'. Supported generators: {1}",
+ Generator, string.Join(", ", s_supportedGenerators));
+ }
+
+ if (ProtoDepDir != null && DependencyOut != null)
+ {
+ Log.LogError("Properties ProtoDepDir and DependencyOut may not be both specified");
+ }
+
+ if (ProtoBuf.Length > 1 && (ProtoDepDir != null || DependencyOut != null))
+ {
+ Log.LogError("Proto compiler currently allows only one input when " +
+ "--dependency_out is specified (via ProtoDepDir or DependencyOut). " +
+ "Tracking issue: https://github.com/google/protobuf/pull/3959");
+ }
+
+ // Use ProtoDepDir to autogenerate DependencyOut
+ if (ProtoDepDir != null)
+ {
+ DependencyOut = DepFileUtil.GetDepFilenameForProto(ProtoDepDir, ProtoBuf[0].ItemSpec);
+ }
+
+ if (GrpcPluginExe == null)
+ {
+ GrpcOutputOptions = null;
+ GrpcOutputDir = null;
+ }
+ else if (GrpcOutputDir == null)
+ {
+ // Use OutputDir for gRPC output if not specified otherwise by user.
+ GrpcOutputDir = OutputDir;
+ }
+
+ return !Log.HasLoggedErrors && base.ValidateParameters();
+ }
+
+ // Protoc chokes on BOM, naturally. I would!
+ static readonly Encoding s_utf8WithoutBom = new UTF8Encoding(false);
+ protected override Encoding ResponseFileEncoding => s_utf8WithoutBom;
+
+ // Protoc takes one argument per line from the response file, and does not
+ // require any quoting whatsoever. Otherwise, this is similar to the
+ // standard CommandLineBuilder
+ class ProtocResponseFileBuilder
+ {
+ StringBuilder _data = new StringBuilder(1000);
+ public override string ToString() => _data.ToString();
+
+ // If 'value' is not empty, append '--name=value\n'.
+ public void AddSwitchMaybe(string name, string value)
+ {
+ if (!string.IsNullOrEmpty(value))
+ {
+ _data.Append("--").Append(name).Append("=")
+ .Append(value).Append('\n');
+ }
+ }
+
+ // Add switch with the 'values' separated by commas, for options.
+ public void AddSwitchMaybe(string name, string[] values)
+ {
+ if (values?.Length > 0)
+ {
+ _data.Append("--").Append(name).Append("=")
+ .Append(string.Join(",", values)).Append('\n');
+ }
+ }
+
+ // Add a positional argument to the file data.
+ public void AddArg(string arg)
+ {
+ _data.Append(arg).Append('\n');
+ }
+ };
+
+ // Called by the base ToolTask to get response file contents.
+ protected override string GenerateResponseFileCommands()
+ {
+ var cmd = new ProtocResponseFileBuilder();
+ cmd.AddSwitchMaybe(Generator + "_out", TrimEndSlash(OutputDir));
+ cmd.AddSwitchMaybe(Generator + "_opt", OutputOptions);
+ cmd.AddSwitchMaybe("plugin=protoc-gen-grpc", GrpcPluginExe);
+ cmd.AddSwitchMaybe("grpc_out", TrimEndSlash(GrpcOutputDir));
+ cmd.AddSwitchMaybe("grpc_opt", GrpcOutputOptions);
+ if (ProtoPath != null)
+ {
+ foreach (string path in ProtoPath)
+ cmd.AddSwitchMaybe("proto_path", TrimEndSlash(path));
+ }
+ cmd.AddSwitchMaybe("dependency_out", DependencyOut);
+ foreach (var proto in ProtoBuf)
+ {
+ cmd.AddArg(proto.ItemSpec);
+ }
+ return cmd.ToString();
+ }
+
+ // Protoc cannot digest trailing slashes in directory names,
+ // curiously under Linux, but not in Windows.
+ static string TrimEndSlash(string dir)
+ {
+ if (dir == null || dir.Length <= 1)
+ {
+ return dir;
+ }
+ string trim = dir.TrimEnd('/', '\\');
+ // Do not trim the root slash, drive letter possible.
+ if (trim.Length == 0)
+ {
+ // Slashes all the way down.
+ return dir.Substring(0, 1);
+ }
+ if (trim.Length == 2 && dir.Length > 2 && trim[1] == ':')
+ {
+ // We have a drive letter and root, e. g. 'C:\'
+ return dir.Substring(0, 3);
+ }
+ return trim;
+ }
+
+ // Called by the base class to log tool's command line.
+ //
+ // Protoc command file is peculiar, with one argument per line, separated
+ // by newlines. Unwrap it for log readability into a single line, and also
+ // quote arguments, lest it look weird and so it may be copied and pasted
+ // into shell. Since this is for logging only, correct enough is correct.
+ protected override void LogToolCommand(string cmd)
+ {
+ var printer = new StringBuilder(1024);
+
+ // Print 'str' slice into 'printer', wrapping in quotes if contains some
+ // interesting characters in file names, or if empty string. The list of
+ // characters requiring quoting is not by any means exhaustive; we are
+ // just striving to be nice, not guaranteeing to be nice.
+ var quotable = new[] { ' ', '!', '$', '&', '\'', '^' };
+ void PrintQuoting(string str, int start, int count)
+ {
+ bool wrap = count == 0 || str.IndexOfAny(quotable, start, count) >= 0;
+ if (wrap) printer.Append('"');
+ printer.Append(str, start, count);
+ if (wrap) printer.Append('"');
+ }
+
+ for (int ib = 0, ie; (ie = cmd.IndexOf('\n', ib)) >= 0; ib = ie + 1)
+ {
+ // First line only contains both the program name and the first switch.
+ // We can rely on at least the '--out_dir' switch being always present.
+ if (ib == 0)
+ {
+ int iep = cmd.IndexOf(" --");
+ if (iep > 0)
+ {
+ PrintQuoting(cmd, 0, iep);
+ ib = iep + 1;
+ }
+ }
+ printer.Append(' ');
+ if (cmd[ib] == '-')
+ {
+ // Print switch unquoted, including '=' if any.
+ int iarg = cmd.IndexOf('=', ib, ie - ib);
+ if (iarg < 0)
+ {
+ // Bare switch without a '='.
+ printer.Append(cmd, ib, ie - ib);
+ continue;
+ }
+ printer.Append(cmd, ib, iarg + 1 - ib);
+ ib = iarg + 1;
+ }
+ // A positional argument or switch value.
+ PrintQuoting(cmd, ib, ie - ib);
+ }
+
+ base.LogToolCommand(printer.ToString());
+ }
+
+ // Main task entry point.
+ public override bool Execute()
+ {
+ base.UseCommandProcessor = false;
+
+ bool ok = base.Execute();
+ if (!ok)
+ {
+ return false;
+ }
+
+ // Read dependency output file from the compiler to retrieve the
+ // definitive list of created files. Report the dependency file
+ // itself as having been written to.
+ if (DependencyOut != null)
+ {
+ string[] outputs = DepFileUtil.ReadDependencyOutputs(DependencyOut, Log);
+ if (HasLoggedErrors)
+ {
+ return false;
+ }
+
+ GeneratedFiles = new ITaskItem[outputs.Length];
+ for (int i = 0; i < outputs.Length; i++)
+ {
+ GeneratedFiles[i] = new TaskItem(outputs[i]);
+ }
+ AdditionalFileWrites = new ITaskItem[] { new TaskItem(DependencyOut) };
+ }
+
+ return true;
+ }
+ };
+}
diff --git a/src/csharp/Grpc.Tools/ProtoCompilerOutputs.cs b/src/csharp/Grpc.Tools/ProtoCompilerOutputs.cs
new file mode 100644
index 0000000000..915be3421e
--- /dev/null
+++ b/src/csharp/Grpc.Tools/ProtoCompilerOutputs.cs
@@ -0,0 +1,86 @@
+#region Copyright notice and license
+
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System.Collections.Generic;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+namespace Grpc.Tools
+{
+ public class ProtoCompilerOutputs : Task
+ {
+ /// <summary>
+ /// Code generator. Currently supported are "csharp", "cpp".
+ /// </summary>
+ [Required]
+ public string Generator { get; set; }
+
+ /// <summary>
+ /// All Proto files in the project. The task computes possible outputs
+ /// from these proto files, and returns them in the PossibleOutputs list.
+ /// Not all of these might be actually produced by protoc; this is dealt
+ /// with later in the ProtoCompile task which returns the list of
+ /// files actually produced by the compiler.
+ /// </summary>
+ [Required]
+ public ITaskItem[] ProtoBuf { get; set; }
+
+ /// <summary>
+ /// Output items per each potential output. We do not look at existing
+ /// cached dependency even if they exist, since file may be refactored,
+ /// affecting whether or not gRPC code file is generated from a given proto.
+ /// Instead, all potentially possible generated sources are collected.
+ /// It is a wise idea to generate empty files later for those potentials
+ /// that are not actually created by protoc, so the dependency checks
+ /// result in a minimal recompilation. The Protoc task can output the
+ /// list of files it actually produces, given right combination of its
+ /// properties.
+ /// Output items will have the Source metadata set on them:
+ /// <ItemName Include="MyProto.cs" Source="my_proto.proto" />
+ /// </summary>
+ [Output]
+ public ITaskItem[] PossibleOutputs { get; private set; }
+
+ public override bool Execute()
+ {
+ var generator = GeneratorServices.GetForLanguage(Generator, Log);
+ if (generator == null)
+ {
+ // Error already logged, just return.
+ return false;
+ }
+
+ // Get language-specific possible output. The generator expects certain
+ // metadata be set on the proto item.
+ var possible = new List<ITaskItem>();
+ foreach (var proto in ProtoBuf)
+ {
+ var outputs = generator.GetPossibleOutputs(proto);
+ foreach (string output in outputs)
+ {
+ var ti = new TaskItem(output);
+ ti.SetMetadata(Metadata.Source, proto.ItemSpec);
+ possible.Add(ti);
+ }
+ }
+ PossibleOutputs = possible.ToArray();
+
+ return !Log.HasLoggedErrors;
+ }
+ };
+}
diff --git a/src/csharp/Grpc.Tools/ProtoReadDependencies.cs b/src/csharp/Grpc.Tools/ProtoReadDependencies.cs
new file mode 100644
index 0000000000..963837e8b7
--- /dev/null
+++ b/src/csharp/Grpc.Tools/ProtoReadDependencies.cs
@@ -0,0 +1,78 @@
+#region Copyright notice and license
+
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System.Collections.Generic;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+namespace Grpc.Tools
+{
+ public class ProtoReadDependencies : Task
+ {
+ /// <summary>
+ /// The collection is used to collect possible additional dependencies
+ /// of proto files cached under ProtoDepDir.
+ /// </summary>
+ [Required]
+ public ITaskItem[] ProtoBuf { get; set; }
+
+ /// <summary>
+ /// Directory where protoc dependency files are cached.
+ /// </summary>
+ [Required]
+ public string ProtoDepDir { get; set; }
+
+ /// <summary>
+ /// Additional items that a proto file depends on. This list may include
+ /// extra dependencies; we do our best to include as few extra positives
+ /// as reasonable to avoid missing any. The collection item is the
+ /// dependency, and its Source metadatum is the dependent proto file, like
+ /// <ItemName Include="/usr/include/proto/wrapper.proto"
+ /// Source="my_proto.proto" />
+ /// </summary>
+ [Output]
+ public ITaskItem[] Dependencies { get; private set; }
+
+ public override bool Execute()
+ {
+ // Read dependency files, where available. There might be none,
+ // just use a best effort.
+ if (ProtoDepDir != null)
+ {
+ var dependencies = new List<ITaskItem>();
+ foreach (var proto in ProtoBuf)
+ {
+ string[] deps = DepFileUtil.ReadDependencyInputs(ProtoDepDir, proto.ItemSpec, Log);
+ foreach (string dep in deps)
+ {
+ var ti = new TaskItem(dep);
+ ti.SetMetadata(Metadata.Source, proto.ItemSpec);
+ dependencies.Add(ti);
+ }
+ }
+ Dependencies = dependencies.ToArray();
+ }
+ else
+ {
+ Dependencies = new ITaskItem[0];
+ }
+
+ return !Log.HasLoggedErrors;
+ }
+ };
+}
diff --git a/src/csharp/Grpc.Tools/ProtoToolsPlatform.cs b/src/csharp/Grpc.Tools/ProtoToolsPlatform.cs
new file mode 100644
index 0000000000..aed8a66339
--- /dev/null
+++ b/src/csharp/Grpc.Tools/ProtoToolsPlatform.cs
@@ -0,0 +1,63 @@
+#region Copyright notice and license
+
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+namespace Grpc.Tools
+{
+ /// <summary>
+ /// A helper task to resolve actual OS type and bitness.
+ /// </summary>
+ public class ProtoToolsPlatform : Task
+ {
+ /// <summary>
+ /// Return one of 'linux', 'macosx' or 'windows'.
+ /// If the OS is unknown, the property is not set.
+ /// </summary>
+ [Output]
+ public string Os { get; set; }
+
+ /// <summary>
+ /// Return one of 'x64' or 'x86'.
+ /// If the CPU is unknown, the property is not set.
+ /// </summary>
+ [Output]
+ public string Cpu { get; set; }
+
+
+ public override bool Execute()
+ {
+ switch (Platform.Os)
+ {
+ case Platform.OsKind.Linux: Os = "linux"; break;
+ case Platform.OsKind.MacOsX: Os = "macosx"; break;
+ case Platform.OsKind.Windows: Os = "windows"; break;
+ default: Os = ""; break;
+ }
+
+ switch (Platform.Cpu)
+ {
+ case Platform.CpuKind.X86: Cpu = "x86"; break;
+ case Platform.CpuKind.X64: Cpu = "x64"; break;
+ default: Cpu = ""; break;
+ }
+ return true;
+ }
+ };
+}
diff --git a/src/csharp/Grpc.Tools/build/Grpc.Tools.props b/src/csharp/Grpc.Tools/build/Grpc.Tools.props
new file mode 100644
index 0000000000..dbcd8bf494
--- /dev/null
+++ b/src/csharp/Grpc.Tools/build/Grpc.Tools.props
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
+ </PropertyGroup>
+
+ <!-- Name of this file must match package ID. -->
+ <!-- Packages will be split later. -->
+ <Import Project="_grpc/_Grpc.Tools.props"/>
+ <Import Project="_protobuf/Google.Protobuf.Tools.props"/>
+</Project>
diff --git a/src/csharp/Grpc.Tools/build/Grpc.Tools.targets b/src/csharp/Grpc.Tools/build/Grpc.Tools.targets
new file mode 100644
index 0000000000..c0a5b1e2c5
--- /dev/null
+++ b/src/csharp/Grpc.Tools/build/Grpc.Tools.targets
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
+ </PropertyGroup>
+
+ <!-- Name of this file must match package ID. -->
+ <!-- Packages will be split later. -->
+ <Import Project="_grpc/_Grpc.Tools.targets"/>
+ <Import Project="_protobuf/Google.Protobuf.Tools.targets"/>
+</Project>
diff --git a/src/csharp/Grpc.Tools/build/_grpc/Grpc.CSharp.xml b/src/csharp/Grpc.Tools/build/_grpc/Grpc.CSharp.xml
new file mode 100644
index 0000000000..54468eb5ef
--- /dev/null
+++ b/src/csharp/Grpc.Tools/build/_grpc/Grpc.CSharp.xml
@@ -0,0 +1,30 @@
+<ProjectSchemaDefinitions xmlns="http://schemas.microsoft.com/build/2009/properties">
+ <Rule Name="ProtoBuf"
+ DisplayName="File Properties"
+ PageTemplate="generic"
+ Description="File Properties"
+ OverrideMode="Extend">
+ <Rule.DataSource>
+ <DataSource Persistence="ProjectFile" Label="Configuration" ItemType="ProtoBuf"
+ HasConfigurationCondition="false" SourceOfDefaultValue="AfterContext" />
+ </Rule.DataSource>
+
+ <Rule.Categories>
+ <Category Name="gRPC" DisplayName="gRPC" />
+ </Rule.Categories>
+
+ <EnumProperty Name="GrpcServices" DisplayName="gRPC Stub Classes"
+ Category="gRPC" Default="Both"
+ Description="Generate gRPC server and client stub classes.">
+ <EnumValue Name="Both" DisplayName="Client and Server" IsDefault="true" />
+ <EnumValue Name="Client" DisplayName="Client only" />
+ <EnumValue Name="Server" DisplayName="Server only" />
+ <EnumValue Name="None" DisplayName="Do not generate" />
+ <EnumProperty.DataSource>
+ <DataSource ItemType="ProtoBuf" SourceOfDefaultValue="AfterContext"
+ PersistenceStyle="Attribute" />
+ </EnumProperty.DataSource>
+ </EnumProperty>
+
+ </Rule>
+</ProjectSchemaDefinitions>
diff --git a/src/csharp/Grpc.Tools/build/_grpc/README b/src/csharp/Grpc.Tools/build/_grpc/README
new file mode 100644
index 0000000000..4a7204b9ff
--- /dev/null
+++ b/src/csharp/Grpc.Tools/build/_grpc/README
@@ -0,0 +1,3 @@
+TODO(kkm): These file will go into Grpc.Tools/build after package split.
+ Remove leading underscores from file names; they are hiding the
+ files from some NuGet versions which pull them into project.
diff --git a/src/csharp/Grpc.Tools/build/_grpc/_Grpc.Tools.props b/src/csharp/Grpc.Tools/build/_grpc/_Grpc.Tools.props
new file mode 100644
index 0000000000..8ce07c48ab
--- /dev/null
+++ b/src/csharp/Grpc.Tools/build/_grpc/_Grpc.Tools.props
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
+ </PropertyGroup>
+</Project>
diff --git a/src/csharp/Grpc.Tools/build/_grpc/_Grpc.Tools.targets b/src/csharp/Grpc.Tools/build/_grpc/_Grpc.Tools.targets
new file mode 100644
index 0000000000..5f76c03ce5
--- /dev/null
+++ b/src/csharp/Grpc.Tools/build/_grpc/_Grpc.Tools.targets
@@ -0,0 +1,48 @@
+<?xml version="1.0"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
+ <gRPC_PluginFileName Condition=" '$(gRPC_PluginFileName)' == '' and '$(Language)' == 'C#' ">grpc_csharp_plugin</gRPC_PluginFileName>
+ </PropertyGroup>
+
+ <ItemGroup Condition=" '$(Protobuf_ProjectSupported)' == 'true' and '$(Language)' == 'C#' ">
+ <!-- Extend property pages with gRPC properties. -->
+ <PropertyPageSchema Include="$(MSBuildThisFileDirectory)Grpc.CSharp.xml">
+ <Context>File;BrowseObject</Context>
+ </PropertyPageSchema>
+ </ItemGroup>
+
+ <ItemDefinitionGroup Condition=" '$(Protobuf_ProjectSupported)' == 'true' and '$(Language)' == 'C#' ">
+ <ProtoBuf>
+ <GrpcServices Condition=" '%(ProtoBuf.GrpcServices)' == '' ">Both</GrpcServices>
+ </ProtoBuf>
+ </ItemDefinitionGroup>
+
+ <!-- This target is invoked in a C# project, or can be called in a customized project. -->
+ <Target Name="gRPC_ResolvePluginFullPath" AfterTargets="Protobuf_ResolvePlatform">
+ <PropertyGroup>
+ <!-- TODO(kkm): Do not use Protobuf_PackagedToolsPath, roll gRPC's own. -->
+ <!-- TODO(kkm): Do not package windows x64 builds (#13098). -->
+ <gRPC_PluginFullPath Condition=" '$(gRPC_PluginFullPath)' == '' and '$(Protobuf_ToolsOs)' == 'windows' "
+ >$(Protobuf_PackagedToolsPath)\$(Protobuf_ToolsOs)_x86\$(gRPC_PluginFileName).exe</gRPC_PluginFullPath>
+ <gRPC_PluginFullPath Condition=" '$(gRPC_PluginFullPath)' == '' "
+ >$(Protobuf_PackagedToolsPath)/$(Protobuf_ToolsOs)_$(Protobuf_ToolsCpu)/$(gRPC_PluginFileName)</gRPC_PluginFullPath>
+ </PropertyGroup>
+ </Target>
+
+ <Target Name="_gRPC_PrepareCompileOptions" AfterTargets="Protobuf_PrepareCompileOptions">
+ <ItemGroup Condition=" '$(Language)' == 'C#' ">
+ <Protobuf_Compile Condition=" %(Protobuf_Compile.GrpcServices) != 'None' ">
+ <GrpcPluginExe Condition=" '%(Protobuf_Compile.GrpcPluginExe)' == '' ">$(gRPC_PluginFullPath)</GrpcPluginExe>
+ <GrpcOutputDir Condition=" '%(Protobuf_Compile.GrpcOutputDir)' == '' " >%(Protobuf_Compile.OutputDir)</GrpcOutputDir>
+ <_GrpcOutputOptions Condition=" '%(Protobuf_Compile.Access)' == 'Internal' ">%(Protobuf_Compile._GrpcOutputOptions);internal_access</_GrpcOutputOptions>
+ </Protobuf_Compile>
+ <Protobuf_Compile Condition=" '%(Protobuf_Compile.GrpcServices)' == 'Client' ">
+ <_GrpcOutputOptions>%(Protobuf_Compile._GrpcOutputOptions);no_server</_GrpcOutputOptions>
+ </Protobuf_Compile>
+ <Protobuf_Compile Condition=" '%(Protobuf_Compile.GrpcServices)' == 'Server' ">
+ <_GrpcOutputOptions>%(Protobuf_Compile._GrpcOutputOptions);no_client</_GrpcOutputOptions>
+ </Protobuf_Compile>
+ </ItemGroup>
+ </Target>
+</Project>
diff --git a/src/csharp/Grpc.Tools/build/_protobuf/Google.Protobuf.Tools.props b/src/csharp/Grpc.Tools/build/_protobuf/Google.Protobuf.Tools.props
new file mode 100644
index 0000000000..9f2d8bb4b5
--- /dev/null
+++ b/src/csharp/Grpc.Tools/build/_protobuf/Google.Protobuf.Tools.props
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
+
+ <!-- Revision number of this package conventions (as if "API" version). -->
+ <Protobuf_ToolingRevision>1</Protobuf_ToolingRevision>
+
+ <!-- TODO(kkm): Remove one "../" when separating packages. -->
+ <!-- TODO(kkm): Do not place non-tools under tools/, use build/native/bin/. -->
+ <Protobuf_PackagedToolsPath>$( [System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)../../tools) )</Protobuf_PackagedToolsPath>
+ <Protobuf_StandardImportsPath>$( [System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)../native/include) )</Protobuf_StandardImportsPath>
+ </PropertyGroup>
+
+ <!-- NET SDK projects only: include proto files by default. Other project
+ types are not setting or using $(EnableDefaultItems).
+ Note that MSBuild evaluates all ItemGroups and their conditions in the
+ final pass over the build script, so properties like EnableDefaultProtoBufItems
+ here can be changed later in the project. -->
+ <ItemGroup Condition=" '$(Protobuf_ProjectSupported)' == 'true' ">
+ <ProtoBuf Include="**/*.proto"
+ Condition=" '$(EnableDefaultItems)' == 'true' and '$(EnableDefaultProtoBufItems)' == 'true' " />
+ </ItemGroup>
+</Project>
diff --git a/src/csharp/Grpc.Tools/build/_protobuf/Google.Protobuf.Tools.targets b/src/csharp/Grpc.Tools/build/_protobuf/Google.Protobuf.Tools.targets
new file mode 100644
index 0000000000..1d233d23a8
--- /dev/null
+++ b/src/csharp/Grpc.Tools/build/_protobuf/Google.Protobuf.Tools.targets
@@ -0,0 +1,384 @@
+<?xml version="1.0"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
+ <!-- We allow a non-C# generator be set by the user, but skip adding outputs to Compile in this case. -->
+ <Protobuf_Generator Condition=" '$(Protobuf_Generator)' == '' and '$(Language)' == 'C#' ">CSharp</Protobuf_Generator>
+ <!-- Configuration is passing the smoke test. -->
+ <Protobuf_ProjectSupported Condition=" '$(Protobuf_Generator)' != '' ">true</Protobuf_ProjectSupported>
+ <_Protobuf_MsBuildAssembly Condition=" '$(MSBuildRuntimeType)' == 'Core' ">netstandard1.3\Protobuf.MSBuild.dll</_Protobuf_MsBuildAssembly>
+ <_Protobuf_MsBuildAssembly Condition=" '$(MSBuildRuntimeType)' != 'Core' ">net45\Protobuf.MSBuild.dll</_Protobuf_MsBuildAssembly>
+ </PropertyGroup>
+
+ <UsingTask AssemblyFile="$(_Protobuf_MsBuildAssembly)" TaskName="Grpc.Tools.ProtoToolsPlatform" />
+ <UsingTask AssemblyFile="$(_Protobuf_MsBuildAssembly)" TaskName="Grpc.Tools.ProtoCompilerOutputs" />
+ <UsingTask AssemblyFile="$(_Protobuf_MsBuildAssembly)" TaskName="Grpc.Tools.ProtoReadDependencies" />
+ <UsingTask AssemblyFile="$(_Protobuf_MsBuildAssembly)" TaskName="Grpc.Tools.ProtoCompile" />
+
+ <PropertyGroup Condition=" '$(Protobuf_ProjectSupported)' == 'true' ">
+ <Protobuf_IntermediatePath Condition=" '$(Protobuf_IntermediatePath)' == '' ">$(IntermediateOutputPath)</Protobuf_IntermediatePath>
+ <Protobuf_OutputPath Condition=" '$(Protobuf_OutputPath)' == '' ">$(Protobuf_IntermediatePath)</Protobuf_OutputPath>
+ <Protobuf_DepFilesPath Condition=" '$(Protobuf_DepFilesPath)' == '' ">$(Protobuf_IntermediatePath)</Protobuf_DepFilesPath>
+ </PropertyGroup>
+
+ <ItemDefinitionGroup Condition=" '$(Protobuf_ProjectSupported)' == 'true' and '$(Language)' == 'C#' ">
+ <ProtoBuf>
+ <Access Condition="'%(ProtoBuf.Access)' == '' ">Public</Access>
+ <ProtoCompile Condition="'%(ProtoBuf.ProtoCompile)' == '' ">True</ProtoCompile>
+ <ProtoRoot Condition="'%(ProtoBuf.ProtoRoot)' == '' " />
+ <CompileOutputs Condition="'%(ProtoBuf.CompileOutputs)' == ''">True</CompileOutputs>
+ <OutputDir Condition="'%(ProtoBuf.OutputDir)' == '' ">$(Protobuf_OutputPath)</OutputDir>
+ </ProtoBuf>
+ </ItemDefinitionGroup>
+
+ <ItemGroup Condition=" '$(Protobuf_ProjectSupported)' == 'true' and '$(Language)' == 'C#' ">
+ <PropertyPageSchema Include="$(MSBuildThisFileDirectory)Protobuf.CSharp.xml">
+ <Context>File;BrowseObject</Context>
+ </PropertyPageSchema>
+ <AvailableItemName Include="ProtoBuf" />
+ </ItemGroup>
+
+ <PropertyGroup>
+ <!-- NET SDK: by default, do not include proto files in the directory.
+ Current Microsoft's recommendation is against globbing:
+ https://docs.microsoft.com/en-us/dotnet/core/tools/csproj#recommendation -->
+ <EnableDefaultProtoBufItems Condition=" '$(EnableDefaultProtoBufItems)' == '' ">false</EnableDefaultProtoBufItems>
+ </PropertyGroup>
+
+ <!-- Check configuration sanity before build. -->
+ <Target Name="_Protobuf_SanityCheck" BeforeTargets="PrepareForBuild">
+ <Error
+ Condition=" '$(Protobuf_ProjectSupported)' != 'true' "
+ Text="Google.Protobuf.Tools proto compilation is only supported by default in a C# project (extension .csproj)" />
+ </Target>
+
+ <!--================================================================================
+ Tool path resolution
+ =================================================================================-->
+
+ <!-- Extension point for plugin packages: use Protobuf_ToolsOs and Protobuf_ToolsCpu
+ to resolve executable. Either or both may be blank, however, if resolution
+ fails; do check them before using. -->
+ <Target Name="Protobuf_ResolvePlatform">
+ <ProtoToolsPlatform>
+ <Output TaskParameter="Os" PropertyName="_Protobuf_ToolsOs"/>
+ <Output TaskParameter="Cpu" PropertyName="_Protobuf_ToolsCpu"/>
+ </ProtoToolsPlatform>
+
+ <PropertyGroup>
+ <!-- First try environment variable. -->
+ <Protobuf_ToolsOs>$(PROTOBUF_TOOLS_OS)</Protobuf_ToolsOs>
+ <Protobuf_ToolsCpu>$(PROTOBUF_TOOLS_CPU)</Protobuf_ToolsCpu>
+ <Protobuf_ProtocFullPath>$(PROTOBUF_PROTOC)</Protobuf_ProtocFullPath>
+
+ <!-- Next try OS and CPU resolved by ProtoToolsPlatform. -->
+ <Protobuf_ToolsOs Condition=" '$(Protobuf_ToolsOs)' == '' ">$(_Protobuf_ToolsOs)</Protobuf_ToolsOs>
+ <Protobuf_ToolsCpu Condition=" '$(Protobuf_ToolsCpu)' == '' ">$(_Protobuf_ToolsCpu)</Protobuf_ToolsCpu>
+ <!-- TODO(kkm): Do not package windows x64 builds (#13098). -->
+ <Protobuf_ProtocFullPath Condition=" '$(Protobuf_ProtocFullPath)' == '' and '$(Protobuf_ToolsOs)' == 'windows' "
+ >$(Protobuf_PackagedToolsPath)\$(Protobuf_ToolsOs)_x86\protoc.exe</Protobuf_ProtocFullPath>
+ <Protobuf_ProtocFullPath Condition=" '$(Protobuf_ProtocFullPath)' == '' "
+ >$(Protobuf_PackagedToolsPath)/$(Protobuf_ToolsOs)_$(Protobuf_ToolsCpu)/protoc</Protobuf_ProtocFullPath>
+ </PropertyGroup>
+
+ <Error Condition=" '$(DesignTimeBuild)' != 'true' and '$(PROTOBUF_PROTOC)' == ''
+ and ( '$(Protobuf_ToolsOs)' == '' or '$(Protobuf_ToolsCpu)' == '' ) "
+ Text="Google.Protobuf.Tools cannot determine host OS and CPU.&#10;Use environment variables PROTOBUF_TOOLS_OS={linux|macosx|windows} and PROTOBUF_TOOLS_CPU={x86|x64} to try the closest match to your system.&#10;You may also set PROTOBUF_PROTOC to specify full path to the host-provided compiler (v3.5+ is required)." />
+ </Target>
+
+ <!--================================================================================
+ Proto compilation
+ =================================================================================-->
+
+ <!-- Extension points. -->
+ <Target Name="Protobuf_BeforeCompile" />
+ <Target Name="Protobuf_AfterCompile" />
+
+ <!-- Main compile sequence. Certain steps are gated by the value $(DesignTimeBuild),
+ so the sequence is good for either design time or build time. -->
+ <Target Name="Protobuf_Compile"
+ Condition=" '@(ProtoBuf)' != '' "
+ DependsOnTargets=" Protobuf_BeforeCompile;
+ Protobuf_ResolvePlatform;
+ _Protobuf_SelectFiles;
+ Protobuf_PrepareCompile;
+ _Protobuf_AugmentLanguageCompile;
+ _Protobuf_CoreCompile;
+ Protobuf_ReconcileOutputs;
+ Protobuf_AfterCompile" />
+
+ <!-- Do proto compilation by default in a C# project. In other types, the user invoke
+ Protobuf_Compile directly where required. -->
+ <!-- TODO(kkm): Do shared compile in outer multitarget project? -->
+ <Target Name="_Protobuf_Compile_BeforeCsCompile"
+ BeforeTargets="BeforeCompile"
+ DependsOnTargets="Protobuf_Compile"
+ Condition=" '$(Language)' == 'C#' " />
+
+ <Target Name="_Protobuf_SelectFiles">
+ <!-- Guess .proto root for the files. Whenever the root is set for a file explicitly,
+ leave it as is. Otherwise, for files under the project directory, set the root
+ to "." for the project's directory, as it is the current when compiling; for the
+ files outside of project directory, use each .proto file's directory as the root. -->
+ <FindUnderPath Path="$(MSBuildProjectDirectory)"
+ Files="@(ProtoBuf->WithMetadataValue('ProtoRoot',''))">
+ <Output TaskParameter="InPath" ItemName="_Protobuf_NoRootInProject"/>
+ <Output TaskParameter="OutOfPath" ItemName="_Protobuf_NoRootElsewhere"/>
+ </FindUnderPath>
+ <ItemGroup>
+ <!-- Files with explicit metadata. -->
+ <Protobuf_Compile Include="@(ProtoBuf->HasMetadata('ProtoRoot'))" />
+ <!-- In-project files will have ProtoRoot='.'. -->
+ <Protobuf_Compile Include="@(_Protobuf_NoRootInProject)">
+ <ProtoRoot>.</ProtoRoot>
+ </Protobuf_Compile>
+ <!-- Out-of-project files will have respective ProtoRoot='%(RelativeDir)'. -->
+ <Protobuf_Compile Include="@(_Protobuf_NoRootElsewhere)">
+ <ProtoRoot>%(RelativeDir)</ProtoRoot>
+ </Protobuf_Compile>
+ <!-- Remove files not for compile. -->
+ <Protobuf_Compile Remove="@(Protobuf_Compile)" Condition=" !%(ProtoCompile) " />
+ <!-- Ensure invariant Source=%(Identity). -->
+ <Protobuf_Compile>
+ <Source>%(Identity)</Source>
+ </Protobuf_Compile>
+ </ItemGroup>
+ </Target>
+
+ <!-- Extension point for non-C# project. Protobuf_Generator should be supported
+ by the ProtoCompile task, but we skip inferring expected outputs. All proto
+ files will be always recompiled with a warning, unless you add expectations
+ to the Protobuf_ExpectedOutputs collection.
+
+ All inferred ExpectedOutputs will be added to code compile (C#) in a C# project
+ by default. This is controlled per-proto by the CompileOutputs metadata. -->
+ <Target Name="Protobuf_PrepareCompile" Condition=" '@(Protobuf_Compile)' != '' ">
+ <!-- Predict expected names. -->
+ <ProtoCompilerOutputs Condition=" '$(Language)' == 'C#' "
+ ProtoBuf="@(Protobuf_Compile)"
+ Generator="$(Protobuf_Generator)">
+ <Output TaskParameter="PossibleOutputs" ItemName="Protobuf_ExpectedOutputs" />
+ </ProtoCompilerOutputs>
+ <!-- Read any dependency files from previous compiles. -->
+ <ProtoReadDependencies Condition=" '$(Protobuf_DepFilesPath)' != '' and '$(DesignTimeBuild)' != 'true' "
+ ProtoBuf="@(Protobuf_Compile)"
+ ProtoDepDir="$(Protobuf_DepFilesPath)" >
+ <Output TaskParameter="Dependencies" ItemName="Protobuf_Dependencies" />
+ </ProtoReadDependencies>
+ </Target>
+
+ <!-- Add all expected outputs, and only these, to language compile. -->
+ <Target Name="_Protobuf_AugmentLanguageCompile"
+ DependsOnTargets="_Protobuf_EnforceInvariants"
+ Condition=" '$(Language)' == 'C#' ">
+ <ItemGroup>
+ <_Protobuf_CodeCompile Include="@(Protobuf_ExpectedOutputs->Distinct())"
+ Condition=" '%(Source)' != '' and '@(Protobuf_Compile->WithMetadataValue('CompileOutputs', 'true'))' != '' " />
+ <Compile Include="@(_Protobuf_CodeCompile)" />
+ </ItemGroup>
+ </Target>
+
+ <!-- These invariants must be kept for compile up-to-date check to work. -->
+ <Target Name="_Protobuf_EnforceInvariants">
+ <!-- Enforce Source=Identity on proto files. The 'Source' metadata is used as a common
+ key to match dependencies/expected outputs in the lists for up-to-date checks. -->
+ <ItemGroup>
+ <Protobuf_Compile>
+ <Source>%(Identity)</Source>
+ </Protobuf_Compile>
+ </ItemGroup>
+
+ <!-- Remove possible output and dependency declarations that have no Source set, or those
+ not matching any proto marked for compilation. -->
+ <ItemGroup>
+ <Protobuf_ExpectedOutputs Remove="@(Protobuf_ExpectedOutputs)" Condition=" '%(Protobuf_ExpectedOutputs.Source)' == '' " />
+ <Protobuf_ExpectedOutputs Remove="@(Protobuf_ExpectedOutputs)" Condition=" '%(Source)' != '' and '@(Protobuf_Compile)' == '' " />
+ <Protobuf_Dependencies Remove="@(Protobuf_Dependencies)" Condition=" '%(Protobuf_Dependencies.Source)' == '' " />
+ <Protobuf_Dependencies Remove="@(Protobuf_Dependencies)" Condition=" '%(Source)' != '' and '@(Protobuf_Compile)' == '' " />
+ </ItemGroup>
+ </Target>
+
+ <!-- Gather files with and without known outputs, separately. -->
+ <Target Name="_Protobuf_GatherStaleFiles"
+ Condition=" '@(Protobuf_Compile)' != '' "
+ DependsOnTargets="_Protobuf_EnforceInvariants; _Protobuf_GatherStaleSimple; _Protobuf_GatherStaleBatched">
+ <ItemGroup>
+ <!-- Drop outputs from MSBuild inference (they won't have the '_Exec' metadata). -->
+ <_Protobuf_OutOfDateProto Remove="@(_Protobuf_OutOfDateProto->WithMetadataValue('_Exec',''))" />
+ </ItemGroup>
+ </Target>
+
+ <Target Name="_Protobuf_GatherStaleSimple">
+ <!-- Simple selection: always compile files that have no declared outputs (but warn below). -->
+ <ItemGroup>
+ <_Protobuf_OutOfDateProto Include="@(Protobuf_Compile)"
+ Condition = " '%(Source)' != '' and '@(Protobuf_ExpectedOutputs)' == '' ">
+ <_Exec>true</_Exec>
+ </_Protobuf_OutOfDateProto>
+ </ItemGroup>
+
+ <!-- You are seeing this warning because there was no Protobuf_ExpectedOutputs items with
+ their Source attribute pointing to the proto files listed in the warning. Such files
+ will be recompiled on every build, as there is nothing to run up-to-date check against.
+ Set Protobuf_NoOrphanWarning to 'true' to suppress if this is what you want. -->
+ <Warning Condition=" '@(_Protobuf_OutOfDateProto)' != '' and '$(Protobuf_NoOrphanWarning)' != 'true' "
+ Text="The following files have no known outputs, and will be always recompiled as if out-of-date:&#10;@(_Protobuf_Orphans->'&#10; %(Identity)', '')" />
+ </Target>
+
+ <Target Name="_Protobuf_GatherStaleBatched"
+ Inputs="@(Protobuf_Compile);%(Source);@(Protobuf_Dependencies);$(MSBuildAllProjects)"
+ Outputs="@(Protobuf_ExpectedOutputs)" >
+ <!-- The '_Exec' metadatum is set to distinguish really executed items from those MSBuild so
+ "helpfully" infers in a bucketed task. For the same reason, cannot use the intrinsic
+ ItemGroup task here. -->
+ <CreateItem Include="@(Protobuf_Compile)" AdditionalMetadata="_Exec=true">
+ <Output TaskParameter="Include" ItemName="_Protobuf_OutOfDateProto"/>
+ </CreateItem>
+ </Target>
+
+ <!-- Extension point: Plugins massage metadata into recognized metadata
+ values passed to the ProtoCompile task. -->
+ <Target Name="Protobuf_PrepareCompileOptions" Condition=" '@(Protobuf_Compile)' != '' ">
+ <ItemGroup>
+ <Protobuf_Compile>
+ <_OutputOptions Condition=" '%(Protobuf_Compile.Access)' == 'Internal' ">%(Protobuf_Compile._OutputOptions);internal_access</_OutputOptions>
+ </Protobuf_Compile>
+ </ItemGroup>
+ </Target>
+
+ <Target Name="_Protobuf_CoreCompile"
+ Condition=" '$(DesignTimeBuild)' != 'true' "
+ DependsOnTargets="Protobuf_PrepareCompileOptions;_Protobuf_GatherStaleFiles">
+ <!-- Ensure output directories. -->
+ <MakeDir Directories="%(_Protobuf_OutOfDateProto.OutputDir)" />
+ <MakeDir Directories="%(_Protobuf_OutOfDateProto.GrpcOutputDir)" />
+ <MakeDir Directories="$(Protobuf_DepFilesPath)" />
+
+ <!-- Force output to the current directory if the user has set it to empty. -->
+ <ItemGroup>
+ <_Protobuf_OutOfDateProto>
+ <OutputDir Condition=" '%(OutputDir)' == '' ">.</OutputDir>
+ </_Protobuf_OutOfDateProto>
+ </ItemGroup>
+
+ <ProtoCompile Condition=" '@(_Protobuf_OutOfDateProto)' != '' "
+ ToolExe="$(Protobuf_ProtocFullPath)"
+ Generator="$(Protobuf_Generator)"
+ ProtoBuf="%(_Protobuf_OutOfDateProto.Source)"
+ ProtoPath="%(_Protobuf_OutOfDateProto.AdditionalImportDirs);$(Protobuf_StandardImportsPath);%(_Protobuf_OutOfDateProto.ProtoRoot)"
+ ProtoDepDir="$(Protobuf_DepFilesPath)"
+ OutputDir="%(_Protobuf_OutOfDateProto.OutputDir)"
+ OutputOptions="%(_Protobuf_OutOfDateProto._OutputOptions)"
+ GrpcPluginExe="%(_Protobuf_OutOfDateProto.GrpcPluginExe)"
+ GrpcOutputDir="%(_Protobuf_OutOfDateProto.GrpcOutputDir)"
+ GrpcOutputOptions="%(_Protobuf_OutOfDateProto._GrpcOutputOptions)"
+ >
+ <Output TaskParameter="GeneratedFiles" ItemName="_Protobuf_GeneratedFiles"/>
+ </ProtoCompile>
+
+ <!-- Compute files expected but not in fact produced by protoc. -->
+ <ItemGroup Condition=" '@(_Protobuf_OutOfDateProto)' != '' ">
+ <Protobuf_ExpectedNotGenerated Include="@(Protobuf_ExpectedOutputs)"
+ Condition=" '%(Source)' != '' and '@(_Protobuf_OutOfDateProto)' != '' " />
+ <Protobuf_ExpectedNotGenerated Remove="@(_Protobuf_GeneratedFiles)" />
+ </ItemGroup>
+ </Target>
+
+ <!-- Extension point. Plugins and/or unsupported projects may take special care of the
+ Protobuf_ExpectedNotGenerated list in BeforeTargets. We just silently create the
+ missing outputs so that out-of-date checks work (we do not add them to language
+ compile though). You can empty this collection in your Before targets to do nothing.
+ The target is not executed if the proto compiler is not executed. -->
+ <Target Name="Protobuf_ReconcileOutputs"
+ Condition=" '$(DesignTimeBuild)' != 'true' ">
+ <!-- Warn about unexpected/missing files outside object file directory only.
+ This should have happened because build was incorrectly customized. -->
+ <FindUnderPath Path="$(BaseIntermediateOutputPath)" Files="@(Protobuf_ExpectedNotGenerated)">
+ <Output TaskParameter="InPath" ItemName="_Protobuf_ExpectedNotGeneratedInTemp"/>
+ <Output TaskParameter="OutOfPath" ItemName="_Protobuf_ExpectedNotGeneratedElsewhere"/>
+ </FindUnderPath>
+
+ <!-- Prevent unnecessary recompilation by silently creating empty files. This probably
+ has happened because a proto file with an rpc service was processed by the gRPC
+ plugin, and the user did not set GrpcOutput to None. When we treat outputs as
+ transient, we can do it permissively. -->
+ <Touch Files="@(_Protobuf_ExpectedNotGeneratedInTemp)" AlwaysCreate="true" />
+
+ <!-- Also create empty files outside of the intermediate directory, if the user wants so. -->
+ <Touch Files="@(_Protobuf_ExpectedNotGeneratedElsewhere)" AlwaysCreate="true"
+ Condition=" '$(Protobuf_TouchMissingExpected)' == 'true' "/>
+
+ <!-- You are seeing this warning because there were some Protobuf_ExpectedOutputs items
+ (outside of the transient directory under obj/) not in fact produced by protoc. -->
+ <Warning Condition=" '@(_Protobuf_ExpectedNotGeneratedElsewhere)' != '' and $(Protobuf_NoWarnMissingExpected) != 'true' "
+ Text="Some expected protoc outputs were not generated.&#10;@(_Protobuf_ExpectedNotGeneratedElsewhere->'&#10; %(Identity)', '')" />
+ </Target>
+
+ <!--================================================================================
+ Proto cleanup
+ =================================================================================-->
+
+ <!-- We fully support cleanup only in a C# project. If extending the build for other
+ generators/plugins, then mostly roll your own. -->
+
+ <!-- Extension points. -->
+ <Target Name="Protobuf_BeforeClean" />
+ <Target Name="Protobuf_AfterClean" />
+
+ <!-- Main cleanup sequence. -->
+ <Target Name="Protobuf_Clean"
+ Condition=" '@(ProtoBuf)' != '' "
+ DependsOnTargets=" Protobuf_BeforeClean;
+ Protobuf_PrepareClean;
+ _Protobuf_CoreClean;
+ Protobuf_AfterClean" />
+
+ <!-- Do proto cleanup by default in a C# project. In other types, the user should
+ invoke Protobuf_Clean directly if required. -->
+ <Target Name="_Protobuf_Clean_AfterCsClean"
+ AfterTargets="CoreClean"
+ DependsOnTargets="Protobuf_Clean"
+ Condition=" '$(Protobuf_ProjectSupported)' == 'true' and '$(Language)' == 'C#' " />
+
+ <!-- Extension point for non-C# project. ProtoCompilerOutputs is not invoked for
+ non-C# projects, since inferring protoc outputs is required, so this is a
+ no-op in other project types. In your extension target populate the
+ Protobuf_ExpectedOutputs with all possible output. An option is to include
+ all existing outputs using Include with a wildcard, if you know where to look.
+
+ Note this is like Protobuf_PrepareCompile, but uses @(Protobuf) regardless
+ of the Compile metadata, to remove all possible outputs. Plugins should err
+ on the side of overextending the Protobuf_ExpectedOutputs here.
+
+ All ExpectedOutputs will be removed. -->
+ <Target Name="Protobuf_PrepareClean" Condition=" '@(Protobuf)' != '' ">
+ <!-- Predict expected names. -->
+ <ProtoCompilerOutputs Condition=" '$(Language)' == 'C#' "
+ ProtoBuf="@(Protobuf)"
+ Generator="$(Protobuf_Generator)">
+ <Output TaskParameter="PossibleOutputs" ItemName="Protobuf_ExpectedOutputs" />
+ </ProtoCompilerOutputs>
+ </Target>
+
+ <Target Name="_Protobuf_CoreClean">
+ <ItemGroup>
+ <_Protobuf_Protodep Include="$(Protobuf_DepFilesPath)*.protodep" />
+ </ItemGroup>
+ <Delete Files="@(Protobuf_ExpectedOutputs);@(_Protobuf_Protodep)" TreatErrorsAsWarnings="true" />
+ </Target>
+
+ <!--================================================================================
+ Design-time support
+ =================================================================================-->
+
+ <!-- Add all .proto files to the SourceFilesProjectOutputGroupOutput, so that:
+ * Visual Studio triggers a build when any of them changed;
+ * The Pack target includes .proto files into the source package. -->
+ <Target Name="_Protobuf_SourceFilesProjectOutputGroup"
+ BeforeTargets="SourceFilesProjectOutputGroup"
+ Condition=" '@(ProtoBuf)' != '' " >
+ <ItemGroup>
+ <SourceFilesProjectOutputGroupOutput Include="@(ProtoBuf->'%(FullPath)')" />
+ </ItemGroup>
+ </Target>
+</Project>
diff --git a/src/csharp/Grpc.Tools/build/_protobuf/Protobuf.CSharp.xml b/src/csharp/Grpc.Tools/build/_protobuf/Protobuf.CSharp.xml
new file mode 100644
index 0000000000..2c41fbcbd0
--- /dev/null
+++ b/src/csharp/Grpc.Tools/build/_protobuf/Protobuf.CSharp.xml
@@ -0,0 +1,99 @@
+<ProjectSchemaDefinitions xmlns="http://schemas.microsoft.com/build/2009/properties">
+ <FileExtension Name=".proto"
+ ContentType="ProtoFile" />
+
+ <ContentType Name="ProtoFile"
+ DisplayName="Protocol buffer definitions file"
+ ItemType="ProtoBuf" />
+
+ <ItemType Name="ProtoBuf"
+ DisplayName="Protobuf compiler" />
+
+ <Rule Name="ProtoBuf"
+ DisplayName="File Properties"
+ PageTemplate="generic"
+ Description="File Properties"
+ OverrideMode="Extend">
+ <Rule.DataSource>
+ <DataSource Persistence="ProjectFile" Label="Configuration" ItemType="ProtoBuf"
+ HasConfigurationCondition="false" SourceOfDefaultValue="AfterContext" />
+ </Rule.DataSource>
+
+ <Rule.Categories>
+ <Category Name="Advanced" DisplayName="Advanced" />
+ <Category Name="Protobuf" DisplayName="Protobuf" />
+ <Category Name="Misc" DisplayName="Misc" />
+ </Rule.Categories>
+
+ <DynamicEnumProperty Name="{}{ItemType}" DisplayName="Build Action" Category="Advanced"
+ Description="How the file relates to the build and deployment processes."
+ EnumProvider="ItemTypes" />
+
+ <StringProperty Name="Identity" Visible="false" ReadOnly="true">
+ <StringProperty.DataSource>
+ <DataSource Persistence="Intrinsic" ItemType="ProtoBuf"
+ PersistedName="Identity" SourceOfDefaultValue="AfterContext" />
+ </StringProperty.DataSource>
+ </StringProperty>
+
+ <StringProperty Name="FullPath"
+ DisplayName="Full Path"
+ ReadOnly="true"
+ Category="Misc"
+ Description="Location of the file.">
+ <StringProperty.DataSource>
+ <DataSource Persistence="Intrinsic" ItemType="ProtoBuf"
+ PersistedName="FullPath" SourceOfDefaultValue="AfterContext" />
+ </StringProperty.DataSource>
+ </StringProperty>
+
+ <StringProperty Name="FileNameAndExtension"
+ DisplayName="File Name"
+ ReadOnly="true"
+ Category="Misc"
+ Description="Name of the file or folder.">
+ <StringProperty.DataSource>
+ <DataSource Persistence="Intrinsic" ItemType="ProtoBuf"
+ PersistedName="FileNameAndExtension" SourceOfDefaultValue="AfterContext" />
+ </StringProperty.DataSource>
+ </StringProperty>
+
+ <BoolProperty Name="Visible" Visible="false" Default="true" />
+
+ <StringProperty Name="DependentUpon" Visible="false">
+ <StringProperty.Metadata>
+ <NameValuePair Name="DoNotCopyAcrossProjects" Value="true" />
+ </StringProperty.Metadata>
+ </StringProperty>
+
+ <StringProperty Name="Link" Visible="false">
+ <StringProperty.DataSource>
+ <DataSource SourceOfDefaultValue="AfterContext" />
+ </StringProperty.DataSource>
+ <StringProperty.Metadata>
+ <NameValuePair Name="DoNotCopyAcrossProjects" Value="true" />
+ </StringProperty.Metadata>
+ </StringProperty>
+
+ <EnumProperty Name="Access" DisplayName="Class Access"
+ Category="Protobuf"
+ Description="Public or internal access modifier on generated classes.">
+ <EnumValue Name="Public" DisplayName="Public" IsDefault="true" />
+ <EnumValue Name="Internal" DisplayName="Internal" />
+ <EnumProperty.DataSource>
+ <DataSource ItemType="ProtoBuf" SourceOfDefaultValue="AfterContext"
+ PersistenceStyle="Attribute" />
+ </EnumProperty.DataSource>
+ </EnumProperty>
+
+ <BoolProperty Name="ProtoCompile" DisplayName="Compile Protobuf"
+ Category="Protobuf" Default="true"
+ Description="Specifies if this file is compiled or only imported by other files.">
+ <BoolProperty.DataSource>
+ <DataSource ItemType="ProtoBuf" SourceOfDefaultValue="AfterContext"
+ PersistenceStyle="Attribute" />
+ </BoolProperty.DataSource>
+ </BoolProperty>
+
+ </Rule>
+</ProjectSchemaDefinitions>
diff --git a/src/csharp/Grpc.Tools/build/_protobuf/README b/src/csharp/Grpc.Tools/build/_protobuf/README
new file mode 100644
index 0000000000..e6e358a218
--- /dev/null
+++ b/src/csharp/Grpc.Tools/build/_protobuf/README
@@ -0,0 +1 @@
+TODO(kkm): These file will go into Google.Protobuf.Tools/build after package split.
diff --git a/src/csharp/Grpc.Tools/build/native/Grpc.Tools.props b/src/csharp/Grpc.Tools/build/native/Grpc.Tools.props
new file mode 100644
index 0000000000..f83c4d135a
--- /dev/null
+++ b/src/csharp/Grpc.Tools/build/native/Grpc.Tools.props
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
+
+ <!-- Revision number of this package conventions (as if "API" version). -->
+ <Protobuf_ToolingRevision>1</Protobuf_ToolingRevision>
+
+ <!-- For a Visual Studio C++ native project we currently only resolve tools and import paths. -->
+ <!-- TODO(kkm): Do not place non-tools under tools/, use build/native/bin/. -->
+ <!-- TODO(kkm): Do not package windows x64 builds (#13098). -->
+ <Protobuf_ProtocFullPath>$(MSBuildThisFileDirectory)..\..\tools\windows_x86\protoc.exe</Protobuf_ProtocFullPath>
+ <Protobuf_StandardImportsPath>$(MSBuildThisFileDirectory)include\</Protobuf_StandardImportsPath>
+ <gRPC_PluginFileName>grpc_cpp_plugin</gRPC_PluginFileName>
+ <gRPC_PluginFullPath>$(MSBuildThisFileDirectory)..\..\tools\windows_x86\grpc_cpp_plugin.exe</gRPC_PluginFullPath>
+ </PropertyGroup>
+</Project>
diff --git a/src/csharp/Grpc.sln b/src/csharp/Grpc.sln
index d9a7b8d556..6c1b2e9998 100644
--- a/src/csharp/Grpc.sln
+++ b/src/csharp/Grpc.sln
@@ -39,6 +39,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Reflection.Tests", "Gr
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Microbenchmarks", "Grpc.Microbenchmarks\Grpc.Microbenchmarks.csproj", "{84C17746-4727-4290-8E8B-A380793DAE1E}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Tools", "Grpc.Tools\Grpc.Tools.csproj", "{8A643A1B-B85C-4E3D-BFD3-719FE04D7E91}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Tools.Tests", "Grpc.Tools.Tests\Grpc.Tools.Tests.csproj", "{AEBE9BD8-E433-45B7-8B3D-D458EDBBCFC4}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -117,6 +121,14 @@ Global
{84C17746-4727-4290-8E8B-A380793DAE1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{84C17746-4727-4290-8E8B-A380793DAE1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{84C17746-4727-4290-8E8B-A380793DAE1E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8A643A1B-B85C-4E3D-BFD3-719FE04D7E91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8A643A1B-B85C-4E3D-BFD3-719FE04D7E91}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8A643A1B-B85C-4E3D-BFD3-719FE04D7E91}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8A643A1B-B85C-4E3D-BFD3-719FE04D7E91}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AEBE9BD8-E433-45B7-8B3D-D458EDBBCFC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AEBE9BD8-E433-45B7-8B3D-D458EDBBCFC4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AEBE9BD8-E433-45B7-8B3D-D458EDBBCFC4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AEBE9BD8-E433-45B7-8B3D-D458EDBBCFC4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat
index 9ceb37e0a9..27688360e9 100755
--- a/src/csharp/build_packages_dotnetcli.bat
+++ b/src/csharp/build_packages_dotnetcli.bat
@@ -39,10 +39,10 @@ xcopy /Y /I nativelibs\csharp_ext_windows_x64\grpc_csharp_ext.dll ..\..\cmake\bu
%DOTNET% pack --configuration Release Grpc.Auth --output ..\..\..\artifacts || goto :error
%DOTNET% pack --configuration Release Grpc.HealthCheck --output ..\..\..\artifacts || goto :error
%DOTNET% pack --configuration Release Grpc.Reflection --output ..\..\..\artifacts || goto :error
+%DOTNET% pack --configuration Release Grpc.Tools --output ..\..\..\artifacts || goto :error
%NUGET% pack Grpc.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts || goto :error
%NUGET% pack Grpc.Core.NativeDebug.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts
-%NUGET% pack Grpc.Tools.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts
@rem copy resulting nuget packages to artifacts directory
xcopy /Y /I *.nupkg ..\..\artifacts\ || goto :error
diff --git a/src/csharp/tests.json b/src/csharp/tests.json
index 5683d164c6..760776f9e7 100644
--- a/src/csharp/tests.json
+++ b/src/csharp/tests.json
@@ -64,5 +64,15 @@
"Grpc.Reflection.Tests": [
"Grpc.Reflection.Tests.ReflectionClientServerTest",
"Grpc.Reflection.Tests.SymbolRegistryTest"
+ ],
+ "Grpc.Tools.Tests": [
+ "Grpc.Tools.Tests.CppGeneratorTest",
+ "Grpc.Tools.Tests.CSharpGeneratorTest",
+ "Grpc.Tools.Tests.DepFileUtilTest",
+ "Grpc.Tools.Tests.GeneratorTest",
+ "Grpc.Tools.Tests.ProtoCompileBasicTest",
+ "Grpc.Tools.Tests.ProtoCompileCommandLineGeneratorTest",
+ "Grpc.Tools.Tests.ProtoCompileCommandLinePrinterTest",
+ "Grpc.Tools.Tests.ProtoToolsPlatformTaskTest"
]
}
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m
index 862909f238..85b95dee91 100644
--- a/src/objective-c/GRPCClient/private/GRPCHost.m
+++ b/src/objective-c/GRPCClient/private/GRPCHost.m
@@ -69,7 +69,7 @@ static NSMutableDictionary *kHostCache;
// gRPC library.
// TODO(jcanizales): Add unit tests for the types of addresses we want to let pass untouched.
NSURL *hostURL = [NSURL URLWithString:[@"https://" stringByAppendingString:address]];
- if (hostURL.host && !hostURL.port) {
+ if (hostURL.host && hostURL.port == nil) {
address = [hostURL.host stringByAppendingString:@":443"];
}
@@ -193,6 +193,7 @@ static NSMutableDictionary *kHostCache;
if (pemPrivateKey == nil && pemCertChain == nil) {
creds = grpc_ssl_credentials_create(rootsASCII.bytes, NULL, NULL, NULL);
} else {
+ assert(pemPrivateKey != nil && pemCertChain != nil);
grpc_ssl_pem_key_cert_pair key_cert_pair;
NSData *privateKeyASCII = [self nullTerminatedDataWithString:pemPrivateKey];
NSData *certChainASCII = [self nullTerminatedDataWithString:pemCertChain];
@@ -226,7 +227,7 @@ static NSMutableDictionary *kHostCache;
args[@GRPC_SSL_TARGET_NAME_OVERRIDE_ARG] = _hostNameOverride;
}
- if (_responseSizeLimitOverride) {
+ if (_responseSizeLimitOverride != nil) {
args[@GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH] = _responseSizeLimitOverride;
}
diff --git a/src/proto/grpc/health/v1/health.proto b/src/proto/grpc/health/v1/health.proto
index 4b4677b8a4..38843ff1e7 100644
--- a/src/proto/grpc/health/v1/health.proto
+++ b/src/proto/grpc/health/v1/health.proto
@@ -34,10 +34,30 @@ message HealthCheckResponse {
UNKNOWN = 0;
SERVING = 1;
NOT_SERVING = 2;
+ SERVICE_UNKNOWN = 3; // Used only by the Watch method.
}
ServingStatus status = 1;
}
service Health {
+ // If the requested service is unknown, the call will fail with status
+ // NOT_FOUND.
rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
+
+ // Performs a watch for the serving status of the requested service.
+ // The server will immediately send back a message indicating the current
+ // serving status. It will then subsequently send a new message whenever
+ // the service's serving status changes.
+ //
+ // If the requested service is unknown when the call is received, the
+ // server will send a message setting the serving status to
+ // SERVICE_UNKNOWN but will *not* terminate the call. If at some
+ // future point, the serving status of the service becomes known, the
+ // server will send a new message with the service's serving status.
+ //
+ // If the call terminates with status UNIMPLEMENTED, then clients
+ // should assume this method is not supported and should not retry the
+ // call. If the call terminates with any other status (including OK),
+ // clients should retry the call with appropriate exponential backoff.
+ rpc Watch(HealthCheckRequest) returns (stream HealthCheckResponse);
}
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 932621a38d..0bd3951a19 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -348,10 +348,14 @@ CORE_SOURCE_FILES = [
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc',
'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc',
+ 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c',
'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c',
- 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc',
+ 'src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc',
'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc',
'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc',
diff --git a/src/proto/grpc/testing/package_options.proto b/src/ruby/spec/pb/codegen/grpc/testing/package_options.proto
index e7ecf8c196..e7ecf8c196 100644
--- a/src/proto/grpc/testing/package_options.proto
+++ b/src/ruby/spec/pb/codegen/grpc/testing/package_options.proto
diff --git a/src/ruby/spec/pb/codegen/package_option_spec.rb b/src/ruby/spec/pb/codegen/package_option_spec.rb
index 46d23cd651..0ebd503d79 100644
--- a/src/ruby/spec/pb/codegen/package_option_spec.rb
+++ b/src/ruby/spec/pb/codegen/package_option_spec.rb
@@ -21,9 +21,8 @@ describe 'Code Generation Options' do
fail 'CONFIG env variable unexpectedly unset' unless ENV['CONFIG']
bins_sub_dir = ENV['CONFIG']
- src_dir = File.join(File.dirname(__FILE__), '..', '..', '..', '..')
- pb_dir = File.join(src_dir, 'proto')
- bins_dir = File.join(src_dir, '..', 'bins', bins_sub_dir)
+ pb_dir = File.dirname(__FILE__)
+ bins_dir = File.join('..', '..', '..', '..', '..', 'bins', bins_sub_dir)
plugin = File.join(bins_dir, 'grpc_ruby_plugin')
protoc = File.join(bins_dir, 'protobuf', 'protoc')
diff --git a/templates/src/csharp/build_packages_dotnetcli.bat.template b/templates/src/csharp/build_packages_dotnetcli.bat.template
index 2ae909f53a..877899c7bd 100755
--- a/templates/src/csharp/build_packages_dotnetcli.bat.template
+++ b/templates/src/csharp/build_packages_dotnetcli.bat.template
@@ -41,10 +41,10 @@
%%DOTNET% pack --configuration Release Grpc.Auth --output ..\..\..\artifacts || goto :error
%%DOTNET% pack --configuration Release Grpc.HealthCheck --output ..\..\..\artifacts || goto :error
%%DOTNET% pack --configuration Release Grpc.Reflection --output ..\..\..\artifacts || goto :error
+ %%DOTNET% pack --configuration Release Grpc.Tools --output ..\..\..\artifacts || goto :error
%%NUGET% pack Grpc.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts || goto :error
%%NUGET% pack Grpc.Core.NativeDebug.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts
- %%NUGET% pack Grpc.Tools.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts
@rem copy resulting nuget packages to artifacts directory
xcopy /Y /I *.nupkg ..\..\artifacts\ || goto :error
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile.template
index 79c55d5e56..c908a638ed 100644
--- a/templates/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile.template
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile.template
@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
- FROM golang:latest
+ FROM golang:1.11
<%include file="../../go_path.include"/>
<%include file="../../python_deps.include"/>
diff --git a/test/core/memory_usage/memory_usage_test.cc b/test/core/memory_usage/memory_usage_test.cc
index c170f5ad26..5c35b4e1d3 100644
--- a/test/core/memory_usage/memory_usage_test.cc
+++ b/test/core/memory_usage/memory_usage_test.cc
@@ -43,7 +43,7 @@ int main(int argc, char** argv) {
strcpy(root, ".");
}
/* start the server */
- gpr_asprintf(&args[0], "%s/memory_profile_server%s", root,
+ gpr_asprintf(&args[0], "%s/memory_usage_server%s", root,
gpr_subprocess_binary_extension());
args[1] = const_cast<char*>("--bind");
gpr_join_host_port(&args[2], "::", port);
@@ -53,7 +53,7 @@ int main(int argc, char** argv) {
gpr_free(args[2]);
/* start the client */
- gpr_asprintf(&args[0], "%s/memory_profile_client%s", root,
+ gpr_asprintf(&args[0], "%s/memory_usage_client%s", root,
gpr_subprocess_binary_extension());
args[1] = const_cast<char*>("--target");
gpr_join_host_port(&args[2], "127.0.0.1", port);
diff --git a/test/cpp/end2end/health_service_end2end_test.cc b/test/cpp/end2end/health_service_end2end_test.cc
index 1c48b9d151..fca65dfc13 100644
--- a/test/cpp/end2end/health_service_end2end_test.cc
+++ b/test/cpp/end2end/health_service_end2end_test.cc
@@ -64,6 +64,29 @@ class HealthCheckServiceImpl : public ::grpc::health::v1::Health::Service {
return Status::OK;
}
+ Status Watch(ServerContext* context, const HealthCheckRequest* request,
+ ::grpc::ServerWriter<HealthCheckResponse>* writer) override {
+ auto last_state = HealthCheckResponse::UNKNOWN;
+ while (!context->IsCancelled()) {
+ {
+ std::lock_guard<std::mutex> lock(mu_);
+ HealthCheckResponse response;
+ auto iter = status_map_.find(request->service());
+ if (iter == status_map_.end()) {
+ response.set_status(response.SERVICE_UNKNOWN);
+ } else {
+ response.set_status(iter->second);
+ }
+ if (response.status() != last_state) {
+ writer->Write(response, ::grpc::WriteOptions());
+ }
+ }
+ gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
+ gpr_time_from_millis(1000, GPR_TIMESPAN)));
+ }
+ return Status::OK;
+ }
+
void SetStatus(const grpc::string& service_name,
HealthCheckResponse::ServingStatus status) {
std::lock_guard<std::mutex> lock(mu_);
@@ -106,14 +129,6 @@ class CustomHealthCheckService : public HealthCheckServiceInterface {
HealthCheckServiceImpl* impl_; // not owned
};
-void LoopCompletionQueue(ServerCompletionQueue* cq) {
- void* tag;
- bool ok;
- while (cq->Next(&tag, &ok)) {
- abort(); // Nothing should come out of the cq.
- }
-}
-
class HealthServiceEnd2endTest : public ::testing::Test {
protected:
HealthServiceEnd2endTest() {}
@@ -218,6 +233,33 @@ class HealthServiceEnd2endTest : public ::testing::Test {
Status(StatusCode::NOT_FOUND, ""));
}
+ void VerifyHealthCheckServiceStreaming() {
+ const grpc::string kServiceName("service_name");
+ HealthCheckServiceInterface* service = server_->GetHealthCheckService();
+ // Start Watch for service.
+ ClientContext context;
+ HealthCheckRequest request;
+ request.set_service(kServiceName);
+ std::unique_ptr<::grpc::ClientReaderInterface<HealthCheckResponse>> reader =
+ hc_stub_->Watch(&context, request);
+ // Initial response will be SERVICE_UNKNOWN.
+ HealthCheckResponse response;
+ EXPECT_TRUE(reader->Read(&response));
+ EXPECT_EQ(response.SERVICE_UNKNOWN, response.status());
+ response.Clear();
+ // Now set service to NOT_SERVING and make sure we get an update.
+ service->SetServingStatus(kServiceName, false);
+ EXPECT_TRUE(reader->Read(&response));
+ EXPECT_EQ(response.NOT_SERVING, response.status());
+ response.Clear();
+ // Now set service to SERVING and make sure we get another update.
+ service->SetServingStatus(kServiceName, true);
+ EXPECT_TRUE(reader->Read(&response));
+ EXPECT_EQ(response.SERVING, response.status());
+ // Finish call.
+ context.TryCancel();
+ }
+
TestServiceImpl echo_test_service_;
HealthCheckServiceImpl health_check_service_impl_;
std::unique_ptr<Health::Stub> hc_stub_;
@@ -245,6 +287,7 @@ TEST_F(HealthServiceEnd2endTest, DefaultHealthService) {
EXPECT_TRUE(DefaultHealthCheckServiceEnabled());
SetUpServer(true, false, false, nullptr);
VerifyHealthCheckService();
+ VerifyHealthCheckServiceStreaming();
// The default service has a size limit of the service name.
const grpc::string kTooLongServiceName(201, 'x');
@@ -252,22 +295,6 @@ TEST_F(HealthServiceEnd2endTest, DefaultHealthService) {
Status(StatusCode::INVALID_ARGUMENT, ""));
}
-// The server has no sync service.
-TEST_F(HealthServiceEnd2endTest, DefaultHealthServiceAsyncOnly) {
- EnableDefaultHealthCheckService(true);
- EXPECT_TRUE(DefaultHealthCheckServiceEnabled());
- SetUpServer(false, true, false, nullptr);
- cq_thread_ = std::thread(LoopCompletionQueue, cq_.get());
-
- HealthCheckServiceInterface* default_service =
- server_->GetHealthCheckService();
- EXPECT_TRUE(default_service == nullptr);
-
- ResetStubs();
-
- SendHealthCheckRpc("", Status(StatusCode::UNIMPLEMENTED, ""));
-}
-
// Provide an empty service to disable the default service.
TEST_F(HealthServiceEnd2endTest, ExplicitlyDisableViaOverride) {
EnableDefaultHealthCheckService(true);
@@ -296,6 +323,7 @@ TEST_F(HealthServiceEnd2endTest, ExplicitlyOverride) {
ResetStubs();
VerifyHealthCheckService();
+ VerifyHealthCheckServiceStreaming();
}
} // namespace
diff --git a/test/cpp/microbenchmarks/BUILD b/test/cpp/microbenchmarks/BUILD
index 0c3b9ef816..097e92f583 100644
--- a/test/cpp/microbenchmarks/BUILD
+++ b/test/cpp/microbenchmarks/BUILD
@@ -24,7 +24,7 @@ grpc_cc_test(
external_deps = [
"benchmark",
],
- deps = ["//test/core/util:gpr_test_util",]
+ deps = ["//test/core/util:gpr_test_util"],
)
grpc_cc_library(
@@ -69,6 +69,13 @@ grpc_cc_binary(
)
grpc_cc_binary(
+ name = "bm_call_create",
+ testonly = 1,
+ srcs = ["bm_call_create.cc"],
+ deps = [":helpers"],
+)
+
+grpc_cc_binary(
name = "bm_cq",
testonly = 1,
srcs = ["bm_cq.cc"],
diff --git a/test/cpp/microbenchmarks/bm_call_create.cc b/test/cpp/microbenchmarks/bm_call_create.cc
index 389b888084..1f7831096c 100644
--- a/test/cpp/microbenchmarks/bm_call_create.cc
+++ b/test/cpp/microbenchmarks/bm_call_create.cc
@@ -34,7 +34,6 @@
#include "src/core/ext/filters/http/client/http_client_filter.h"
#include "src/core/ext/filters/http/message_compress/message_compress_filter.h"
#include "src/core/ext/filters/http/server/http_server_filter.h"
-#include "src/core/ext/filters/load_reporting/server_load_reporting_filter.h"
#include "src/core/ext/filters/message_size/message_size_filter.h"
#include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/channel/connected_channel.h"
diff --git a/tools/distrib/check_nanopb_output.sh b/tools/distrib/check_nanopb_output.sh
index 6b98619c32..1c2ef9b768 100755
--- a/tools/distrib/check_nanopb_output.sh
+++ b/tools/distrib/check_nanopb_output.sh
@@ -16,6 +16,7 @@
set -ex
readonly NANOPB_ALTS_TMP_OUTPUT="$(mktemp -d)"
+readonly NANOPB_HEALTH_TMP_OUTPUT="$(mktemp -d)"
readonly NANOPB_TMP_OUTPUT="$(mktemp -d)"
readonly PROTOBUF_INSTALL_PREFIX="$(mktemp -d)"
@@ -68,6 +69,23 @@ if ! diff -r "$NANOPB_TMP_OUTPUT" src/core/ext/filters/client_channel/lb_policy/
fi
#
+# checks for health.proto
+#
+readonly HEALTH_GRPC_OUTPUT_PATH='src/cpp/server/health'
+# nanopb-compile the proto to a temp location
+./tools/codegen/core/gen_nano_proto.sh \
+ src/proto/grpc/health/v1/health.proto \
+ "$NANOPB_HEALTH_TMP_OUTPUT" \
+ "$HEALTH_GRPC_OUTPUT_PATH"
+# compare outputs to checked compiled code
+for NANOPB_OUTPUT_FILE in $NANOPB_HEALTH_TMP_OUTPUT/*.pb.*; do
+ if ! diff "$NANOPB_OUTPUT_FILE" "src/cpp/server/health/$(basename $NANOPB_OUTPUT_FILE)"; then
+ echo "Outputs differ: $NANOPB_HEALTH_TMP_OUTPUT vs $HEALTH_GRPC_OUTPUT_PATH"
+ exit 2
+ fi
+done
+
+#
# Checks for handshaker.proto and transport_security_common.proto
#
readonly HANDSHAKER_GRPC_OUTPUT_PATH='src/core/tsi/alts/handshaker'
diff --git a/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile
index b136259ce9..e5e68943a4 100644
--- a/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-FROM golang:latest
+FROM golang:1.11
# Using login shell removes Go from path, so we add it.
RUN ln -s /usr/local/go/bin/go /usr/local/bin
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index d5986fde90..204ef493ba 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -910,6 +910,14 @@ src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balan
src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc \
src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc \
src/core/ext/filters/client_channel/lb_policy/subchannel_list.h \
+src/core/ext/filters/client_channel/lb_policy/xds/xds.cc \
+src/core/ext/filters/client_channel/lb_policy/xds/xds.h \
+src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h \
+src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc \
+src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc \
+src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h \
+src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc \
+src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h \
src/core/ext/filters/client_channel/lb_policy_factory.cc \
src/core/ext/filters/client_channel/lb_policy_factory.h \
src/core/ext/filters/client_channel/lb_policy_registry.cc \
diff --git a/tools/gce/create_linux_kokoro_performance_worker_from_image.sh b/tools/gce/create_linux_kokoro_performance_worker_from_image.sh
new file mode 100755
index 0000000000..0f7939be4c
--- /dev/null
+++ b/tools/gce/create_linux_kokoro_performance_worker_from_image.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+# Copyright 2018 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Creates a performance worker on GCE from an image that's used for kokoro
+# perf workers.
+
+set -ex
+
+cd "$(dirname "$0")"
+
+CLOUD_PROJECT=grpc-testing
+ZONE=us-central1-b # this zone allows 32core machines
+LATEST_PERF_WORKER_IMAGE=grpc-performance-kokoro-v2 # update if newer image exists
+
+INSTANCE_NAME="${1:-grpc-kokoro-performance-server}"
+MACHINE_TYPE="${2:-n1-standard-32}"
+
+gcloud compute instances create "$INSTANCE_NAME" \
+ --project="$CLOUD_PROJECT" \
+ --zone "$ZONE" \
+ --machine-type "$MACHINE_TYPE" \
+ --image-project "$CLOUD_PROJECT" \
+ --image "$LATEST_PERF_WORKER_IMAGE" \
+ --boot-disk-size 300 \
+ --scopes https://www.googleapis.com/auth/bigquery \
+ --tags=allow-ssh
diff --git a/tools/internal_ci/linux/grpc_e2e_performance_singlevm.sh b/tools/internal_ci/linux/grpc_e2e_performance_singlevm.sh
index 86d669be33..3c9798d375 100755
--- a/tools/internal_ci/linux/grpc_e2e_performance_singlevm.sh
+++ b/tools/internal_ci/linux/grpc_e2e_performance_singlevm.sh
@@ -25,4 +25,5 @@ tools/run_tests/run_performance_tests.py \
--netperf \
--category smoketest \
-u kbuilder \
+ --bq_result_table performance_test.performance_experiment_singlevm \
--xml_report reports/singlemachine/sponge_log.xml
diff --git a/tools/internal_ci/linux/grpc_performance_profile_daily.sh b/tools/internal_ci/linux/grpc_performance_profile_daily.sh
index 34d41bc04c..0e08699923 100755
--- a/tools/internal_ci/linux/grpc_performance_profile_daily.sh
+++ b/tools/internal_ci/linux/grpc_performance_profile_daily.sh
@@ -24,8 +24,8 @@ CPUS=`python -c 'import multiprocessing; print multiprocessing.cpu_count()'`
./tools/run_tests/start_port_server.py || true
-make CONFIG=opt memory_profile_test memory_profile_client memory_profile_server -j $CPUS
-bins/opt/memory_profile_test
+make CONFIG=opt memory_usage_test memory_usage_client memory_usage_server -j $CPUS
+bins/opt/memory_usage_test
bq load microbenchmarks.memory memory_usage.csv
tools/run_tests/run_microbenchmark.py --collect summary --bigquery_upload || FAILED="true"
diff --git a/tools/internal_ci/linux/run_performance_profile_hourly.sh b/tools/internal_ci/linux/run_performance_profile_hourly.sh
index edf85c2e2c..2be9edf756 100755
--- a/tools/internal_ci/linux/run_performance_profile_hourly.sh
+++ b/tools/internal_ci/linux/run_performance_profile_hourly.sh
@@ -21,8 +21,8 @@ cd $(dirname $0)/../../..
CPUS=`python -c 'import multiprocessing; print multiprocessing.cpu_count()'`
-make CONFIG=opt memory_profile_test memory_profile_client memory_profile_server -j $CPUS
-bins/opt/memory_profile_test
+make CONFIG=opt memory_usage_test memory_usage_client memory_usage_server -j $CPUS
+bins/opt/memory_usage_test
bq load microbenchmarks.memory memory_usage.csv
tools/run_tests/run_microbenchmark.py --collect summary --bigquery_upload
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index 00c52baf9e..20b6d36671 100644
--- a/tools/run_tests/generated/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -1593,7 +1593,7 @@
"headers": [],
"is_filegroup": false,
"language": "c",
- "name": "memory_profile_client",
+ "name": "memory_usage_client",
"src": [
"test/core/memory_usage/client.cc"
],
@@ -1610,7 +1610,7 @@
"headers": [],
"is_filegroup": false,
"language": "c",
- "name": "memory_profile_server",
+ "name": "memory_usage_server",
"src": [
"test/core/memory_usage/server.cc"
],
@@ -7047,6 +7047,7 @@
"grpc_lb_policy_grpclb_secure",
"grpc_lb_policy_pick_first",
"grpc_lb_policy_round_robin",
+ "grpc_lb_policy_xds_secure",
"grpc_max_age_filter",
"grpc_message_size_filter",
"grpc_resolver_dns_ares",
@@ -7140,6 +7141,7 @@
"grpc_lb_policy_grpclb",
"grpc_lb_policy_pick_first",
"grpc_lb_policy_round_robin",
+ "grpc_lb_policy_xds",
"grpc_max_age_filter",
"grpc_message_size_filter",
"grpc_resolver_dns_ares",
@@ -10137,6 +10139,7 @@
"grpc_base",
"grpc_client_channel",
"grpc_resolver_fake",
+ "grpclb_proto",
"nanopb"
],
"headers": [
@@ -10144,10 +10147,7 @@
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h",
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h",
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h"
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h"
],
"is_filegroup": true,
"language": "c",
@@ -10162,13 +10162,7 @@
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc",
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h",
"src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h"
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h"
],
"third_party": false,
"type": "filegroup"
@@ -10180,6 +10174,7 @@
"grpc_client_channel",
"grpc_resolver_fake",
"grpc_secure",
+ "grpclb_proto",
"nanopb"
],
"headers": [
@@ -10187,10 +10182,7 @@
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h",
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h",
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h"
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h"
],
"is_filegroup": true,
"language": "c",
@@ -10205,13 +10197,7 @@
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc",
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h",
"src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h"
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h"
],
"third_party": false,
"type": "filegroup"
@@ -10256,38 +10242,27 @@
"grpc_base",
"grpc_client_channel",
"grpc_resolver_fake",
+ "grpclb_proto",
"nanopb"
],
"headers": [
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.h",
- "src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.h",
"src/core/ext/filters/client_channel/lb_policy/xds/xds.h",
"src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h",
- "src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h"
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h"
],
"is_filegroup": true,
"language": "c",
"name": "grpc_lb_policy_xds",
"src": [
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.cc",
- "src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.h",
- "src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.cc",
- "src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.h",
"src/core/ext/filters/client_channel/lb_policy/xds/xds.cc",
"src/core/ext/filters/client_channel/lb_policy/xds/xds.h",
"src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.cc",
"src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h",
"src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc",
- "src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h"
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h"
],
"third_party": false,
"type": "filegroup"
@@ -10299,38 +10274,27 @@
"grpc_client_channel",
"grpc_resolver_fake",
"grpc_secure",
+ "grpclb_proto",
"nanopb"
],
"headers": [
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.h",
- "src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.h",
"src/core/ext/filters/client_channel/lb_policy/xds/xds.h",
"src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h",
- "src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h"
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h"
],
"is_filegroup": true,
"language": "c",
"name": "grpc_lb_policy_xds_secure",
"src": [
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c",
- "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h",
- "src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.cc",
- "src/core/ext/filters/client_channel/lb_policy/xds/client_load_reporting_filter.h",
- "src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.cc",
- "src/core/ext/filters/client_channel/lb_policy/xds/load_balancer_api.h",
"src/core/ext/filters/client_channel/lb_policy/xds/xds.cc",
"src/core/ext/filters/client_channel/lb_policy/xds/xds.h",
"src/core/ext/filters/client_channel/lb_policy/xds/xds_channel.h",
"src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc",
"src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc",
- "src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h"
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.h"
],
"third_party": false,
"type": "filegroup"
@@ -10480,6 +10444,7 @@
"headers": [
"include/grpc/grpc_security.h",
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds.h",
"src/core/lib/security/context/security_context.h",
"src/core/lib/security/credentials/alts/alts_credentials.h",
"src/core/lib/security/credentials/composite/composite_credentials.h",
@@ -10512,6 +10477,7 @@
"src": [
"include/grpc/grpc_security.h",
"src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h",
+ "src/core/ext/filters/client_channel/lb_policy/xds/xds.h",
"src/core/lib/http/httpcli_security_connector.cc",
"src/core/lib/security/context/security_context.cc",
"src/core/lib/security/context/security_context.h",
@@ -11008,6 +10974,29 @@
},
{
"deps": [
+ "nanopb"
+ ],
+ "headers": [
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h",
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h",
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h"
+ ],
+ "is_filegroup": true,
+ "language": "c",
+ "name": "grpclb_proto",
+ "src": [
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c",
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.h",
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c",
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.h",
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c",
+ "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h"
+ ],
+ "third_party": false,
+ "type": "filegroup"
+ },
+ {
+ "deps": [
"nanopb_headers"
],
"headers": [],