From eb1e5a11c6397dd9809d3bb4adf142caf0007065 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Mon, 7 Nov 2022 11:25:30 -0800 Subject: [PATCH 01/39] Start 1.52.0 development cycle --- build.gradle | 2 +- .../src/test/golden/TestDeprecatedService.java.txt | 2 +- compiler/src/test/golden/TestService.java.txt | 2 +- .../src/testLite/golden/TestDeprecatedService.java.txt | 2 +- compiler/src/testLite/golden/TestService.java.txt | 2 +- core/src/main/java/io/grpc/internal/GrpcUtil.java | 2 +- examples/android/clientcache/app/build.gradle | 10 +++++----- examples/android/helloworld/app/build.gradle | 8 ++++---- examples/android/routeguide/app/build.gradle | 8 ++++---- examples/android/strictmode/app/build.gradle | 8 ++++---- examples/build.gradle | 2 +- examples/example-alts/build.gradle | 2 +- examples/example-gauth/build.gradle | 2 +- examples/example-gauth/pom.xml | 4 ++-- examples/example-hostname/build.gradle | 2 +- examples/example-hostname/pom.xml | 4 ++-- examples/example-jwt-auth/build.gradle | 2 +- examples/example-jwt-auth/pom.xml | 4 ++-- examples/example-orca/build.gradle | 2 +- examples/example-tls/build.gradle | 2 +- examples/example-tls/pom.xml | 4 ++-- examples/example-xds/build.gradle | 2 +- examples/pom.xml | 4 ++-- 23 files changed, 41 insertions(+), 41 deletions(-) diff --git a/build.gradle b/build.gradle index 21068ba522d..8ae24adbdb8 100644 --- a/build.gradle +++ b/build.gradle @@ -20,7 +20,7 @@ subprojects { apply plugin: "net.ltgt.errorprone" group = "io.grpc" - version = "1.51.0-SNAPSHOT" // CURRENT_GRPC_VERSION + version = "1.52.0-SNAPSHOT" // CURRENT_GRPC_VERSION repositories { maven { // The google mirror is less flaky than mavenCentral() diff --git a/compiler/src/test/golden/TestDeprecatedService.java.txt b/compiler/src/test/golden/TestDeprecatedService.java.txt index 7c8fa57714d..b3ca789493e 100644 --- a/compiler/src/test/golden/TestDeprecatedService.java.txt +++ b/compiler/src/test/golden/TestDeprecatedService.java.txt @@ -8,7 +8,7 @@ import static io.grpc.MethodDescriptor.generateFullMethodName; * */ @javax.annotation.Generated( - value = "by gRPC proto compiler (version 1.51.0-SNAPSHOT)", + value = "by gRPC proto compiler (version 1.52.0-SNAPSHOT)", comments = "Source: grpc/testing/compiler/test.proto") @io.grpc.stub.annotations.GrpcGenerated @java.lang.Deprecated diff --git a/compiler/src/test/golden/TestService.java.txt b/compiler/src/test/golden/TestService.java.txt index d87bc631256..6ccfb179592 100644 --- a/compiler/src/test/golden/TestService.java.txt +++ b/compiler/src/test/golden/TestService.java.txt @@ -8,7 +8,7 @@ import static io.grpc.MethodDescriptor.generateFullMethodName; * */ @javax.annotation.Generated( - value = "by gRPC proto compiler (version 1.51.0-SNAPSHOT)", + value = "by gRPC proto compiler (version 1.52.0-SNAPSHOT)", comments = "Source: grpc/testing/compiler/test.proto") @io.grpc.stub.annotations.GrpcGenerated public final class TestServiceGrpc { diff --git a/compiler/src/testLite/golden/TestDeprecatedService.java.txt b/compiler/src/testLite/golden/TestDeprecatedService.java.txt index dcd6f4e4bd5..a6b7dac6dfc 100644 --- a/compiler/src/testLite/golden/TestDeprecatedService.java.txt +++ b/compiler/src/testLite/golden/TestDeprecatedService.java.txt @@ -8,7 +8,7 @@ import static io.grpc.MethodDescriptor.generateFullMethodName; * */ @javax.annotation.Generated( - value = "by gRPC proto compiler (version 1.51.0-SNAPSHOT)", + value = "by gRPC proto compiler (version 1.52.0-SNAPSHOT)", comments = "Source: grpc/testing/compiler/test.proto") @io.grpc.stub.annotations.GrpcGenerated @java.lang.Deprecated diff --git a/compiler/src/testLite/golden/TestService.java.txt b/compiler/src/testLite/golden/TestService.java.txt index fdf75a9bf9a..abdd0a4751c 100644 --- a/compiler/src/testLite/golden/TestService.java.txt +++ b/compiler/src/testLite/golden/TestService.java.txt @@ -8,7 +8,7 @@ import static io.grpc.MethodDescriptor.generateFullMethodName; * */ @javax.annotation.Generated( - value = "by gRPC proto compiler (version 1.51.0-SNAPSHOT)", + value = "by gRPC proto compiler (version 1.52.0-SNAPSHOT)", comments = "Source: grpc/testing/compiler/test.proto") @io.grpc.stub.annotations.GrpcGenerated public final class TestServiceGrpc { diff --git a/core/src/main/java/io/grpc/internal/GrpcUtil.java b/core/src/main/java/io/grpc/internal/GrpcUtil.java index 0159a0b5275..dc96a880b11 100644 --- a/core/src/main/java/io/grpc/internal/GrpcUtil.java +++ b/core/src/main/java/io/grpc/internal/GrpcUtil.java @@ -217,7 +217,7 @@ public byte[] parseAsciiString(byte[] serialized) { public static final Splitter ACCEPT_ENCODING_SPLITTER = Splitter.on(',').trimResults(); - private static final String IMPLEMENTATION_VERSION = "1.51.0-SNAPSHOT"; // CURRENT_GRPC_VERSION + private static final String IMPLEMENTATION_VERSION = "1.52.0-SNAPSHOT"; // CURRENT_GRPC_VERSION /** * The default timeout in nanos for a keepalive ping request. diff --git a/examples/android/clientcache/app/build.gradle b/examples/android/clientcache/app/build.gradle index 827609afe8d..50317384e10 100644 --- a/examples/android/clientcache/app/build.gradle +++ b/examples/android/clientcache/app/build.gradle @@ -34,7 +34,7 @@ android { protobuf { protoc { artifact = 'com.google.protobuf:protoc:3.21.7' } plugins { - grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.51.0-SNAPSHOT' // CURRENT_GRPC_VERSION + grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION } } generateProtoTasks { @@ -54,12 +54,12 @@ dependencies { implementation 'com.android.support:appcompat-v7:27.0.2' // You need to build grpc-java to obtain these libraries below. - implementation 'io.grpc:grpc-okhttp:1.51.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-protobuf-lite:1.51.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-stub:1.51.0-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-okhttp:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-protobuf-lite:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-stub:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION implementation 'org.apache.tomcat:annotations-api:6.0.53' testImplementation 'junit:junit:4.12' testImplementation 'com.google.truth:truth:1.0.1' - testImplementation 'io.grpc:grpc-testing:1.51.0-SNAPSHOT' // CURRENT_GRPC_VERSION + testImplementation 'io.grpc:grpc-testing:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION } diff --git a/examples/android/helloworld/app/build.gradle b/examples/android/helloworld/app/build.gradle index 94e86df7f30..a7af5710c85 100644 --- a/examples/android/helloworld/app/build.gradle +++ b/examples/android/helloworld/app/build.gradle @@ -32,7 +32,7 @@ android { protobuf { protoc { artifact = 'com.google.protobuf:protoc:3.21.7' } plugins { - grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.51.0-SNAPSHOT' // CURRENT_GRPC_VERSION + grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION } } generateProtoTasks { @@ -52,8 +52,8 @@ dependencies { implementation 'com.android.support:appcompat-v7:27.0.2' // You need to build grpc-java to obtain these libraries below. - implementation 'io.grpc:grpc-okhttp:1.51.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-protobuf-lite:1.51.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-stub:1.51.0-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-okhttp:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-protobuf-lite:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-stub:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION implementation 'org.apache.tomcat:annotations-api:6.0.53' } diff --git a/examples/android/routeguide/app/build.gradle b/examples/android/routeguide/app/build.gradle index 953a14c2a73..45ecf397124 100644 --- a/examples/android/routeguide/app/build.gradle +++ b/examples/android/routeguide/app/build.gradle @@ -32,7 +32,7 @@ android { protobuf { protoc { artifact = 'com.google.protobuf:protoc:3.21.7' } plugins { - grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.51.0-SNAPSHOT' // CURRENT_GRPC_VERSION + grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION } } generateProtoTasks { @@ -52,8 +52,8 @@ dependencies { implementation 'com.android.support:appcompat-v7:27.0.2' // You need to build grpc-java to obtain these libraries below. - implementation 'io.grpc:grpc-okhttp:1.51.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-protobuf-lite:1.51.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-stub:1.51.0-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-okhttp:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-protobuf-lite:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-stub:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION implementation 'org.apache.tomcat:annotations-api:6.0.53' } diff --git a/examples/android/strictmode/app/build.gradle b/examples/android/strictmode/app/build.gradle index fa70153bcb4..cb08cc3454d 100644 --- a/examples/android/strictmode/app/build.gradle +++ b/examples/android/strictmode/app/build.gradle @@ -33,7 +33,7 @@ android { protobuf { protoc { artifact = 'com.google.protobuf:protoc:3.21.7' } plugins { - grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.51.0-SNAPSHOT' // CURRENT_GRPC_VERSION + grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION } } generateProtoTasks { @@ -53,8 +53,8 @@ dependencies { implementation 'com.android.support:appcompat-v7:28.0.0' // You need to build grpc-java to obtain these libraries below. - implementation 'io.grpc:grpc-okhttp:1.51.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-protobuf-lite:1.51.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-stub:1.51.0-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-okhttp:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-protobuf-lite:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-stub:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION implementation 'org.apache.tomcat:annotations-api:6.0.53' } diff --git a/examples/build.gradle b/examples/build.gradle index 89e066d0680..db21f6edd2e 100644 --- a/examples/build.gradle +++ b/examples/build.gradle @@ -22,7 +22,7 @@ targetCompatibility = 1.8 // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.51.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION def protobufVersion = '3.21.7' def protocVersion = protobufVersion diff --git a/examples/example-alts/build.gradle b/examples/example-alts/build.gradle index eb8fa418068..17696edafc8 100644 --- a/examples/example-alts/build.gradle +++ b/examples/example-alts/build.gradle @@ -23,7 +23,7 @@ targetCompatibility = 1.8 // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.51.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION def protocVersion = '3.21.7' dependencies { diff --git a/examples/example-gauth/build.gradle b/examples/example-gauth/build.gradle index 448ec374fdf..65a44069368 100644 --- a/examples/example-gauth/build.gradle +++ b/examples/example-gauth/build.gradle @@ -23,7 +23,7 @@ targetCompatibility = 1.8 // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.51.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION def protobufVersion = '3.21.7' def protocVersion = protobufVersion diff --git a/examples/example-gauth/pom.xml b/examples/example-gauth/pom.xml index 9f36e0e98b2..fbda89ee251 100644 --- a/examples/example-gauth/pom.xml +++ b/examples/example-gauth/pom.xml @@ -6,13 +6,13 @@ jar - 1.51.0-SNAPSHOT + 1.52.0-SNAPSHOT example-gauth https://github.com/grpc/grpc-java UTF-8 - 1.51.0-SNAPSHOT + 1.52.0-SNAPSHOT 3.21.7 1.7 diff --git a/examples/example-hostname/build.gradle b/examples/example-hostname/build.gradle index c3051b99264..52612623673 100644 --- a/examples/example-hostname/build.gradle +++ b/examples/example-hostname/build.gradle @@ -21,7 +21,7 @@ targetCompatibility = 1.8 // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.51.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION def protobufVersion = '3.21.7' dependencies { diff --git a/examples/example-hostname/pom.xml b/examples/example-hostname/pom.xml index e111c244f6f..224a8a99c41 100644 --- a/examples/example-hostname/pom.xml +++ b/examples/example-hostname/pom.xml @@ -6,13 +6,13 @@ jar - 1.51.0-SNAPSHOT + 1.52.0-SNAPSHOT example-hostname https://github.com/grpc/grpc-java UTF-8 - 1.51.0-SNAPSHOT + 1.52.0-SNAPSHOT 3.21.7 1.7 diff --git a/examples/example-jwt-auth/build.gradle b/examples/example-jwt-auth/build.gradle index 968ad9ca385..6493238c7be 100644 --- a/examples/example-jwt-auth/build.gradle +++ b/examples/example-jwt-auth/build.gradle @@ -22,7 +22,7 @@ targetCompatibility = 1.8 // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.51.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION def protobufVersion = '3.21.7' def protocVersion = protobufVersion diff --git a/examples/example-jwt-auth/pom.xml b/examples/example-jwt-auth/pom.xml index d6223b1e0d0..6bd4c0331d1 100644 --- a/examples/example-jwt-auth/pom.xml +++ b/examples/example-jwt-auth/pom.xml @@ -7,13 +7,13 @@ jar - 1.51.0-SNAPSHOT + 1.52.0-SNAPSHOT example-jwt-auth https://github.com/grpc/grpc-java UTF-8 - 1.51.0-SNAPSHOT + 1.52.0-SNAPSHOT 3.21.7 3.21.7 diff --git a/examples/example-orca/build.gradle b/examples/example-orca/build.gradle index ba2acf222bf..abd9201a26c 100644 --- a/examples/example-orca/build.gradle +++ b/examples/example-orca/build.gradle @@ -17,7 +17,7 @@ repositories { sourceCompatibility = 1.8 targetCompatibility = 1.8 -def grpcVersion = '1.51.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION def protocVersion = '3.21.7' dependencies { diff --git a/examples/example-tls/build.gradle b/examples/example-tls/build.gradle index 66365ce2a70..0181e802598 100644 --- a/examples/example-tls/build.gradle +++ b/examples/example-tls/build.gradle @@ -23,7 +23,7 @@ targetCompatibility = 1.8 // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.51.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION def protocVersion = '3.21.7' dependencies { diff --git a/examples/example-tls/pom.xml b/examples/example-tls/pom.xml index e3573aaa25d..ea87202b57e 100644 --- a/examples/example-tls/pom.xml +++ b/examples/example-tls/pom.xml @@ -6,13 +6,13 @@ jar - 1.51.0-SNAPSHOT + 1.52.0-SNAPSHOT example-tls https://github.com/grpc/grpc-java UTF-8 - 1.51.0-SNAPSHOT + 1.52.0-SNAPSHOT 3.21.7 2.0.54.Final diff --git a/examples/example-xds/build.gradle b/examples/example-xds/build.gradle index 6acbaa35f59..cc89381fa9d 100644 --- a/examples/example-xds/build.gradle +++ b/examples/example-xds/build.gradle @@ -22,7 +22,7 @@ targetCompatibility = 1.8 // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.51.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION def nettyTcNativeVersion = '2.0.31.Final' def protocVersion = '3.21.7' diff --git a/examples/pom.xml b/examples/pom.xml index b6631152bd9..c4ecdfe4f93 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -6,13 +6,13 @@ jar - 1.51.0-SNAPSHOT + 1.52.0-SNAPSHOT examples https://github.com/grpc/grpc-java UTF-8 - 1.51.0-SNAPSHOT + 1.52.0-SNAPSHOT 3.21.7 3.21.7 From b8f142c1e774d2438193f73c31df44a8edab59fa Mon Sep 17 00:00:00 2001 From: RapperCL <775523362@qq.com> Date: Fri, 21 Oct 2022 19:55:38 +0800 Subject: [PATCH 02/39] reduce redundant judgment --- api/src/main/java/io/grpc/LoadBalancerRegistry.java | 4 +--- api/src/main/java/io/grpc/ManagedChannelRegistry.java | 4 +--- api/src/main/java/io/grpc/NameResolverRegistry.java | 4 +--- api/src/main/java/io/grpc/ServerRegistry.java | 4 +--- 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/api/src/main/java/io/grpc/LoadBalancerRegistry.java b/api/src/main/java/io/grpc/LoadBalancerRegistry.java index a215c4108d1..f6b69f978b8 100644 --- a/api/src/main/java/io/grpc/LoadBalancerRegistry.java +++ b/api/src/main/java/io/grpc/LoadBalancerRegistry.java @@ -107,9 +107,7 @@ public static synchronized LoadBalancerRegistry getDefaultRegistry() { instance = new LoadBalancerRegistry(); for (LoadBalancerProvider provider : providerList) { logger.fine("Service loader found " + provider); - if (provider.isAvailable()) { - instance.addProvider(provider); - } + instance.addProvider(provider); } instance.refreshProviderMap(); } diff --git a/api/src/main/java/io/grpc/ManagedChannelRegistry.java b/api/src/main/java/io/grpc/ManagedChannelRegistry.java index 52a19d55ecb..04bdc6b0d57 100644 --- a/api/src/main/java/io/grpc/ManagedChannelRegistry.java +++ b/api/src/main/java/io/grpc/ManagedChannelRegistry.java @@ -106,9 +106,7 @@ public static synchronized ManagedChannelRegistry getDefaultRegistry() { instance = new ManagedChannelRegistry(); for (ManagedChannelProvider provider : providerList) { logger.fine("Service loader found " + provider); - if (provider.isAvailable()) { - instance.addProvider(provider); - } + instance.addProvider(provider); } instance.refreshProviders(); } diff --git a/api/src/main/java/io/grpc/NameResolverRegistry.java b/api/src/main/java/io/grpc/NameResolverRegistry.java index 2e12bb77483..ab8a1e803eb 100644 --- a/api/src/main/java/io/grpc/NameResolverRegistry.java +++ b/api/src/main/java/io/grpc/NameResolverRegistry.java @@ -124,9 +124,7 @@ public static synchronized NameResolverRegistry getDefaultRegistry() { instance = new NameResolverRegistry(); for (NameResolverProvider provider : providerList) { logger.fine("Service loader found " + provider); - if (provider.isAvailable()) { - instance.addProvider(provider); - } + instance.addProvider(provider); } instance.refreshProviders(); } diff --git a/api/src/main/java/io/grpc/ServerRegistry.java b/api/src/main/java/io/grpc/ServerRegistry.java index e40039fb34c..e6a067ce87f 100644 --- a/api/src/main/java/io/grpc/ServerRegistry.java +++ b/api/src/main/java/io/grpc/ServerRegistry.java @@ -98,9 +98,7 @@ public static synchronized ServerRegistry getDefaultRegistry() { instance = new ServerRegistry(); for (ServerProvider provider : providerList) { logger.fine("Service loader found " + provider); - if (provider.isAvailable()) { - instance.addProvider(provider); - } + instance.addProvider(provider); } instance.refreshProviders(); } From 096898a46e8f15ce5eca07ee5231fcc458487202 Mon Sep 17 00:00:00 2001 From: RapperCL <44110731+RapperCL@users.noreply.github.com> Date: Fri, 11 Nov 2022 08:15:13 +0800 Subject: [PATCH 03/39] ManagedChannelImpl.SubchannelImpl args check bug (#9651) Previously it could trigger NPE without the string saying which argument was null. --- core/src/main/java/io/grpc/internal/ManagedChannelImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java b/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java index 9cc7d70d1e7..0311a6d2e34 100644 --- a/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java +++ b/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java @@ -1942,13 +1942,14 @@ private final class SubchannelImpl extends AbstractSubchannel { ScheduledHandle delayedShutdownTask; SubchannelImpl(CreateSubchannelArgs args, LbHelperImpl helper) { + checkNotNull(args, "args"); addressGroups = args.getAddresses(); if (authorityOverride != null) { List eagsWithoutOverrideAttr = stripOverrideAuthorityAttributes(args.getAddresses()); args = args.toBuilder().setAddresses(eagsWithoutOverrideAttr).build(); } - this.args = checkNotNull(args, "args"); + this.args = args; this.helper = checkNotNull(helper, "helper"); subchannelLogId = InternalLogId.allocate("Subchannel", /*details=*/ authority()); subchannelTracer = new ChannelTracer( From 80cd7ec4577738a553f596fb13dfa287871f7e83 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Wed, 16 Nov 2022 13:01:59 -0800 Subject: [PATCH 04/39] bazel: Migrate from `cfg = "host"` to `cfg = "exec"` (#9695) This change migrates from `cfg = "host"` to `cfg = "exec"`. This is a no-op cleanup: `cfg = "host"` is a deprecated alias for `cfg = "exec"`. Tested: ``` bazel build //grpclb:grpclb bazel build //compiler:java_grpc_library_toolchain bazel build //compiler:grpc_java_plugin bazel build '//compiler:*' ``` Internal ref cl/487924699 --- java_grpc_library.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java_grpc_library.bzl b/java_grpc_library.bzl index 237fd2fb7a5..51e4f6996e8 100644 --- a/java_grpc_library.bzl +++ b/java_grpc_library.bzl @@ -30,12 +30,12 @@ java_rpc_toolchain = rule( providers = [JavaInfo], ), "plugin": attr.label( - cfg = "host", + cfg = "exec", executable = True, ), "plugin_arg": attr.string(), "_protoc": attr.label( - cfg = "host", + cfg = "exec", default = Label("@com_google_protobuf//:protoc"), executable = True, ), From 1241946c15ce4b44af2302600b18fd9777dfd1e9 Mon Sep 17 00:00:00 2001 From: Justin Bassett Date: Tue, 25 Oct 2022 11:38:58 -0700 Subject: [PATCH 05/39] Always update the TagContext in filterContext() This is a potential optimization, depending on the OpenCensus implementation installed. Currently, the code checks TagContext equality against the empty TagContext as an optimization to avoid updating the Context, but checking equality may not be cheaper than updating the Context. In particular, this condition is almost always true, because we [update the parentCtx with an additional tag](https://github.com/grpc/grpc-java/blob/bacf18db8dcfbf50006eadaac1693fbce74bc550/census/src/main/java/io/grpc/census/CensusStatsModule.java#L770-L774). It's only true when there is no OpenCensus implementation (i.e. some kind of no-op implementation that ignores TagContexts) or when the empty TagContext already has that tag set to the specific value which varies depending on the RPC method. For the default OpenCensus implementation, the equality check is equality between two maps. Other implementations may require additional work to determine equality. Basically, we are trading off rarely avoiding updating the Context for always doing at least a map equality or potentially even more depending on the OpenCensus implementation in use. Given this, it makes sense to just always update the Context. --- census/src/main/java/io/grpc/census/CensusStatsModule.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/census/src/main/java/io/grpc/census/CensusStatsModule.java b/census/src/main/java/io/grpc/census/CensusStatsModule.java index d05368f3ee5..03eaf73570d 100644 --- a/census/src/main/java/io/grpc/census/CensusStatsModule.java +++ b/census/src/main/java/io/grpc/census/CensusStatsModule.java @@ -751,10 +751,7 @@ public void streamClosed(Status status) { @Override public Context filterContext(Context context) { - if (!module.tagger.empty().equals(parentCtx)) { - return ContextUtils.withValue(context, parentCtx); - } - return context; + return ContextUtils.withValue(context, parentCtx); } } From 1b94f48dc84f91977b1553a33e8eccbfaffbfb05 Mon Sep 17 00:00:00 2001 From: pandaapo <35672972+pandaapo@users.noreply.github.com> Date: Fri, 18 Nov 2022 05:11:27 +0800 Subject: [PATCH 06/39] api: Fix CallOptions to be properly `@Immutable` (#9689) Although CallOptions is annotated by @Immutable, its fields are not final. So it's not truly immutable, namely not safe for unsynchronized publication. This commit adds final to all fields of CallOptions. Using internal builder class to keep flexibility of constructing CallOptions. Fixes #9658 --- api/src/main/java/io/grpc/CallOptions.java | 160 ++++++++++++--------- 1 file changed, 92 insertions(+), 68 deletions(-) diff --git a/api/src/main/java/io/grpc/CallOptions.java b/api/src/main/java/io/grpc/CallOptions.java index 5c05d5b7bd7..16684275dea 100644 --- a/api/src/main/java/io/grpc/CallOptions.java +++ b/api/src/main/java/io/grpc/CallOptions.java @@ -41,42 +41,68 @@ public final class CallOptions { /** * A blank {@code CallOptions} that all fields are not set. */ - public static final CallOptions DEFAULT = new CallOptions(); + public static final CallOptions DEFAULT = new Builder().build(); - // Although {@code CallOptions} is immutable, its fields are not final, so that we can initialize - // them outside of constructor. Otherwise the constructor will have a potentially long list of - // unnamed arguments, which is undesirable. @Nullable - private Deadline deadline; - + private final Deadline deadline; + @Nullable - private Executor executor; + private final Executor executor; @Nullable - private String authority; + private final String authority; @Nullable - private CallCredentials credentials; + private final CallCredentials credentials; @Nullable - private String compressorName; + private final String compressorName; - private Object[][] customOptions; + private final Object[][] customOptions; - // Unmodifiable list - private List streamTracerFactories = Collections.emptyList(); + private final List streamTracerFactories; /** * Opposite to fail fast. */ @Nullable - private Boolean waitForReady; + private final Boolean waitForReady; @Nullable - private Integer maxInboundMessageSize; + private final Integer maxInboundMessageSize; @Nullable - private Integer maxOutboundMessageSize; + private final Integer maxOutboundMessageSize; + + private CallOptions(Builder builder) { + this.deadline = builder.deadline; + this.executor = builder.executor; + this.authority = builder.authority; + this.credentials = builder.credentials; + this.compressorName = builder.compressorName; + this.customOptions = builder.customOptions; + this.streamTracerFactories = builder.streamTracerFactories; + this.waitForReady = builder.waitForReady; + this.maxInboundMessageSize = builder.maxInboundMessageSize; + this.maxOutboundMessageSize = builder.maxOutboundMessageSize; + } + static class Builder { + Deadline deadline; + Executor executor; + String authority; + CallCredentials credentials; + String compressorName; + Object[][] customOptions = new Object[0][2]; + // Unmodifiable list + List streamTracerFactories = Collections.emptyList(); + Boolean waitForReady; + Integer maxInboundMessageSize; + Integer maxOutboundMessageSize; + + private CallOptions build() { + return new CallOptions(this); + } + } /** * Override the HTTP/2 authority the channel claims to be connecting to. This is not @@ -89,18 +115,18 @@ public final class CallOptions { */ @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1767") public CallOptions withAuthority(@Nullable String authority) { - CallOptions newOptions = new CallOptions(this); - newOptions.authority = authority; - return newOptions; + Builder builder = toBuilder(this); + builder.authority = authority; + return builder.build(); } /** * Returns a new {@code CallOptions} with the given call credentials. */ public CallOptions withCallCredentials(@Nullable CallCredentials credentials) { - CallOptions newOptions = new CallOptions(this); - newOptions.credentials = credentials; - return newOptions; + Builder builder = toBuilder(this); + builder.credentials = credentials; + return builder.build(); } /** @@ -113,9 +139,9 @@ public CallOptions withCallCredentials(@Nullable CallCredentials credentials) { */ @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1704") public CallOptions withCompression(@Nullable String compressorName) { - CallOptions newOptions = new CallOptions(this); - newOptions.compressorName = compressorName; - return newOptions; + Builder builder = toBuilder(this); + builder.compressorName = compressorName; + return builder.build(); } /** @@ -127,9 +153,9 @@ public CallOptions withCompression(@Nullable String compressorName) { * @param deadline the deadline or {@code null} for unsetting the deadline. */ public CallOptions withDeadline(@Nullable Deadline deadline) { - CallOptions newOptions = new CallOptions(this); - newOptions.deadline = deadline; - return newOptions; + Builder builder = toBuilder(this); + builder.deadline = deadline; + return builder.build(); } /** @@ -156,9 +182,9 @@ public Deadline getDeadline() { * fails RPCs without sending them if unable to connect. */ public CallOptions withWaitForReady() { - CallOptions newOptions = new CallOptions(this); - newOptions.waitForReady = Boolean.TRUE; - return newOptions; + Builder builder = toBuilder(this); + builder.waitForReady = Boolean.TRUE; + return builder.build(); } /** @@ -166,9 +192,9 @@ public CallOptions withWaitForReady() { * This method should be rarely used because the default is without 'wait for ready'. */ public CallOptions withoutWaitForReady() { - CallOptions newOptions = new CallOptions(this); - newOptions.waitForReady = Boolean.FALSE; - return newOptions; + Builder builder = toBuilder(this); + builder.waitForReady = Boolean.FALSE; + return builder.build(); } /** @@ -208,9 +234,9 @@ public CallCredentials getCredentials() { * executor specified with {@link ManagedChannelBuilder#executor}. */ public CallOptions withExecutor(@Nullable Executor executor) { - CallOptions newOptions = new CallOptions(this); - newOptions.executor = executor; - return newOptions; + Builder builder = toBuilder(this); + builder.executor = executor; + return builder.build(); } /** @@ -221,13 +247,13 @@ public CallOptions withExecutor(@Nullable Executor executor) { */ @ExperimentalApi("https://github.com/grpc/grpc-java/issues/2861") public CallOptions withStreamTracerFactory(ClientStreamTracer.Factory factory) { - CallOptions newOptions = new CallOptions(this); ArrayList newList = new ArrayList<>(streamTracerFactories.size() + 1); newList.addAll(streamTracerFactories); newList.add(factory); - newOptions.streamTracerFactories = Collections.unmodifiableList(newList); - return newOptions; + Builder builder = toBuilder(this); + builder.streamTracerFactories = Collections.unmodifiableList(newList); + return builder.build(); } /** @@ -319,7 +345,7 @@ public CallOptions withOption(Key key, T value) { Preconditions.checkNotNull(key, "key"); Preconditions.checkNotNull(value, "value"); - CallOptions newOptions = new CallOptions(this); + Builder builder = toBuilder(this); int existingIdx = -1; for (int i = 0; i < customOptions.length; i++) { if (key.equals(customOptions[i][0])) { @@ -328,18 +354,18 @@ public CallOptions withOption(Key key, T value) { } } - newOptions.customOptions = new Object[customOptions.length + (existingIdx == -1 ? 1 : 0)][2]; - System.arraycopy(customOptions, 0, newOptions.customOptions, 0, customOptions.length); + builder.customOptions = new Object[customOptions.length + (existingIdx == -1 ? 1 : 0)][2]; + System.arraycopy(customOptions, 0, builder.customOptions, 0, customOptions.length); if (existingIdx == -1) { // Add a new option - newOptions.customOptions[customOptions.length] = new Object[] {key, value}; + builder.customOptions[customOptions.length] = new Object[] {key, value}; } else { // Replace an existing option - newOptions.customOptions[existingIdx] = new Object[] {key, value}; + builder.customOptions[existingIdx] = new Object[] {key, value}; } - return newOptions; + return builder.build(); } /** @@ -368,10 +394,6 @@ public Executor getExecutor() { return executor; } - private CallOptions() { - customOptions = new Object[0][2]; - } - /** * Returns whether * 'wait for ready' option is enabled for the call. 'Fail fast' is the default option for gRPC @@ -392,9 +414,9 @@ Boolean getWaitForReady() { @ExperimentalApi("https://github.com/grpc/grpc-java/issues/2563") public CallOptions withMaxInboundMessageSize(int maxSize) { checkArgument(maxSize >= 0, "invalid maxsize %s", maxSize); - CallOptions newOptions = new CallOptions(this); - newOptions.maxInboundMessageSize = maxSize; - return newOptions; + Builder builder = toBuilder(this); + builder.maxInboundMessageSize = maxSize; + return builder.build(); } /** @@ -403,9 +425,9 @@ public CallOptions withMaxInboundMessageSize(int maxSize) { @ExperimentalApi("https://github.com/grpc/grpc-java/issues/2563") public CallOptions withMaxOutboundMessageSize(int maxSize) { checkArgument(maxSize >= 0, "invalid maxsize %s", maxSize); - CallOptions newOptions = new CallOptions(this); - newOptions.maxOutboundMessageSize = maxSize; - return newOptions; + Builder builder = toBuilder(this); + builder.maxOutboundMessageSize = maxSize; + return builder.build(); } /** @@ -427,19 +449,21 @@ public Integer getMaxOutboundMessageSize() { } /** - * Copy constructor. + * Copy CallOptions. */ - private CallOptions(CallOptions other) { - deadline = other.deadline; - authority = other.authority; - credentials = other.credentials; - executor = other.executor; - compressorName = other.compressorName; - customOptions = other.customOptions; - waitForReady = other.waitForReady; - maxInboundMessageSize = other.maxInboundMessageSize; - maxOutboundMessageSize = other.maxOutboundMessageSize; - streamTracerFactories = other.streamTracerFactories; + private static Builder toBuilder(CallOptions other) { + Builder builder = new Builder(); + builder.deadline = other.deadline; + builder.executor = other.executor; + builder.authority = other.authority; + builder.credentials = other.credentials; + builder.compressorName = other.compressorName; + builder.customOptions = other.customOptions; + builder.streamTracerFactories = other.streamTracerFactories; + builder.waitForReady = other.waitForReady; + builder.maxInboundMessageSize = other.maxInboundMessageSize; + builder.maxOutboundMessageSize = other.maxOutboundMessageSize; + return builder; } @Override From 775d79b0eb1717f381ebb698f5302db702f6200c Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Wed, 16 Nov 2022 11:48:39 -0800 Subject: [PATCH 07/39] Update README etc to reference 1.51.0 --- README.md | 30 ++++++++++++------------ cronet/README.md | 2 +- documentation/android-channel-builder.md | 4 ++-- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index f4397b34353..2c18763b180 100644 --- a/README.md +++ b/README.md @@ -31,8 +31,8 @@ For a guided tour, take a look at the [quick start guide](https://grpc.io/docs/languages/java/quickstart) or the more explanatory [gRPC basics](https://grpc.io/docs/languages/java/basics). -The [examples](https://github.com/grpc/grpc-java/tree/v1.50.2/examples) and the -[Android example](https://github.com/grpc/grpc-java/tree/v1.50.2/examples/android) +The [examples](https://github.com/grpc/grpc-java/tree/v1.51.0/examples) and the +[Android example](https://github.com/grpc/grpc-java/tree/v1.51.0/examples/android) are standalone projects that showcase the usage of gRPC. Download @@ -43,18 +43,18 @@ Download [the JARs][]. Or for Maven with non-Android, add to your `pom.xml`: io.grpc grpc-netty-shaded - 1.50.2 + 1.51.0 runtime io.grpc grpc-protobuf - 1.50.2 + 1.51.0 io.grpc grpc-stub - 1.50.2 + 1.51.0 org.apache.tomcat @@ -66,23 +66,23 @@ Download [the JARs][]. Or for Maven with non-Android, add to your `pom.xml`: Or for Gradle with non-Android, add to your dependencies: ```gradle -runtimeOnly 'io.grpc:grpc-netty-shaded:1.50.2' -implementation 'io.grpc:grpc-protobuf:1.50.2' -implementation 'io.grpc:grpc-stub:1.50.2' +runtimeOnly 'io.grpc:grpc-netty-shaded:1.51.0' +implementation 'io.grpc:grpc-protobuf:1.51.0' +implementation 'io.grpc:grpc-stub:1.51.0' compileOnly 'org.apache.tomcat:annotations-api:6.0.53' // necessary for Java 9+ ``` For Android client, use `grpc-okhttp` instead of `grpc-netty-shaded` and `grpc-protobuf-lite` instead of `grpc-protobuf`: ```gradle -implementation 'io.grpc:grpc-okhttp:1.50.2' -implementation 'io.grpc:grpc-protobuf-lite:1.50.2' -implementation 'io.grpc:grpc-stub:1.50.2' +implementation 'io.grpc:grpc-okhttp:1.51.0' +implementation 'io.grpc:grpc-protobuf-lite:1.51.0' +implementation 'io.grpc:grpc-stub:1.51.0' compileOnly 'org.apache.tomcat:annotations-api:6.0.53' // necessary for Java 9+ ``` [the JARs]: -https://search.maven.org/search?q=g:io.grpc%20AND%20v:1.50.2 +https://search.maven.org/search?q=g:io.grpc%20AND%20v:1.51.0 Development snapshots are available in [Sonatypes's snapshot repository](https://oss.sonatype.org/content/repositories/snapshots/). @@ -114,7 +114,7 @@ For protobuf-based codegen integrated with the Maven build system, you can use com.google.protobuf:protoc:3.21.7:exe:${os.detected.classifier} grpc-java - io.grpc:protoc-gen-grpc-java:1.50.2:exe:${os.detected.classifier} + io.grpc:protoc-gen-grpc-java:1.51.0:exe:${os.detected.classifier} @@ -144,7 +144,7 @@ protobuf { } plugins { grpc { - artifact = 'io.grpc:protoc-gen-grpc-java:1.50.2' + artifact = 'io.grpc:protoc-gen-grpc-java:1.51.0' } } generateProtoTasks { @@ -177,7 +177,7 @@ protobuf { } plugins { grpc { - artifact = 'io.grpc:protoc-gen-grpc-java:1.50.2' + artifact = 'io.grpc:protoc-gen-grpc-java:1.51.0' } } generateProtoTasks { diff --git a/cronet/README.md b/cronet/README.md index e871a64ffbe..b29d19c99b6 100644 --- a/cronet/README.md +++ b/cronet/README.md @@ -26,7 +26,7 @@ In your app module's `build.gradle` file, include a dependency on both `grpc-cro Google Play Services Client Library for Cronet ``` -implementation 'io.grpc:grpc-cronet:1.50.2' +implementation 'io.grpc:grpc-cronet:1.51.0' implementation 'com.google.android.gms:play-services-cronet:16.0.0' ``` diff --git a/documentation/android-channel-builder.md b/documentation/android-channel-builder.md index 46dd67504f2..82bfff47e91 100644 --- a/documentation/android-channel-builder.md +++ b/documentation/android-channel-builder.md @@ -36,8 +36,8 @@ In your `build.gradle` file, include a dependency on both `grpc-android` and `grpc-okhttp`: ``` -implementation 'io.grpc:grpc-android:1.50.2' -implementation 'io.grpc:grpc-okhttp:1.50.2' +implementation 'io.grpc:grpc-android:1.51.0' +implementation 'io.grpc:grpc-okhttp:1.51.0' ``` You also need permission to access the device's network state in your From 806fb84a57216963e94e873bd86c16dda60a7745 Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Thu, 17 Nov 2022 13:18:30 -0800 Subject: [PATCH 08/39] examples: Swap to Channel/ServerCredentials API This makes it more obvious when plaintext vs TLS is being used and is the preferred API. I did not change the Google Auth example, because it is doing things a weird way and changing it would be more invasive. I also didn't update the Android examples. --- .../io/grpc/examples/alts/HelloWorldAltsClient.java | 6 ++++-- .../io/grpc/examples/alts/HelloWorldAltsServer.java | 5 +++-- .../io/grpc/examples/hostname/HostnameServer.java | 4 +++- .../java/io/grpc/examples/jwtauth/AuthClient.java | 12 +++++------- .../java/io/grpc/examples/jwtauth/AuthServer.java | 5 +++-- .../examples/orca/CustomBackendMetricsClient.java | 6 +++--- .../examples/orca/CustomBackendMetricsServer.java | 5 +++-- .../io/grpc/examples/advanced/HelloJsonClient.java | 6 +++--- .../io/grpc/examples/advanced/HelloJsonServer.java | 5 +++-- .../examples/errorhandling/DetailErrorSample.java | 12 +++++++----- .../examples/errorhandling/ErrorHandlingClient.java | 12 +++++++----- .../experimental/CompressingHelloWorldClient.java | 6 +++--- .../CompressingHelloWorldServerAllMethods.java | 5 +++-- .../CompressingHelloWorldServerPerMethod.java | 5 +++-- .../io/grpc/examples/header/CustomHeaderClient.java | 7 ++++--- .../io/grpc/examples/header/CustomHeaderServer.java | 5 +++-- .../examples/hedging/HedgingHelloWorldClient.java | 9 ++++----- .../examples/hedging/HedgingHelloWorldServer.java | 5 +++-- .../grpc/examples/helloworld/HelloWorldClient.java | 11 ++++++----- .../grpc/examples/helloworld/HelloWorldServer.java | 5 +++-- .../examples/retrying/RetryingHelloWorldClient.java | 8 ++++---- .../examples/retrying/RetryingHelloWorldServer.java | 5 +++-- .../grpc/examples/routeguide/RouteGuideClient.java | 6 ++++-- .../grpc/examples/routeguide/RouteGuideServer.java | 5 ++++- 24 files changed, 91 insertions(+), 69 deletions(-) diff --git a/examples/example-alts/src/main/java/io/grpc/examples/alts/HelloWorldAltsClient.java b/examples/example-alts/src/main/java/io/grpc/examples/alts/HelloWorldAltsClient.java index 96351808b25..991ad777309 100644 --- a/examples/example-alts/src/main/java/io/grpc/examples/alts/HelloWorldAltsClient.java +++ b/examples/example-alts/src/main/java/io/grpc/examples/alts/HelloWorldAltsClient.java @@ -16,7 +16,8 @@ package io.grpc.examples.alts; -import io.grpc.alts.AltsChannelBuilder; +import io.grpc.alts.AltsChannelCredentials; +import io.grpc.Grpc; import io.grpc.ManagedChannel; import io.grpc.examples.helloworld.GreeterGrpc; import io.grpc.examples.helloworld.HelloReply; @@ -81,7 +82,8 @@ private void parseArgs(String[] args) { private void run(String[] args) throws InterruptedException { parseArgs(args); ExecutorService executor = Executors.newFixedThreadPool(1); - ManagedChannel channel = AltsChannelBuilder.forTarget(serverAddress).executor(executor).build(); + ManagedChannel channel = Grpc.newChannelBuilder(serverAddress, AltsChannelCredentials.create()) + .executor(executor).build(); try { GreeterGrpc.GreeterBlockingStub stub = GreeterGrpc.newBlockingStub(channel); HelloReply resp = stub.sayHello(HelloRequest.newBuilder().setName("Waldo").build()); diff --git a/examples/example-alts/src/main/java/io/grpc/examples/alts/HelloWorldAltsServer.java b/examples/example-alts/src/main/java/io/grpc/examples/alts/HelloWorldAltsServer.java index fd662069cfd..6bc5226bf59 100644 --- a/examples/example-alts/src/main/java/io/grpc/examples/alts/HelloWorldAltsServer.java +++ b/examples/example-alts/src/main/java/io/grpc/examples/alts/HelloWorldAltsServer.java @@ -16,7 +16,8 @@ package io.grpc.examples.alts; -import io.grpc.alts.AltsServerBuilder; +import io.grpc.alts.AltsServerCredentials; +import io.grpc.Grpc; import io.grpc.Server; import io.grpc.examples.helloworld.GreeterGrpc.GreeterImplBase; import io.grpc.examples.helloworld.HelloReply; @@ -82,7 +83,7 @@ private void parseArgs(String[] args) { private void start(String[] args) throws IOException, InterruptedException { parseArgs(args); server = - AltsServerBuilder.forPort(port) + Grpc.newServerBuilderForPort(port, AltsServerCredentials.create()) .addService(this) .executor(Executors.newFixedThreadPool(1)) .build(); diff --git a/examples/example-hostname/src/main/java/io/grpc/examples/hostname/HostnameServer.java b/examples/example-hostname/src/main/java/io/grpc/examples/hostname/HostnameServer.java index a6f2175914e..3c63296d7fa 100644 --- a/examples/example-hostname/src/main/java/io/grpc/examples/hostname/HostnameServer.java +++ b/examples/example-hostname/src/main/java/io/grpc/examples/hostname/HostnameServer.java @@ -16,6 +16,8 @@ package io.grpc.examples.hostname; +import io.grpc.Grpc; +import io.grpc.InsecureServerCredentials; import io.grpc.Server; import io.grpc.ServerBuilder; import io.grpc.health.v1.HealthCheckResponse.ServingStatus; @@ -49,7 +51,7 @@ public static void main(String[] args) throws IOException, InterruptedException hostname = args[1]; } HealthStatusManager health = new HealthStatusManager(); - final Server server = ServerBuilder.forPort(port) + final Server server = Grpc.newServerBuilderForPort(port, InsecureServerCredentials.create()) .addService(new HostnameGreeter(hostname)) .addService(ProtoReflectionService.newInstance()) .addService(health.getHealthService()) diff --git a/examples/example-jwt-auth/src/main/java/io/grpc/examples/jwtauth/AuthClient.java b/examples/example-jwt-auth/src/main/java/io/grpc/examples/jwtauth/AuthClient.java index f6ea4c57e45..c5769625807 100644 --- a/examples/example-jwt-auth/src/main/java/io/grpc/examples/jwtauth/AuthClient.java +++ b/examples/example-jwt-auth/src/main/java/io/grpc/examples/jwtauth/AuthClient.java @@ -17,8 +17,9 @@ package io.grpc.examples.jwtauth; import io.grpc.CallCredentials; +import io.grpc.Grpc; +import io.grpc.InsecureChannelCredentials; import io.grpc.ManagedChannel; -import io.grpc.ManagedChannelBuilder; import io.grpc.examples.helloworld.GreeterGrpc; import io.grpc.examples.helloworld.HelloReply; import io.grpc.examples.helloworld.HelloRequest; @@ -42,12 +43,9 @@ public class AuthClient { AuthClient(CallCredentials callCredentials, String host, int port) { this( callCredentials, - ManagedChannelBuilder - .forAddress(host, port) - // Channels are secure by default (via SSL/TLS). For this example we disable TLS - // to avoid needing certificates, but it is recommended to use a secure channel - // while passing credentials. - .usePlaintext() + // For this example we use plaintext to avoid needing certificates, but it is + // recommended to use TlsChannelCredentials. + Grpc.newChannelBuilderForAddress(host, port, InsecureChannelCredentials.create()) .build()); } diff --git a/examples/example-jwt-auth/src/main/java/io/grpc/examples/jwtauth/AuthServer.java b/examples/example-jwt-auth/src/main/java/io/grpc/examples/jwtauth/AuthServer.java index 90e7dff1458..208645e4fad 100644 --- a/examples/example-jwt-auth/src/main/java/io/grpc/examples/jwtauth/AuthServer.java +++ b/examples/example-jwt-auth/src/main/java/io/grpc/examples/jwtauth/AuthServer.java @@ -16,8 +16,9 @@ package io.grpc.examples.jwtauth; +import io.grpc.Grpc; +import io.grpc.InsecureServerCredentials; import io.grpc.Server; -import io.grpc.ServerBuilder; import io.grpc.examples.helloworld.GreeterGrpc; import io.grpc.examples.helloworld.HelloReply; import io.grpc.examples.helloworld.HelloRequest; @@ -41,7 +42,7 @@ public AuthServer(int port) { } private void start() throws IOException { - server = ServerBuilder.forPort(port) + server = Grpc.newServerBuilderForPort(port, InsecureServerCredentials.create()) .addService(new GreeterImpl()) .intercept(new JwtServerInterceptor()) // add the JwtServerInterceptor .build() diff --git a/examples/example-orca/src/main/java/io/grpc/examples/orca/CustomBackendMetricsClient.java b/examples/example-orca/src/main/java/io/grpc/examples/orca/CustomBackendMetricsClient.java index da231bd1f16..66143b44364 100644 --- a/examples/example-orca/src/main/java/io/grpc/examples/orca/CustomBackendMetricsClient.java +++ b/examples/example-orca/src/main/java/io/grpc/examples/orca/CustomBackendMetricsClient.java @@ -19,9 +19,10 @@ import static io.grpc.examples.orca.CustomBackendMetricsLoadBalancerProvider.EXAMPLE_LOAD_BALANCER; import io.grpc.Channel; +import io.grpc.Grpc; +import io.grpc.InsecureChannelCredentials; import io.grpc.LoadBalancerRegistry; import io.grpc.ManagedChannel; -import io.grpc.ManagedChannelBuilder; import io.grpc.StatusRuntimeException; import io.grpc.examples.helloworld.GreeterGrpc; import io.grpc.examples.helloworld.HelloReply; @@ -91,9 +92,8 @@ public static void main(String[] args) throws Exception { LoadBalancerRegistry.getDefaultRegistry().register( new CustomBackendMetricsLoadBalancerProvider()); - ManagedChannel channel = ManagedChannelBuilder.forTarget(target) + ManagedChannel channel = Grpc.newChannelBuilder(target, InsecureChannelCredentials.create()) .defaultLoadBalancingPolicy(EXAMPLE_LOAD_BALANCER) - .usePlaintext() .build(); try { CustomBackendMetricsClient client = new CustomBackendMetricsClient(channel); diff --git a/examples/example-orca/src/main/java/io/grpc/examples/orca/CustomBackendMetricsServer.java b/examples/example-orca/src/main/java/io/grpc/examples/orca/CustomBackendMetricsServer.java index da76b3b5b2c..b04664da363 100644 --- a/examples/example-orca/src/main/java/io/grpc/examples/orca/CustomBackendMetricsServer.java +++ b/examples/example-orca/src/main/java/io/grpc/examples/orca/CustomBackendMetricsServer.java @@ -21,8 +21,9 @@ import io.grpc.examples.helloworld.GreeterGrpc; import io.grpc.examples.helloworld.HelloReply; import io.grpc.examples.helloworld.HelloRequest; +import io.grpc.Grpc; +import io.grpc.InsecureServerCredentials; import io.grpc.Server; -import io.grpc.ServerBuilder; import io.grpc.services.CallMetricRecorder; import io.grpc.services.InternalCallMetricRecorder; import io.grpc.services.MetricRecorder; @@ -57,7 +58,7 @@ private void start() throws IOException { // configuration to be as short as 1s, suitable for test demonstration. BindableService orcaOobService = OrcaServiceImpl.createService(executor, metricRecorder, 1, TimeUnit.SECONDS); - server = ServerBuilder.forPort(port) + server = Grpc.newServerBuilderForPort(port, InsecureServerCredentials.create()) .addService(new GreeterImpl()) // Enable OOB custom backend metrics reporting. .addService(orcaOobService) diff --git a/examples/src/main/java/io/grpc/examples/advanced/HelloJsonClient.java b/examples/src/main/java/io/grpc/examples/advanced/HelloJsonClient.java index 264fe76b7d3..9291e45bafe 100644 --- a/examples/src/main/java/io/grpc/examples/advanced/HelloJsonClient.java +++ b/examples/src/main/java/io/grpc/examples/advanced/HelloJsonClient.java @@ -20,8 +20,9 @@ import io.grpc.CallOptions; import io.grpc.Channel; +import io.grpc.Grpc; +import io.grpc.InsecureChannelCredentials; import io.grpc.ManagedChannel; -import io.grpc.ManagedChannelBuilder; import io.grpc.MethodDescriptor; import io.grpc.StatusRuntimeException; import io.grpc.examples.helloworld.GreeterGrpc; @@ -49,8 +50,7 @@ public final class HelloJsonClient { /** Construct client connecting to HelloWorld server at {@code host:port}. */ public HelloJsonClient(String host, int port) { - channel = ManagedChannelBuilder.forAddress(host, port) - .usePlaintext() + channel = Grpc.newChannelBuilderForAddress(host, port, InsecureChannelCredentials.create()) .build(); blockingStub = new HelloJsonStub(channel); } diff --git a/examples/src/main/java/io/grpc/examples/advanced/HelloJsonServer.java b/examples/src/main/java/io/grpc/examples/advanced/HelloJsonServer.java index 0a656dd52b8..0f4e5d28f16 100644 --- a/examples/src/main/java/io/grpc/examples/advanced/HelloJsonServer.java +++ b/examples/src/main/java/io/grpc/examples/advanced/HelloJsonServer.java @@ -19,8 +19,9 @@ import static io.grpc.stub.ServerCalls.asyncUnaryCall; import io.grpc.BindableService; +import io.grpc.Grpc; +import io.grpc.InsecureServerCredentials; import io.grpc.Server; -import io.grpc.ServerBuilder; import io.grpc.ServerServiceDefinition; import io.grpc.examples.helloworld.GreeterGrpc; import io.grpc.examples.helloworld.HelloReply; @@ -50,7 +51,7 @@ public class HelloJsonServer { private void start() throws IOException { /* The port on which the server should run */ int port = 50051; - server = ServerBuilder.forPort(port) + server = Grpc.newServerBuilderForPort(port, InsecureServerCredentials.create()) .addService(new GreeterImpl()) .build() .start(); diff --git a/examples/src/main/java/io/grpc/examples/errorhandling/DetailErrorSample.java b/examples/src/main/java/io/grpc/examples/errorhandling/DetailErrorSample.java index b743b46b471..b026b6f32dc 100644 --- a/examples/src/main/java/io/grpc/examples/errorhandling/DetailErrorSample.java +++ b/examples/src/main/java/io/grpc/examples/errorhandling/DetailErrorSample.java @@ -27,11 +27,12 @@ import com.google.rpc.DebugInfo; import io.grpc.CallOptions; import io.grpc.ClientCall; +import io.grpc.Grpc; +import io.grpc.InsecureChannelCredentials; +import io.grpc.InsecureServerCredentials; import io.grpc.ManagedChannel; -import io.grpc.ManagedChannelBuilder; import io.grpc.Metadata; import io.grpc.Server; -import io.grpc.ServerBuilder; import io.grpc.Status; import io.grpc.examples.helloworld.GreeterGrpc; import io.grpc.examples.helloworld.GreeterGrpc.GreeterBlockingStub; @@ -73,7 +74,8 @@ public static void main(String[] args) throws Exception { private ManagedChannel channel; void run() throws Exception { - Server server = ServerBuilder.forPort(0).addService(new GreeterGrpc.GreeterImplBase() { + Server server = Grpc.newServerBuilderForPort(0, InsecureServerCredentials.create()) + .addService(new GreeterGrpc.GreeterImplBase() { @Override public void sayHello(HelloRequest request, StreamObserver responseObserver) { Metadata trailers = new Metadata(); @@ -82,8 +84,8 @@ public void sayHello(HelloRequest request, StreamObserver responseOb .asRuntimeException(trailers)); } }).build().start(); - channel = - ManagedChannelBuilder.forAddress("localhost", server.getPort()).usePlaintext().build(); + channel = Grpc.newChannelBuilderForAddress( + "localhost", server.getPort(), InsecureChannelCredentials.create()).build(); blockingCall(); futureCallDirect(); diff --git a/examples/src/main/java/io/grpc/examples/errorhandling/ErrorHandlingClient.java b/examples/src/main/java/io/grpc/examples/errorhandling/ErrorHandlingClient.java index 4afd39b08fa..7e310433a90 100644 --- a/examples/src/main/java/io/grpc/examples/errorhandling/ErrorHandlingClient.java +++ b/examples/src/main/java/io/grpc/examples/errorhandling/ErrorHandlingClient.java @@ -25,11 +25,12 @@ import com.google.common.util.concurrent.Uninterruptibles; import io.grpc.CallOptions; import io.grpc.ClientCall; +import io.grpc.Grpc; +import io.grpc.InsecureChannelCredentials; +import io.grpc.InsecureServerCredentials; import io.grpc.ManagedChannel; -import io.grpc.ManagedChannelBuilder; import io.grpc.Metadata; import io.grpc.Server; -import io.grpc.ServerBuilder; import io.grpc.Status; import io.grpc.examples.helloworld.GreeterGrpc; import io.grpc.examples.helloworld.GreeterGrpc.GreeterBlockingStub; @@ -55,15 +56,16 @@ public static void main(String [] args) throws Exception { void run() throws Exception { // Port 0 means that the operating system will pick an available port to use. - Server server = ServerBuilder.forPort(0).addService(new GreeterGrpc.GreeterImplBase() { + Server server = Grpc.newServerBuilderForPort(0, InsecureServerCredentials.create()) + .addService(new GreeterGrpc.GreeterImplBase() { @Override public void sayHello(HelloRequest request, StreamObserver responseObserver) { responseObserver.onError(Status.INTERNAL .withDescription("Eggplant Xerxes Crybaby Overbite Narwhal").asRuntimeException()); } }).build().start(); - channel = - ManagedChannelBuilder.forAddress("localhost", server.getPort()).usePlaintext().build(); + channel = Grpc.newChannelBuilderForAddress( + "localhost", server.getPort(), InsecureChannelCredentials.create()).build(); blockingCall(); futureCallDirect(); diff --git a/examples/src/main/java/io/grpc/examples/experimental/CompressingHelloWorldClient.java b/examples/src/main/java/io/grpc/examples/experimental/CompressingHelloWorldClient.java index 410b0c7c14c..49e9cb36d53 100644 --- a/examples/src/main/java/io/grpc/examples/experimental/CompressingHelloWorldClient.java +++ b/examples/src/main/java/io/grpc/examples/experimental/CompressingHelloWorldClient.java @@ -16,8 +16,9 @@ package io.grpc.examples.experimental; +import io.grpc.Grpc; +import io.grpc.InsecureChannelCredentials; import io.grpc.ManagedChannel; -import io.grpc.ManagedChannelBuilder; import io.grpc.StatusRuntimeException; import io.grpc.examples.helloworld.GreeterGrpc; import io.grpc.examples.helloworld.HelloReply; @@ -42,8 +43,7 @@ public class CompressingHelloWorldClient { /** Construct client connecting to HelloWorld server at {@code host:port}. */ public CompressingHelloWorldClient(String host, int port) { - channel = ManagedChannelBuilder.forAddress(host, port) - .usePlaintext() + channel = Grpc.newChannelBuilderForAddress(host, port, InsecureChannelCredentials.create()) .build(); blockingStub = GreeterGrpc.newBlockingStub(channel); } diff --git a/examples/src/main/java/io/grpc/examples/experimental/CompressingHelloWorldServerAllMethods.java b/examples/src/main/java/io/grpc/examples/experimental/CompressingHelloWorldServerAllMethods.java index 23c51a6d26c..794d7196f35 100644 --- a/examples/src/main/java/io/grpc/examples/experimental/CompressingHelloWorldServerAllMethods.java +++ b/examples/src/main/java/io/grpc/examples/experimental/CompressingHelloWorldServerAllMethods.java @@ -20,9 +20,10 @@ import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import io.grpc.Grpc; +import io.grpc.InsecureServerCredentials; import io.grpc.Metadata; import io.grpc.Server; -import io.grpc.ServerBuilder; import io.grpc.ServerCall; import io.grpc.ServerCall.Listener; import io.grpc.ServerCallHandler; @@ -44,7 +45,7 @@ public class CompressingHelloWorldServerAllMethods { private void start() throws IOException { /* The port on which the server should run */ int port = 50051; - server = ServerBuilder.forPort(port) + server = Grpc.newServerBuilderForPort(port, InsecureServerCredentials.create()) /* This method call adds the Interceptor to enable compressed server responses for all RPCs */ .intercept(new ServerInterceptor() { @Override diff --git a/examples/src/main/java/io/grpc/examples/experimental/CompressingHelloWorldServerPerMethod.java b/examples/src/main/java/io/grpc/examples/experimental/CompressingHelloWorldServerPerMethod.java index 0ccf38184d3..b7faa96d7b4 100644 --- a/examples/src/main/java/io/grpc/examples/experimental/CompressingHelloWorldServerPerMethod.java +++ b/examples/src/main/java/io/grpc/examples/experimental/CompressingHelloWorldServerPerMethod.java @@ -20,8 +20,9 @@ import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import io.grpc.Grpc; +import io.grpc.InsecureServerCredentials; import io.grpc.Server; -import io.grpc.ServerBuilder; import io.grpc.examples.helloworld.GreeterGrpc; import io.grpc.examples.helloworld.HelloReply; import io.grpc.examples.helloworld.HelloRequest; @@ -40,7 +41,7 @@ public class CompressingHelloWorldServerPerMethod { private void start() throws IOException { /* The port on which the server should run */ int port = 50051; - server = ServerBuilder.forPort(port) + server = Grpc.newServerBuilderForPort(port, InsecureServerCredentials.create()) .addService(new GreeterImpl()) .build() .start(); diff --git a/examples/src/main/java/io/grpc/examples/header/CustomHeaderClient.java b/examples/src/main/java/io/grpc/examples/header/CustomHeaderClient.java index 93d106dba9e..52287040ba0 100644 --- a/examples/src/main/java/io/grpc/examples/header/CustomHeaderClient.java +++ b/examples/src/main/java/io/grpc/examples/header/CustomHeaderClient.java @@ -19,8 +19,9 @@ import io.grpc.Channel; import io.grpc.ClientInterceptor; import io.grpc.ClientInterceptors; +import io.grpc.Grpc; +import io.grpc.InsecureChannelCredentials; import io.grpc.ManagedChannel; -import io.grpc.ManagedChannelBuilder; import io.grpc.StatusRuntimeException; import io.grpc.examples.helloworld.GreeterGrpc; import io.grpc.examples.helloworld.HelloReply; @@ -43,8 +44,8 @@ public class CustomHeaderClient { * A custom client. */ private CustomHeaderClient(String host, int port) { - originChannel = ManagedChannelBuilder.forAddress(host, port) - .usePlaintext() + originChannel = Grpc + .newChannelBuilderForAddress(host, port, InsecureChannelCredentials.create()) .build(); ClientInterceptor interceptor = new HeaderClientInterceptor(); Channel channel = ClientInterceptors.intercept(originChannel, interceptor); diff --git a/examples/src/main/java/io/grpc/examples/header/CustomHeaderServer.java b/examples/src/main/java/io/grpc/examples/header/CustomHeaderServer.java index ae80045603c..75a3d24934f 100644 --- a/examples/src/main/java/io/grpc/examples/header/CustomHeaderServer.java +++ b/examples/src/main/java/io/grpc/examples/header/CustomHeaderServer.java @@ -16,8 +16,9 @@ package io.grpc.examples.header; +import io.grpc.Grpc; +import io.grpc.InsecureServerCredentials; import io.grpc.Server; -import io.grpc.ServerBuilder; import io.grpc.ServerInterceptors; import io.grpc.examples.helloworld.GreeterGrpc; import io.grpc.examples.helloworld.HelloReply; @@ -39,7 +40,7 @@ public class CustomHeaderServer { private Server server; private void start() throws IOException { - server = ServerBuilder.forPort(PORT) + server = Grpc.newServerBuilderForPort(PORT, InsecureServerCredentials.create()) .addService(ServerInterceptors.intercept(new GreeterImpl(), new HeaderServerInterceptor())) .build() .start(); diff --git a/examples/src/main/java/io/grpc/examples/hedging/HedgingHelloWorldClient.java b/examples/src/main/java/io/grpc/examples/hedging/HedgingHelloWorldClient.java index 30f7beb49a0..429cceb50c3 100644 --- a/examples/src/main/java/io/grpc/examples/hedging/HedgingHelloWorldClient.java +++ b/examples/src/main/java/io/grpc/examples/hedging/HedgingHelloWorldClient.java @@ -20,6 +20,8 @@ import com.google.gson.Gson; import com.google.gson.stream.JsonReader; +import io.grpc.Grpc; +import io.grpc.InsecureChannelCredentials; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; import io.grpc.StatusRuntimeException; @@ -51,11 +53,8 @@ public class HedgingHelloWorldClient { /** Construct client connecting to HelloWorld server at {@code host:port}. */ public HedgingHelloWorldClient(String host, int port, boolean hedging) { - - ManagedChannelBuilder channelBuilder = ManagedChannelBuilder.forAddress(host, port) - // Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid - // needing certificates. - .usePlaintext(); + ManagedChannelBuilder channelBuilder + = Grpc.newChannelBuilderForAddress(host, port, InsecureChannelCredentials.create()); if (hedging) { Map hedgingServiceConfig = new Gson() diff --git a/examples/src/main/java/io/grpc/examples/hedging/HedgingHelloWorldServer.java b/examples/src/main/java/io/grpc/examples/hedging/HedgingHelloWorldServer.java index b934e8514ac..784269eea1c 100644 --- a/examples/src/main/java/io/grpc/examples/hedging/HedgingHelloWorldServer.java +++ b/examples/src/main/java/io/grpc/examples/hedging/HedgingHelloWorldServer.java @@ -16,9 +16,10 @@ package io.grpc.examples.hedging; +import io.grpc.Grpc; +import io.grpc.InsecureServerCredentials; import io.grpc.Metadata; import io.grpc.Server; -import io.grpc.ServerBuilder; import io.grpc.ServerCall; import io.grpc.ServerCall.Listener; import io.grpc.ServerCallHandler; @@ -43,7 +44,7 @@ public class HedgingHelloWorldServer { private void start() throws IOException { /* The port on which the server should run */ int port = 50051; - server = ServerBuilder.forPort(port) + server = Grpc.newServerBuilderForPort(port, InsecureServerCredentials.create()) .addService(new GreeterImpl()) .intercept(new LatencyInjectionInterceptor()) .build() diff --git a/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldClient.java b/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldClient.java index d00bca1e216..6b186facf46 100644 --- a/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldClient.java +++ b/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldClient.java @@ -17,8 +17,9 @@ package io.grpc.examples.helloworld; import io.grpc.Channel; +import io.grpc.Grpc; +import io.grpc.InsecureChannelCredentials; import io.grpc.ManagedChannel; -import io.grpc.ManagedChannelBuilder; import io.grpc.StatusRuntimeException; import java.util.concurrent.TimeUnit; import java.util.logging.Level; @@ -81,10 +82,10 @@ public static void main(String[] args) throws Exception { // Create a communication channel to the server, known as a Channel. Channels are thread-safe // and reusable. It is common to create channels at the beginning of your application and reuse // them until the application shuts down. - ManagedChannel channel = ManagedChannelBuilder.forTarget(target) - // Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid - // needing certificates. - .usePlaintext() + // + // For the example we use plaintext insecure credentials to avoid needing TLS certificates. To + // use TLS, use TlsChannelCredentials instead. + ManagedChannel channel = Grpc.newChannelBuilder(target, InsecureChannelCredentials.create()) .build(); try { HelloWorldClient client = new HelloWorldClient(channel); diff --git a/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldServer.java b/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldServer.java index 12836a4c828..81027587031 100644 --- a/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldServer.java +++ b/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldServer.java @@ -16,8 +16,9 @@ package io.grpc.examples.helloworld; +import io.grpc.Grpc; +import io.grpc.InsecureServerCredentials; import io.grpc.Server; -import io.grpc.ServerBuilder; import io.grpc.stub.StreamObserver; import java.io.IOException; import java.util.concurrent.TimeUnit; @@ -34,7 +35,7 @@ public class HelloWorldServer { private void start() throws IOException { /* The port on which the server should run */ int port = 50051; - server = ServerBuilder.forPort(port) + server = Grpc.newServerBuilderForPort(port, InsecureServerCredentials.create()) .addService(new GreeterImpl()) .build() .start(); diff --git a/examples/src/main/java/io/grpc/examples/retrying/RetryingHelloWorldClient.java b/examples/src/main/java/io/grpc/examples/retrying/RetryingHelloWorldClient.java index d8f2e72441b..20c9e5893fb 100644 --- a/examples/src/main/java/io/grpc/examples/retrying/RetryingHelloWorldClient.java +++ b/examples/src/main/java/io/grpc/examples/retrying/RetryingHelloWorldClient.java @@ -20,6 +20,8 @@ import com.google.gson.Gson; import com.google.gson.stream.JsonReader; +import io.grpc.Grpc; +import io.grpc.InsecureChannelCredentials; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; import io.grpc.StatusRuntimeException; @@ -64,10 +66,8 @@ public class RetryingHelloWorldClient { */ public RetryingHelloWorldClient(String host, int port, boolean enableRetries) { - ManagedChannelBuilder channelBuilder = ManagedChannelBuilder.forAddress(host, port) - // Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid - // needing certificates. - .usePlaintext(); + ManagedChannelBuilder channelBuilder + = Grpc.newChannelBuilderForAddress(host, port, InsecureChannelCredentials.create()); if (enableRetries) { Map serviceConfig = getRetryingServiceConfig(); logger.info("Client started with retrying configuration: " + serviceConfig); diff --git a/examples/src/main/java/io/grpc/examples/retrying/RetryingHelloWorldServer.java b/examples/src/main/java/io/grpc/examples/retrying/RetryingHelloWorldServer.java index 0bff00a6988..165cc72ffa3 100644 --- a/examples/src/main/java/io/grpc/examples/retrying/RetryingHelloWorldServer.java +++ b/examples/src/main/java/io/grpc/examples/retrying/RetryingHelloWorldServer.java @@ -19,8 +19,9 @@ import java.text.DecimalFormat; import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; +import io.grpc.Grpc; +import io.grpc.InsecureServerCredentials; import io.grpc.Server; -import io.grpc.ServerBuilder; import io.grpc.Status; import io.grpc.examples.helloworld.GreeterGrpc; import io.grpc.examples.helloworld.HelloReply; @@ -43,7 +44,7 @@ public class RetryingHelloWorldServer { private void start() throws IOException { /* The port on which the server should run */ int port = 50051; - server = ServerBuilder.forPort(port) + server = Grpc.newServerBuilderForPort(port, InsecureServerCredentials.create()) .addService(new GreeterImpl()) .build() .start(); diff --git a/examples/src/main/java/io/grpc/examples/routeguide/RouteGuideClient.java b/examples/src/main/java/io/grpc/examples/routeguide/RouteGuideClient.java index 6958c643da7..f65b1215359 100644 --- a/examples/src/main/java/io/grpc/examples/routeguide/RouteGuideClient.java +++ b/examples/src/main/java/io/grpc/examples/routeguide/RouteGuideClient.java @@ -19,8 +19,9 @@ import com.google.common.annotations.VisibleForTesting; import com.google.protobuf.Message; import io.grpc.Channel; +import io.grpc.Grpc; +import io.grpc.InsecureChannelCredentials; import io.grpc.ManagedChannel; -import io.grpc.ManagedChannelBuilder; import io.grpc.Status; import io.grpc.StatusRuntimeException; import io.grpc.examples.routeguide.RouteGuideGrpc.RouteGuideBlockingStub; @@ -259,7 +260,8 @@ public static void main(String[] args) throws InterruptedException { return; } - ManagedChannel channel = ManagedChannelBuilder.forTarget(target).usePlaintext().build(); + ManagedChannel channel = Grpc.newChannelBuilder(target, InsecureChannelCredentials.create()) + .build(); try { RouteGuideClient client = new RouteGuideClient(channel); // Looking for a valid feature diff --git a/examples/src/main/java/io/grpc/examples/routeguide/RouteGuideServer.java b/examples/src/main/java/io/grpc/examples/routeguide/RouteGuideServer.java index c91544ae45d..b39b06a6f92 100644 --- a/examples/src/main/java/io/grpc/examples/routeguide/RouteGuideServer.java +++ b/examples/src/main/java/io/grpc/examples/routeguide/RouteGuideServer.java @@ -25,6 +25,8 @@ import static java.lang.Math.toRadians; import static java.util.concurrent.TimeUnit.NANOSECONDS; +import io.grpc.Grpc; +import io.grpc.InsecureServerCredentials; import io.grpc.Server; import io.grpc.ServerBuilder; import io.grpc.stub.StreamObserver; @@ -55,7 +57,8 @@ public RouteGuideServer(int port) throws IOException { /** Create a RouteGuide server listening on {@code port} using {@code featureFile} database. */ public RouteGuideServer(int port, URL featureFile) throws IOException { - this(ServerBuilder.forPort(port), port, RouteGuideUtil.parseFeatures(featureFile)); + this(Grpc.newServerBuilderForPort(port, InsecureServerCredentials.create()), + port, RouteGuideUtil.parseFeatures(featureFile)); } /** Create a RouteGuide server using serverBuilder as a base and features as data. */ From 159bb8c55b00f09d3a098508783cdbfb49ba69f4 Mon Sep 17 00:00:00 2001 From: Larry Safran <107004254+larry-safran@users.noreply.github.com> Date: Tue, 22 Nov 2022 01:29:36 +0000 Subject: [PATCH 09/39] =?UTF-8?q?test:Report=20the=20values=20that=20were?= =?UTF-8?q?=20compared=20rather=20than=20the=20underlying=20durat=E2=80=A6?= =?UTF-8?q?=20(#9710)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Report the values that were compared rather than the underlying durations that generated those values. * Eliminate BigInteger to eliminate flakiness from possible class loading overhead. --- .../java/io/grpc/testing/DeadlineSubject.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/context/src/test/java/io/grpc/testing/DeadlineSubject.java b/context/src/test/java/io/grpc/testing/DeadlineSubject.java index 820f91248a1..5d4e86fac15 100644 --- a/context/src/test/java/io/grpc/testing/DeadlineSubject.java +++ b/context/src/test/java/io/grpc/testing/DeadlineSubject.java @@ -19,12 +19,12 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.truth.Fact.fact; import static java.util.concurrent.TimeUnit.NANOSECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; import com.google.common.truth.ComparableSubject; import com.google.common.truth.FailureMetadata; import com.google.common.truth.Subject; import io.grpc.Deadline; -import java.math.BigInteger; import java.util.concurrent.TimeUnit; import javax.annotation.CheckReturnValue; import javax.annotation.Nullable; @@ -32,6 +32,7 @@ /** Propositions for {@link Deadline} subjects. */ @SuppressWarnings("rawtypes") // Generics in this class are going away in a subsequent Truth. public final class DeadlineSubject extends ComparableSubject { + public static final double NANOSECONDS_IN_A_SECOND = SECONDS.toNanos(1) * 1.0; private static final Subject.Factory deadlineFactory = new Factory(); @@ -60,14 +61,14 @@ public void of(Deadline expected) { checkNotNull(actual, "actual value cannot be null. expected=%s", expected); // This is probably overkill, but easier than thinking about overflow. - BigInteger actualTimeRemaining = BigInteger.valueOf(actual.timeRemaining(NANOSECONDS)); - BigInteger expectedTimeRemaining = BigInteger.valueOf(expected.timeRemaining(NANOSECONDS)); - BigInteger deltaNanos = BigInteger.valueOf(timeUnit.toNanos(delta)); - if (actualTimeRemaining.subtract(expectedTimeRemaining).abs().compareTo(deltaNanos) > 0) { + long actualNanos = actual.timeRemaining(NANOSECONDS); + long expectedNanos = expected.timeRemaining(NANOSECONDS); + long deltaNanos = timeUnit.toNanos(delta) ; + if (Math.abs(actualNanos - expectedNanos) > deltaNanos) { failWithoutActual( - fact("expected", expected), - fact("but was", actual), - fact("outside tolerance in ns", deltaNanos)); + fact("expected", expectedNanos / NANOSECONDS_IN_A_SECOND), + fact("but was", expectedNanos / NANOSECONDS_IN_A_SECOND), + fact("outside tolerance in seconds", deltaNanos / NANOSECONDS_IN_A_SECOND)); } } }; From b593871801cc28c31c4d2286fa83083ae027f82c Mon Sep 17 00:00:00 2001 From: yifeizhuang Date: Tue, 22 Nov 2022 13:04:06 -0800 Subject: [PATCH 10/39] core: fix RejectedExecutionException in Retriable Stream (#9626) Add big negative integer to pending stream count when cancelled. The count is used to delay closing master listener until streams fully drained. Increment pending stream count before creating one. The count is also used to indicate callExecutor is safe to be used. New stream will not be created if big negative number was added, i.e. stream cancelled. New stream is created if not cancelled, callExecutor is safe to be used, because cancel will be delayed. Create new streams (retry, hedging) is moved to the main thread, before callExecutor calls drain. Minor refactor the masterListener.close() scenario. --- .../io/grpc/internal/RetriableStream.java | 92 ++++++++++--------- .../io/grpc/internal/RetriableStreamTest.java | 19 ++-- .../grpc/testing/integration/RetryTest.java | 15 +-- 3 files changed, 70 insertions(+), 56 deletions(-) diff --git a/core/src/main/java/io/grpc/internal/RetriableStream.java b/core/src/main/java/io/grpc/internal/RetriableStream.java index cb94195cce1..c8c45c61f85 100644 --- a/core/src/main/java/io/grpc/internal/RetriableStream.java +++ b/core/src/main/java/io/grpc/internal/RetriableStream.java @@ -107,6 +107,8 @@ public void uncaughtException(Thread t, Throwable e) { */ private final AtomicBoolean noMoreTransparentRetry = new AtomicBoolean(); private final AtomicInteger localOnlyTransparentRetries = new AtomicInteger(); + private final AtomicInteger inFlightSubStreams = new AtomicInteger(); + private Status savedCancellationReason; // Used for recording the share of buffer used for the current call out of the channel buffer. // This field would not be necessary if there is no channel buffer limit. @@ -220,7 +222,12 @@ private void commitAndRun(Substream winningSubstream) { } } + @Nullable // returns null when cancelled private Substream createSubstream(int previousAttemptCount, boolean isTransparentRetry) { + // increment only when >= 0, i.e. not cancelled + if (inFlightSubStreams.updateAndGet(value -> value < 0 ? value : value + 1) < 0) { + return null; + } Substream sub = new Substream(previousAttemptCount); // one tracer per substream final ClientStreamTracer bufferSizeTracer = new BufferSizeTracer(sub); @@ -367,6 +374,9 @@ public final void start(ClientStreamListener listener) { } Substream substream = createSubstream(0, false); + if (substream == null) { + return; + } if (isHedging) { FutureCanceller scheduledHedgingRef = null; @@ -434,16 +444,19 @@ private final class HedgingRunnable implements Runnable { @Override public void run() { + // It's safe to read state.hedgingAttemptCount here. + // If this run is not cancelled, the value of state.hedgingAttemptCount won't change + // until state.addActiveHedge() is called subsequently, even the state could possibly + // change. + Substream newSubstream = createSubstream(state.hedgingAttemptCount, false); + if (newSubstream == null) { + return; + } callExecutor.execute( new Runnable() { @SuppressWarnings("GuardedBy") @Override public void run() { - // It's safe to read state.hedgingAttemptCount here. - // If this run is not cancelled, the value of state.hedgingAttemptCount won't change - // until state.addActiveHedge() is called subsequently, even the state could possibly - // change. - Substream newSubstream = createSubstream(state.hedgingAttemptCount, false); boolean cancelled = false; FutureCanceller future = null; @@ -489,16 +502,11 @@ public final void cancel(final Status reason) { Runnable runnable = commit(noopSubstream); if (runnable != null) { + savedCancellationReason = reason; runnable.run(); - listenerSerializeExecutor.execute( - new Runnable() { - @Override - public void run() { - isClosed = true; - masterListener.closed(reason, RpcProgress.PROCESSED, new Metadata()); - - } - }); + if (inFlightSubStreams.addAndGet(Integer.MIN_VALUE) == Integer.MIN_VALUE) { + safeCloseMasterListener(reason, RpcProgress.PROCESSED, new Metadata()); + } return; } @@ -803,6 +811,17 @@ private void freezeHedging() { } } + private void safeCloseMasterListener(Status status, RpcProgress progress, Metadata metadata) { + listenerSerializeExecutor.execute( + new Runnable() { + @Override + public void run() { + isClosed = true; + masterListener.closed(status, progress, metadata); + } + }); + } + private interface BufferEntry { /** Replays the buffer entry with the given stream. */ void runWith(Substream substream); @@ -840,19 +859,18 @@ public void closed( closedSubstreamsInsight.append(status.getCode()); } + if (inFlightSubStreams.decrementAndGet() == Integer.MIN_VALUE) { + assert savedCancellationReason != null; + safeCloseMasterListener(savedCancellationReason, RpcProgress.PROCESSED, new Metadata()); + return; + } + // handle a race between buffer limit exceeded and closed, when setting // substream.bufferLimitExceeded = true happens before state.substreamClosed(substream). if (substream.bufferLimitExceeded) { commitAndRun(substream); if (state.winningSubstream == substream) { - listenerSerializeExecutor.execute( - new Runnable() { - @Override - public void run() { - isClosed = true; - masterListener.closed(status, rpcProgress, trailers); - } - }); + safeCloseMasterListener(status, rpcProgress, trailers); } return; } @@ -863,14 +881,7 @@ public void run() { Status tooManyTransparentRetries = Status.INTERNAL .withDescription("Too many transparent retries. Might be a bug in gRPC") .withCause(status.asRuntimeException()); - listenerSerializeExecutor.execute( - new Runnable() { - @Override - public void run() { - isClosed = true; - masterListener.closed(tooManyTransparentRetries, rpcProgress, trailers); - } - }); + safeCloseMasterListener(tooManyTransparentRetries, rpcProgress, trailers); } return; } @@ -881,6 +892,9 @@ public void run() { && noMoreTransparentRetry.compareAndSet(false, true))) { // transparent retry final Substream newSubstream = createSubstream(substream.previousAttemptCount, true); + if (newSubstream == null) { + return; + } if (isHedging) { boolean commit = false; synchronized (lock) { @@ -942,6 +956,11 @@ public void run() { } else { RetryPlan retryPlan = makeRetryDecision(status, trailers); if (retryPlan.shouldRetry) { + // retry + Substream newSubstream = createSubstream(substream.previousAttemptCount + 1, false); + if (newSubstream == null) { + return; + } // The check state.winningSubstream == null, checking if is not already committed, is // racy, but is still safe b/c the retry will also handle committed/cancellation FutureCanceller scheduledRetryCopy; @@ -955,10 +974,6 @@ public void run() { new Runnable() { @Override public void run() { - // retry - Substream newSubstream = createSubstream( - substream.previousAttemptCount + 1, - false); drain(newSubstream); } }); @@ -978,14 +993,7 @@ public void run() { commitAndRun(substream); if (state.winningSubstream == substream) { - listenerSerializeExecutor.execute( - new Runnable() { - @Override - public void run() { - isClosed = true; - masterListener.closed(status, rpcProgress, trailers); - } - }); + safeCloseMasterListener(status, rpcProgress, trailers); } } diff --git a/core/src/test/java/io/grpc/internal/RetriableStreamTest.java b/core/src/test/java/io/grpc/internal/RetriableStreamTest.java index f20e772e92b..12bf697027c 100644 --- a/core/src/test/java/io/grpc/internal/RetriableStreamTest.java +++ b/core/src/test/java/io/grpc/internal/RetriableStreamTest.java @@ -283,6 +283,7 @@ public Void answer(InvocationOnMock in) { doReturn(mockStream2).when(retriableStreamRecorder).newSubstream(1); sublistenerCaptor1.getValue().closed( Status.fromCode(RETRIABLE_STATUS_CODE_2), PROCESSED, new Metadata()); + inOrder.verify(retriableStreamRecorder).newSubstream(1); assertEquals(1, fakeClock.numPendingTasks()); // send more messages during backoff @@ -294,7 +295,6 @@ public Void answer(InvocationOnMock in) { assertEquals(1, fakeClock.numPendingTasks()); fakeClock.forwardTime(1L, TimeUnit.SECONDS); assertEquals(0, fakeClock.numPendingTasks()); - inOrder.verify(retriableStreamRecorder).newSubstream(1); inOrder.verify(mockStream2).setAuthority(AUTHORITY); inOrder.verify(mockStream2).setCompressor(COMPRESSOR); inOrder.verify(mockStream2).setDecompressorRegistry(DECOMPRESSOR_REGISTRY); @@ -339,6 +339,7 @@ public Void answer(InvocationOnMock in) { doReturn(mockStream3).when(retriableStreamRecorder).newSubstream(2); sublistenerCaptor2.getValue().closed( Status.fromCode(RETRIABLE_STATUS_CODE_1), PROCESSED, new Metadata()); + inOrder.verify(retriableStreamRecorder).newSubstream(2); assertEquals(1, fakeClock.numPendingTasks()); // send more messages during backoff @@ -353,7 +354,6 @@ public Void answer(InvocationOnMock in) { assertEquals(1, fakeClock.numPendingTasks()); fakeClock.forwardTime(1L, TimeUnit.SECONDS); assertEquals(0, fakeClock.numPendingTasks()); - inOrder.verify(retriableStreamRecorder).newSubstream(2); inOrder.verify(mockStream3).setAuthority(AUTHORITY); inOrder.verify(mockStream3).setCompressor(COMPRESSOR); inOrder.verify(mockStream3).setDecompressorRegistry(DECOMPRESSOR_REGISTRY); @@ -792,6 +792,8 @@ public boolean isReady() { public void cancelWhileDraining() { ArgumentCaptor sublistenerCaptor1 = ArgumentCaptor.forClass(ClientStreamListener.class); + ArgumentCaptor sublistenerCaptor2 = + ArgumentCaptor.forClass(ClientStreamListener.class); ClientStream mockStream1 = mock(ClientStream.class); ClientStream mockStream2 = mock( @@ -818,7 +820,7 @@ public void request(int numMessages) { Status.fromCode(RETRIABLE_STATUS_CODE_1), PROCESSED, new Metadata()); fakeClock.forwardTime((long) (INITIAL_BACKOFF_IN_SECONDS * FAKE_RANDOM), TimeUnit.SECONDS); - inOrder.verify(mockStream2).start(any(ClientStreamListener.class)); + inOrder.verify(mockStream2).start(sublistenerCaptor2.capture()); inOrder.verify(mockStream2).request(3); inOrder.verify(retriableStreamRecorder).postCommit(); ArgumentCaptor statusCaptor = ArgumentCaptor.forClass(Status.class); @@ -826,6 +828,7 @@ public void request(int numMessages) { assertThat(statusCaptor.getValue().getCode()).isEqualTo(Code.CANCELLED); assertThat(statusCaptor.getValue().getDescription()) .isEqualTo("Stream thrown away because RetriableStream committed"); + sublistenerCaptor2.getValue().closed(Status.CANCELLED, PROCESSED, new Metadata()); verify(masterListener).closed( statusCaptor.capture(), any(RpcProgress.class), any(Metadata.class)); assertThat(statusCaptor.getValue().getCode()).isEqualTo(Code.CANCELLED); @@ -848,6 +851,8 @@ public void start(ClientStreamListener listener) { Status.CANCELLED.withDescription("cancelled while retry start")); } })); + ArgumentCaptor sublistenerCaptor2 = + ArgumentCaptor.forClass(ClientStreamListener.class); InOrder inOrder = inOrder(retriableStreamRecorder, mockStream1, mockStream2); doReturn(mockStream1).when(retriableStreamRecorder).newSubstream(0); @@ -860,13 +865,14 @@ public void start(ClientStreamListener listener) { Status.fromCode(RETRIABLE_STATUS_CODE_1), PROCESSED, new Metadata()); fakeClock.forwardTime((long) (INITIAL_BACKOFF_IN_SECONDS * FAKE_RANDOM), TimeUnit.SECONDS); - inOrder.verify(mockStream2).start(any(ClientStreamListener.class)); + inOrder.verify(mockStream2).start(sublistenerCaptor2.capture()); inOrder.verify(retriableStreamRecorder).postCommit(); ArgumentCaptor statusCaptor = ArgumentCaptor.forClass(Status.class); inOrder.verify(mockStream2).cancel(statusCaptor.capture()); assertThat(statusCaptor.getValue().getCode()).isEqualTo(Code.CANCELLED); assertThat(statusCaptor.getValue().getDescription()) .isEqualTo("Stream thrown away because RetriableStream committed"); + sublistenerCaptor2.getValue().closed(Status.CANCELLED, PROCESSED, new Metadata()); verify(masterListener).closed( statusCaptor.capture(), any(RpcProgress.class), any(Metadata.class)); assertThat(statusCaptor.getValue().getCode()).isEqualTo(Code.CANCELLED); @@ -1121,7 +1127,6 @@ public void perRpcBufferLimitExceededDuringBackoff() { sublistenerCaptor1.getValue().closed( Status.fromCode(RETRIABLE_STATUS_CODE_1), PROCESSED, new Metadata()); - // bufferSizeTracer.outboundWireSize() quits immediately while backoff b/c substream1 is closed assertEquals(1, fakeClock.numPendingTasks()); bufferSizeTracer.outboundWireSize(2); verify(retriableStreamRecorder, never()).postCommit(); @@ -1132,8 +1137,6 @@ public void perRpcBufferLimitExceededDuringBackoff() { // bufferLimitExceeded bufferSizeTracer.outboundWireSize(PER_RPC_BUFFER_LIMIT - 1); - verify(retriableStreamRecorder, never()).postCommit(); - bufferSizeTracer.outboundWireSize(2); verify(retriableStreamRecorder).postCommit(); verifyNoMoreInteractions(mockStream1); @@ -2464,6 +2467,8 @@ public void hedging_cancelled() { assertEquals(CANCELLED_BECAUSE_COMMITTED, statusCaptor.getValue().getDescription()); inOrder.verify(retriableStreamRecorder).postCommit(); + sublistenerCaptor1.getValue().closed(Status.CANCELLED, PROCESSED, new Metadata()); + sublistenerCaptor2.getValue().closed(Status.CANCELLED, PROCESSED, new Metadata()); inOrder.verify(masterListener).closed( any(Status.class), any(RpcProgress.class), any(Metadata.class)); inOrder.verifyNoMoreInteractions(); diff --git a/interop-testing/src/test/java/io/grpc/testing/integration/RetryTest.java b/interop-testing/src/test/java/io/grpc/testing/integration/RetryTest.java index 157fd79524e..eca563fb7c1 100644 --- a/interop-testing/src/test/java/io/grpc/testing/integration/RetryTest.java +++ b/interop-testing/src/test/java/io/grpc/testing/integration/RetryTest.java @@ -351,8 +351,8 @@ public void statsRecorded() throws Exception { call.request(1); assertInboundMessageRecorded(); assertInboundWireSizeRecorded(1); - assertRpcStatusRecorded(Status.Code.OK, 2000, 2); - assertRetryStatsRecorded(1, 0, 10_000); + assertRpcStatusRecorded(Status.Code.OK, 12000, 2); + assertRetryStatsRecorded(1, 0, 0); } @Test @@ -410,13 +410,14 @@ public void streamClosed(Status status) { serverCall.request(2); assertOutboundWireSizeRecorded(message.length()); fakeClock.forwardTime(7, SECONDS); - call.cancel("Cancelled before commit", null); // A noop substream will commit. - // The call listener is closed, but the netty substream listener is not yet closed. - verify(mockCallListener, timeout(5000)).onClose(any(Status.class), any(Metadata.class)); + // A noop substream will commit. But call is not yet closed. + call.cancel("Cancelled before commit", null); // Let the netty substream listener be closed. streamClosedLatch.countDown(); - assertRetryStatsRecorded(1, 0, 10_000); - assertRpcStatusRecorded(Code.CANCELLED, 7_000, 1); + // The call listener is closed. + verify(mockCallListener, timeout(5000)).onClose(any(Status.class), any(Metadata.class)); + assertRpcStatusRecorded(Code.CANCELLED, 17_000, 1); + assertRetryStatsRecorded(1, 0, 0); } @Test From c80b5875796856d3e543ad272d64ba0680dd8b0e Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Tue, 22 Nov 2022 17:09:03 -0800 Subject: [PATCH 11/39] okhttp: Add missing server support for TLS ClientAuth (#9711) --- okhttp/build.gradle | 1 + .../io/grpc/okhttp/OkHttpServerBuilder.java | 81 +++++- .../src/test/java/io/grpc/okhttp/TlsTest.java | 271 ++++++++++++++++++ 3 files changed, 351 insertions(+), 2 deletions(-) create mode 100644 okhttp/src/test/java/io/grpc/okhttp/TlsTest.java diff --git a/okhttp/build.gradle b/okhttp/build.gradle index a044503510d..439abaa3373 100644 --- a/okhttp/build.gradle +++ b/okhttp/build.gradle @@ -21,6 +21,7 @@ dependencies { testImplementation project(':grpc-core').sourceSets.test.output, project(':grpc-api').sourceSets.test.output, project(':grpc-testing'), + project(':grpc-testing-proto'), libraries.netty.codec.http2, libraries.okhttp signature libraries.signature.java diff --git a/okhttp/src/main/java/io/grpc/okhttp/OkHttpServerBuilder.java b/okhttp/src/main/java/io/grpc/okhttp/OkHttpServerBuilder.java index f0e8bf41ff9..45d6b9efc54 100644 --- a/okhttp/src/main/java/io/grpc/okhttp/OkHttpServerBuilder.java +++ b/okhttp/src/main/java/io/grpc/okhttp/OkHttpServerBuilder.java @@ -40,7 +40,10 @@ import io.grpc.internal.SharedResourcePool; import io.grpc.internal.TransportTracer; import io.grpc.okhttp.internal.Platform; +import java.io.IOException; +import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.Socket; import java.net.SocketAddress; import java.security.GeneralSecurityException; import java.util.EnumSet; @@ -54,6 +57,8 @@ import javax.net.ServerSocketFactory; import javax.net.ssl.KeyManager; import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; /** @@ -422,9 +427,26 @@ static HandshakerSocketFactoryResult handshakerSocketFactoryFrom(ServerCredentia } catch (GeneralSecurityException gse) { throw new RuntimeException("TLS Provider failure", gse); } + SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); + switch (tlsCreds.getClientAuth()) { + case OPTIONAL: + sslSocketFactory = new ClientCertRequestingSocketFactory(sslSocketFactory, false); + break; + + case REQUIRE: + sslSocketFactory = new ClientCertRequestingSocketFactory(sslSocketFactory, true); + break; + + case NONE: + // NOOP; this is the SSLContext default + break; + + default: + return HandshakerSocketFactoryResult.error( + "Unknown TlsServerCredentials.ClientAuth value: " + tlsCreds.getClientAuth()); + } return HandshakerSocketFactoryResult.factory(new TlsServerHandshakerSocketFactory( - new SslSocketFactoryServerCredentials.ServerCredentials( - sslContext.getSocketFactory()))); + new SslSocketFactoryServerCredentials.ServerCredentials(sslSocketFactory))); } else if (creds instanceof InsecureServerCredentials) { return HandshakerSocketFactoryResult.factory(new PlaintextHandshakerSocketFactory()); @@ -473,4 +495,59 @@ public static HandshakerSocketFactoryResult factory(HandshakerSocketFactory fact Preconditions.checkNotNull(factory, "factory"), null); } } + + static final class ClientCertRequestingSocketFactory extends SSLSocketFactory { + private final SSLSocketFactory socketFactory; + private final boolean required; + + public ClientCertRequestingSocketFactory(SSLSocketFactory socketFactory, boolean required) { + this.socketFactory = Preconditions.checkNotNull(socketFactory, "socketFactory"); + this.required = required; + } + + private Socket apply(Socket s) throws IOException { + if (!(s instanceof SSLSocket)) { + throw new IOException( + "SocketFactory " + socketFactory + " did not produce an SSLSocket: " + s.getClass()); + } + SSLSocket sslSocket = (SSLSocket) s; + if (required) { + sslSocket.setNeedClientAuth(true); + } else { + sslSocket.setWantClientAuth(true); + } + return sslSocket; + } + + @Override public Socket createSocket(Socket s, String host, int port, boolean autoClose) + throws IOException { + return apply(socketFactory.createSocket(s, host, port, autoClose)); + } + + @Override public Socket createSocket(String host, int port) throws IOException { + return apply(socketFactory.createSocket(host, port)); + } + + @Override public Socket createSocket( + String host, int port, InetAddress localHost, int localPort) throws IOException { + return apply(socketFactory.createSocket(host, port, localHost, localPort)); + } + + @Override public Socket createSocket(InetAddress host, int port) throws IOException { + return apply(socketFactory.createSocket(host, port)); + } + + @Override public Socket createSocket( + InetAddress host, int port, InetAddress localAddress, int localPort) throws IOException { + return apply(socketFactory.createSocket(host, port, localAddress, localPort)); + } + + @Override public String[] getDefaultCipherSuites() { + return socketFactory.getDefaultCipherSuites(); + } + + @Override public String[] getSupportedCipherSuites() { + return socketFactory.getSupportedCipherSuites(); + } + } } diff --git a/okhttp/src/test/java/io/grpc/okhttp/TlsTest.java b/okhttp/src/test/java/io/grpc/okhttp/TlsTest.java new file mode 100644 index 00000000000..cc86c81d970 --- /dev/null +++ b/okhttp/src/test/java/io/grpc/okhttp/TlsTest.java @@ -0,0 +1,271 @@ +/* + * Copyright 2015 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. + */ + +package io.grpc.okhttp; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + +import com.google.common.base.Throwables; +import io.grpc.ChannelCredentials; +import io.grpc.ConnectivityState; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.grpc.Server; +import io.grpc.ServerCredentials; +import io.grpc.Status; +import io.grpc.StatusRuntimeException; +import io.grpc.TlsChannelCredentials; +import io.grpc.TlsServerCredentials; +import io.grpc.internal.testing.TestUtils; +import io.grpc.stub.StreamObserver; +import io.grpc.testing.GrpcCleanupRule; +import io.grpc.testing.TlsTesting; +import io.grpc.testing.protobuf.SimpleRequest; +import io.grpc.testing.protobuf.SimpleResponse; +import io.grpc.testing.protobuf.SimpleServiceGrpc; +import java.io.IOException; +import java.io.InputStream; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Verify OkHttp's TLS integration. */ +@RunWith(JUnit4.class) +public class TlsTest { + @Rule + public final GrpcCleanupRule grpcCleanupRule = new GrpcCleanupRule(); + + @Before + public void checkForAlpnApi() throws Exception { + // This checks for the "Java 9 ALPN API" which was backported to Java 8u252. The Kokoro Windows + // CI is on too old of a JDK for us to assume this is available. + SSLContext context = SSLContext.getInstance("TLS"); + context.init(null, null, null); + SSLEngine engine = context.createSSLEngine(); + try { + SSLEngine.class.getMethod("getApplicationProtocol").invoke(engine); + } catch (NoSuchMethodException | UnsupportedOperationException ex) { + Assume.assumeNoException(ex); + } + } + + @Test + public void mtls_succeeds() throws Exception { + ServerCredentials serverCreds; + try (InputStream serverCert = TlsTesting.loadCert("server1.pem"); + InputStream serverPrivateKey = TlsTesting.loadCert("server1.key"); + InputStream caCert = TlsTesting.loadCert("ca.pem")) { + serverCreds = TlsServerCredentials.newBuilder() + .keyManager(serverCert, serverPrivateKey) + .trustManager(caCert) + .clientAuth(TlsServerCredentials.ClientAuth.REQUIRE) + .build(); + } + ChannelCredentials channelCreds; + try (InputStream clientCertChain = TlsTesting.loadCert("client.pem"); + InputStream clientPrivateKey = TlsTesting.loadCert("client.key"); + InputStream caCert = TlsTesting.loadCert("ca.pem")) { + channelCreds = TlsChannelCredentials.newBuilder() + .keyManager(clientCertChain, clientPrivateKey) + .trustManager(caCert) + .build(); + } + Server server = grpcCleanupRule.register(server(serverCreds)); + ManagedChannel channel = grpcCleanupRule.register(clientChannel(server, channelCreds)); + + SimpleServiceGrpc.newBlockingStub(channel).unaryRpc(SimpleRequest.getDefaultInstance()); + } + + @Test + public void untrustedClient_fails() throws Exception { + ServerCredentials serverCreds; + try (InputStream serverCert = TlsTesting.loadCert("server1.pem"); + InputStream serverPrivateKey = TlsTesting.loadCert("server1.key"); + InputStream caCert = TlsTesting.loadCert("ca.pem")) { + serverCreds = TlsServerCredentials.newBuilder() + .keyManager(serverCert, serverPrivateKey) + .trustManager(caCert) + .clientAuth(TlsServerCredentials.ClientAuth.REQUIRE) + .build(); + } + ChannelCredentials channelCreds; + try (InputStream clientCertChain = TlsTesting.loadCert("badclient.pem"); + InputStream clientPrivateKey = TlsTesting.loadCert("badclient.key"); + InputStream caCert = TlsTesting.loadCert("ca.pem")) { + channelCreds = TlsChannelCredentials.newBuilder() + .keyManager(clientCertChain, clientPrivateKey) + .trustManager(caCert) + .build(); + } + Server server = grpcCleanupRule.register(server(serverCreds)); + ManagedChannel channel = grpcCleanupRule.register(clientChannel(server, channelCreds)); + + assertRpcFails(channel); + } + + @Test + public void missingOptionalClientCert_succeeds() throws Exception { + ServerCredentials serverCreds; + try (InputStream serverCert = TlsTesting.loadCert("server1.pem"); + InputStream serverPrivateKey = TlsTesting.loadCert("server1.key"); + InputStream caCert = TlsTesting.loadCert("ca.pem")) { + serverCreds = TlsServerCredentials.newBuilder() + .keyManager(serverCert, serverPrivateKey) + .trustManager(caCert) + .clientAuth(TlsServerCredentials.ClientAuth.OPTIONAL) + .build(); + } + ChannelCredentials channelCreds; + try (InputStream caCert = TlsTesting.loadCert("ca.pem")) { + channelCreds = TlsChannelCredentials.newBuilder() + .trustManager(caCert) + .build(); + } + Server server = grpcCleanupRule.register(server(serverCreds)); + ManagedChannel channel = grpcCleanupRule.register(clientChannel(server, channelCreds)); + + SimpleServiceGrpc.newBlockingStub(channel).unaryRpc(SimpleRequest.getDefaultInstance()); + } + + @Test + public void missingRequiredClientCert_fails() throws Exception { + ServerCredentials serverCreds; + try (InputStream serverCert = TlsTesting.loadCert("server1.pem"); + InputStream serverPrivateKey = TlsTesting.loadCert("server1.key"); + InputStream caCert = TlsTesting.loadCert("ca.pem")) { + serverCreds = TlsServerCredentials.newBuilder() + .keyManager(serverCert, serverPrivateKey) + .trustManager(caCert) + .clientAuth(TlsServerCredentials.ClientAuth.REQUIRE) + .build(); + } + ChannelCredentials channelCreds; + try (InputStream caCert = TlsTesting.loadCert("ca.pem")) { + channelCreds = TlsChannelCredentials.newBuilder() + .trustManager(caCert) + .build(); + } + Server server = grpcCleanupRule.register(server(serverCreds)); + ManagedChannel channel = grpcCleanupRule.register(clientChannel(server, channelCreds)); + + assertRpcFails(channel); + } + + @Test + public void untrustedServer_fails() throws Exception { + ServerCredentials serverCreds; + try (InputStream serverCert = TlsTesting.loadCert("badserver.pem"); + InputStream serverPrivateKey = TlsTesting.loadCert("badserver.key"); + InputStream caCert = TlsTesting.loadCert("ca.pem")) { + serverCreds = TlsServerCredentials.newBuilder() + .keyManager(serverCert, serverPrivateKey) + .trustManager(caCert) + .build(); + } + ChannelCredentials channelCreds; + try (InputStream clientCertChain = TlsTesting.loadCert("client.pem"); + InputStream clientPrivateKey = TlsTesting.loadCert("client.key"); + InputStream caCert = TlsTesting.loadCert("ca.pem")) { + channelCreds = TlsChannelCredentials.newBuilder() + .keyManager(clientCertChain, clientPrivateKey) + .trustManager(caCert) + .build(); + } + Server server = grpcCleanupRule.register(server(serverCreds)); + ManagedChannel channel = grpcCleanupRule.register(clientChannel(server, channelCreds)); + + assertRpcFails(channel); + } + + @Test + public void unmatchedServerSubjectAlternativeNames_fails() throws Exception { + ServerCredentials serverCreds; + try (InputStream serverCert = TlsTesting.loadCert("server1.pem"); + InputStream serverPrivateKey = TlsTesting.loadCert("server1.key"); + InputStream caCert = TlsTesting.loadCert("ca.pem")) { + serverCreds = TlsServerCredentials.newBuilder() + .keyManager(serverCert, serverPrivateKey) + .trustManager(caCert) + .build(); + } + ChannelCredentials channelCreds; + try (InputStream clientCertChain = TlsTesting.loadCert("client.pem"); + InputStream clientPrivateKey = TlsTesting.loadCert("client.key"); + InputStream caCert = TlsTesting.loadCert("ca.pem")) { + channelCreds = TlsChannelCredentials.newBuilder() + .keyManager(clientCertChain, clientPrivateKey) + .trustManager(caCert) + .build(); + } + Server server = grpcCleanupRule.register(server(serverCreds)); + ManagedChannel channel = grpcCleanupRule.register(clientChannelBuilder(server, channelCreds) + .overrideAuthority("notgonnamatch.example.com") + .build()); + + assertRpcFails(channel); + } + + private static Server server(ServerCredentials creds) throws IOException { + return OkHttpServerBuilder.forPort(0, creds) + .directExecutor() + .addService(new SimpleServiceImpl()) + .build() + .start(); + } + + private static ManagedChannelBuilder clientChannelBuilder( + Server server, ChannelCredentials creds) { + return OkHttpChannelBuilder.forAddress("localhost", server.getPort(), creds) + .directExecutor() + .overrideAuthority(TestUtils.TEST_SERVER_HOST); + } + + private static ManagedChannel clientChannel(Server server, ChannelCredentials creds) { + return clientChannelBuilder(server, creds).build(); + } + + private static void assertRpcFails(ManagedChannel channel) { + SimpleServiceGrpc.SimpleServiceBlockingStub stub = SimpleServiceGrpc.newBlockingStub(channel); + try { + stub.unaryRpc(SimpleRequest.getDefaultInstance()); + assertWithMessage("TLS handshake should have failed, but didn't; received RPC response") + .fail(); + } catch (StatusRuntimeException e) { + assertWithMessage(Throwables.getStackTraceAsString(e)) + .that(e.getStatus().getCode()).isEqualTo(Status.Code.UNAVAILABLE); + } + // We really want to see TRANSIENT_FAILURE here, but if the test runs slowly the 1s backoff + // may be exceeded by the time the failure happens (since it counts from the start of the + // attempt). Even so, CONNECTING is a strong indicator that the handshake failed; otherwise we'd + // expect READY or IDLE. + assertThat(channel.getState(false)) + .isAnyOf(ConnectivityState.TRANSIENT_FAILURE, ConnectivityState.CONNECTING); + } + + private static final class SimpleServiceImpl extends SimpleServiceGrpc.SimpleServiceImplBase { + @Override + public void unaryRpc(SimpleRequest req, StreamObserver respOb) { + respOb.onNext(SimpleResponse.getDefaultInstance()); + respOb.onCompleted(); + } + } +} From 58ba73205af4b0cef2e99fd37e6b0dde8affb674 Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Mon, 28 Nov 2022 10:00:33 -0800 Subject: [PATCH 12/39] README.md: Update support docs, OkHttp server, binder --- README.md | 44 ++++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 2c18763b180..23109dc0c6d 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,6 @@ gRPC-Java - An RPC library and framework ======================================== -gRPC-Java works with JDK 8. gRPC-Java clients are supported on Android API -levels 19 and up (KitKat and later). Deploying gRPC servers on an Android -device is not supported. - -TLS usage typically requires using Java 8, or Play Services Dynamic Security -Provider on Android. Please see the [Security Readme](SECURITY.md). - @@ -24,6 +17,26 @@ Provider on Android. Please see the [Security Readme](SECURITY.md). [![Line Coverage Status](https://coveralls.io/repos/grpc/grpc-java/badge.svg?branch=master&service=github)](https://coveralls.io/github/grpc/grpc-java?branch=master) [![Branch-adjusted Line Coverage Status](https://codecov.io/gh/grpc/grpc-java/branch/master/graph/badge.svg)](https://codecov.io/gh/grpc/grpc-java) +Supported Platforms +------------------- + +gRPC-Java supports Java 8 and later. Android minSdkVersion 19 (KitKat) and +later are supported with [Java 8 language desugaring][android-java-8]. + +TLS usage on Android typically requires Play Services Dynamic Security Provider. +Please see the [Security Readme](SECURITY.md). + +Older Java versions are not directly supported, but a branch remains available +for fixes and releases. See [gRFC P5 JDK Version Support +Policy][P5-jdk-version-support]. + +Java version | gRPC Branch +------------ | ----------- +7 | 1.41.x + +[android-java-8]: https://developer.android.com/studio/write/java8-support#supported_features +[P5-jdk-version-support]: https://github.com/grpc/proposal/blob/master/P5-jdk-version-support.md#proposal + Getting Started --------------- @@ -243,12 +256,15 @@ wire. The interfaces to it are abstract just enough to allow plugging in of different implementations. Note the transport layer API is considered internal to gRPC and has weaker API guarantees than the core API under package `io.grpc`. -gRPC comes with three Transport implementations: +gRPC comes with multiple Transport implementations: -1. The Netty-based transport is the main transport implementation based on - [Netty](https://netty.io). It is for both the client and the server. -2. The OkHttp-based transport is a lightweight transport based on - [OkHttp](https://square.github.io/okhttp/). It is mainly for use on Android - and is for client only. +1. The Netty-based HTTP/2 transport is the main transport implementation based + on [Netty](https://netty.io). It is not officially supported on Android. +2. The OkHttp-based HTTP/2 transport is a lightweight transport based on + [Okio](https://square.github.io/okio/) and forked low-level parts of + [OkHttp](https://square.github.io/okhttp/). It is mainly for use on Android. 3. The in-process transport is for when a server is in the same process as the - client. It is useful for testing, while also being safe for production use. + client. It is used frequently for testing, while also being safe for + production use. +4. The Binder transport is for Android cross-process communication on a single + device. From f082151fb5de1c102a492e2fa2bc4c1bef0d8c6a Mon Sep 17 00:00:00 2001 From: markb74 <57717302+markb74@users.noreply.github.com> Date: Tue, 29 Nov 2022 02:38:00 +0100 Subject: [PATCH 13/39] binder: Ensure the security interceptor is always closest to the actual transport. (#9716) --- .../io/grpc/binder/BinderSecurityTest.java | 40 +++++++++++++++++++ .../io/grpc/binder/BinderServerBuilder.java | 8 +++- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/binder/src/androidTest/java/io/grpc/binder/BinderSecurityTest.java b/binder/src/androidTest/java/io/grpc/binder/BinderSecurityTest.java index 56e8f93c140..27fc293e2a7 100644 --- a/binder/src/androidTest/java/io/grpc/binder/BinderSecurityTest.java +++ b/binder/src/androidTest/java/io/grpc/binder/BinderSecurityTest.java @@ -29,9 +29,12 @@ import com.google.protobuf.Empty; import io.grpc.CallOptions; import io.grpc.ManagedChannel; +import io.grpc.Metadata; import io.grpc.MethodDescriptor; import io.grpc.Server; +import io.grpc.ServerCall; import io.grpc.ServerCallHandler; +import io.grpc.ServerInterceptor; import io.grpc.ServerServiceDefinition; import io.grpc.Status; import io.grpc.StatusRuntimeException; @@ -59,6 +62,7 @@ public final class BinderSecurityTest { @Nullable ManagedChannel channel; Map> methods = new HashMap<>(); List> calls = new ArrayList<>(); + CountingServerInterceptor countingServerInterceptor; @Before public void setupServiceDefinitionsAndMethods() { @@ -86,6 +90,7 @@ public void setupServiceDefinitionsAndMethods() { } serviceDefinitions.add(builder.build()); } + countingServerInterceptor = new CountingServerInterceptor(); } @After @@ -120,6 +125,7 @@ private Server buildServer( ServerSecurityPolicy serverPolicy) { BinderServerBuilder serverBuilder = BinderServerBuilder.forAddress(listenAddr, receiver); serverBuilder.securityPolicy(serverPolicy); + serverBuilder.intercept(countingServerInterceptor); for (ServerServiceDefinition serviceDefinition : serviceDefinitions) { serverBuilder.addService(serviceDefinition); @@ -195,6 +201,27 @@ public void testPerServicePolicy() throws Exception { } } + @Test + public void testSecurityInterceptorIsClosestToTransport() throws Exception { + createChannel( + ServerSecurityPolicy.newBuilder() + .servicePolicy("foo", policy((uid) -> true)) + .servicePolicy("bar", policy((uid) -> false)) + .servicePolicy("baz", policy((uid) -> false)) + .build(), + SecurityPolicies.internalOnly()); + assertThat(countingServerInterceptor.numInterceptedCalls).isEqualTo(0); + for (MethodDescriptor method : methods.values()) { + try { + ClientCalls.blockingUnaryCall(channel, method, CallOptions.DEFAULT, null); + } catch (StatusRuntimeException sre) { + // Ignore. + } + } + // Only the foo calls should have made it to the user interceptor. + assertThat(countingServerInterceptor.numInterceptedCalls).isEqualTo(2); + } + private static SecurityPolicy policy(Function func) { return new SecurityPolicy() { @Override @@ -203,4 +230,17 @@ public Status checkAuthorization(int uid) { } }; } + + private final class CountingServerInterceptor implements ServerInterceptor { + int numInterceptedCalls; + + @Override + public ServerCall.Listener interceptCall( + ServerCall call, + Metadata headers, + ServerCallHandler next) { + numInterceptedCalls += 1; + return next.startCall(call, headers); + } + } } diff --git a/binder/src/main/java/io/grpc/binder/BinderServerBuilder.java b/binder/src/main/java/io/grpc/binder/BinderServerBuilder.java index 383bd3f8e49..c4674a76bbe 100644 --- a/binder/src/main/java/io/grpc/binder/BinderServerBuilder.java +++ b/binder/src/main/java/io/grpc/binder/BinderServerBuilder.java @@ -81,6 +81,7 @@ public static BinderServerBuilder forPort(int port) { SharedResourcePool.forResource(GrpcUtil.TIMER_SERVICE); private ServerSecurityPolicy securityPolicy; private InboundParcelablePolicy inboundParcelablePolicy; + private boolean isBuilt; private BinderServerBuilder( AndroidComponentAddress listenAddress, @@ -107,8 +108,6 @@ private BinderServerBuilder( // Disable stats and tracing by default. serverImplBuilder.setStatsEnabled(false); serverImplBuilder.setTracingEnabled(false); - - BinderTransportSecurity.installAuthInterceptor(this); } @Override @@ -177,6 +176,11 @@ public BinderServerBuilder useTransportSecurity(File certChain, File privateKey) */ @Override // For javadoc refinement only. public Server build() { + // Since we install a final interceptor here, we need to ensure we're only built once. + checkState(!isBuilt, "BinderServerBuilder can only be used to build one server instance."); + isBuilt = true; + // We install the security interceptor last, so it's closest to the transport. + BinderTransportSecurity.installAuthInterceptor(this); return super.build(); } } From 241097c6e0768ade8266d1d4ab81c38538204880 Mon Sep 17 00:00:00 2001 From: markb74 <57717302+markb74@users.noreply.github.com> Date: Tue, 29 Nov 2022 09:57:25 +0100 Subject: [PATCH 14/39] binder: Set default idle timeout to 60 seconds, and enable "strict lifecycle management". (#9486) --- .../io/grpc/binder/BinderChannelBuilder.java | 22 ++++++++++ .../grpc/binder/BinderChannelBuilderTest.java | 44 +++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 binder/src/test/java/io/grpc/binder/BinderChannelBuilderTest.java diff --git a/binder/src/main/java/io/grpc/binder/BinderChannelBuilder.java b/binder/src/main/java/io/grpc/binder/BinderChannelBuilder.java index 91e4e8f1c76..8364645a10e 100644 --- a/binder/src/main/java/io/grpc/binder/BinderChannelBuilder.java +++ b/binder/src/main/java/io/grpc/binder/BinderChannelBuilder.java @@ -17,6 +17,7 @@ package io.grpc.binder; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; import android.app.Application; import android.content.ComponentName; @@ -124,6 +125,7 @@ public static BinderChannelBuilder forTarget(String target) { private SecurityPolicy securityPolicy; private InboundParcelablePolicy inboundParcelablePolicy; private BindServiceFlags bindServiceFlags; + private boolean strictLifecycleManagement; private BinderChannelBuilder( @Nullable AndroidComponentAddress directAddress, @@ -164,6 +166,7 @@ public ClientTransportFactory buildClientTransportFactory() { new BinderChannelTransportFactoryBuilder(), null); } + idleTimeout(60, TimeUnit.SECONDS); } @Override @@ -224,6 +227,25 @@ public BinderChannelBuilder inboundParcelablePolicy( return this; } + /** + * Disables the channel idle timeout and prevents it from being enabled. This + * allows a centralized application method to configure the channel builder + * and return it, without worrying about another part of the application + * accidentally enabling the idle timeout. + */ + public BinderChannelBuilder strictLifecycleManagement() { + strictLifecycleManagement = true; + super.idleTimeout(1000, TimeUnit.DAYS); // >30 days disables timeouts entirely. + return this; + } + + @Override + public BinderChannelBuilder idleTimeout(long value, TimeUnit unit) { + checkState(!strictLifecycleManagement, "Idle timeouts are not supported when strict lifecycle management is enabled"); + super.idleTimeout(value, unit); + return this; + } + /** Creates new binder transports. */ private static final class TransportFactory implements ClientTransportFactory { private final Context sourceContext; diff --git a/binder/src/test/java/io/grpc/binder/BinderChannelBuilderTest.java b/binder/src/test/java/io/grpc/binder/BinderChannelBuilderTest.java new file mode 100644 index 00000000000..5dd7e13107e --- /dev/null +++ b/binder/src/test/java/io/grpc/binder/BinderChannelBuilderTest.java @@ -0,0 +1,44 @@ +/* + * Copyright 2020 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. + */ + +package io.grpc.binder; + +import static org.junit.Assert.fail; + +import android.content.Context; +import androidx.test.core.app.ApplicationProvider; +import java.util.concurrent.TimeUnit; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public final class BinderChannelBuilderTest { + private final Context appContext = ApplicationProvider.getApplicationContext(); + private final AndroidComponentAddress addr = AndroidComponentAddress.forContext(appContext); + + @Test + public void strictLifecycleManagementForbidsIdleTimers() { + BinderChannelBuilder builder = BinderChannelBuilder.forAddress(addr, appContext); + builder.strictLifecycleManagement(); + try { + builder.idleTimeout(10, TimeUnit.SECONDS); + fail(); + } catch (IllegalStateException ise) { + // Expected. + } + } +} From 548d3cac388defaabc1e530147748ca9125d3b5c Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Tue, 29 Nov 2022 09:54:12 -0800 Subject: [PATCH 15/39] MAINTAINERS.md: Add Binder maintainers --- MAINTAINERS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index a81b51bc3dc..f05542e1987 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -9,7 +9,9 @@ for general contribution guidelines. ## Maintainers (in alphabetical order) - [ejona86](https://github.com/ejona86), Google LLC +- [jdcormie](https://github.com/jdcormie), Google LLC - [larry-safran](https://github.com/larry-safran), Google LLC +- [markb74](https://github.com/markb74), Google LLC - [ran-su](https://github.com/ran-su), Google LLC - [sanjaypujare](https://github.com/sanjaypujare), Google LLC - [sergiitk](https://github.com/sergiitk), Google LLC From 5cf54f3178b515911df07acc83d4f04ae928de32 Mon Sep 17 00:00:00 2001 From: Terry Wilson Date: Tue, 29 Nov 2022 13:15:28 -0800 Subject: [PATCH 16/39] xds: Support localities in multiple priorities (#9683) Additional logic to support for the same locality appearing under multiple priorities. --- .../grpc/xds/ClusterResolverLoadBalancer.java | 20 ++--- .../io/grpc/xds/InternalXdsAttributes.java | 5 +- .../io/grpc/xds/WrrLocalityLoadBalancer.java | 46 ++++++---- .../xds/ClusterResolverLoadBalancerTest.java | 35 +++++--- .../grpc/xds/WrrLocalityLoadBalancerTest.java | 90 ++++++++++++++----- 5 files changed, 124 insertions(+), 72 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancer.java b/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancer.java index ca481e5691e..3af58ef93cb 100644 --- a/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancer.java +++ b/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancer.java @@ -216,7 +216,6 @@ private void handleEndpointResourceUpdate() { List addresses = new ArrayList<>(); Map priorityChildConfigs = new HashMap<>(); List priorities = new ArrayList<>(); // totally ordered priority list - Map localityWeights = new HashMap<>(); Status endpointNotFound = Status.OK; for (String cluster : clusters) { @@ -229,7 +228,6 @@ private void handleEndpointResourceUpdate() { addresses.addAll(state.result.addresses); priorityChildConfigs.putAll(state.result.priorityChildConfigs); priorities.addAll(state.result.priorities); - localityWeights.putAll(state.result.localityWeights); } else { endpointNotFound = state.status; } @@ -260,9 +258,6 @@ private void handleEndpointResourceUpdate() { resolvedAddresses.toBuilder() .setLoadBalancingPolicyConfig(childConfig) .setAddresses(Collections.unmodifiableList(addresses)) - .setAttributes(resolvedAddresses.getAttributes().toBuilder() - .set(InternalXdsAttributes.ATTR_LOCALITY_WEIGHTS, - Collections.unmodifiableMap(localityWeights)).build()) .build()); } @@ -396,7 +391,6 @@ public void run() { } Map localityLbEndpoints = update.localityLbEndpointsMap; - Map localityWeights = new HashMap<>(); List dropOverloads = update.dropPolicies; List addresses = new ArrayList<>(); Map> prioritizedLocalityWeights = new HashMap<>(); @@ -415,6 +409,8 @@ public void run() { Attributes attr = endpoint.eag().getAttributes().toBuilder() .set(InternalXdsAttributes.ATTR_LOCALITY, locality) + .set(InternalXdsAttributes.ATTR_LOCALITY_WEIGHT, + localityLbInfo.localityWeight()) .set(InternalXdsAttributes.ATTR_SERVER_WEIGHT, weight) .build(); EquivalentAddressGroup eag = new EquivalentAddressGroup( @@ -429,7 +425,6 @@ public void run() { "Discard locality {0} with 0 healthy endpoints", locality); continue; } - localityWeights.put(locality, localityLbInfo.localityWeight()); if (!prioritizedLocalityWeights.containsKey(priorityName)) { prioritizedLocalityWeights.put(priorityName, new HashMap()); } @@ -450,7 +445,7 @@ public void run() { status = Status.OK; resolved = true; result = new ClusterResolutionResult(addresses, priorityChildConfigs, - sortedPriorityNames, localityWeights); + sortedPriorityNames); handleEndpointResourceUpdate(); } } @@ -690,23 +685,18 @@ private static class ClusterResolutionResult { private final Map priorityChildConfigs; // List of priority names ordered in descending priorities. private final List priorities; - // Most recent view on how localities in the cluster should be wighted. Only set for EDS - // clusters that support the concept. - private final Map localityWeights; ClusterResolutionResult(List addresses, String priority, PriorityChildConfig config) { this(addresses, Collections.singletonMap(priority, config), - Collections.singletonList(priority), Collections.emptyMap()); + Collections.singletonList(priority)); } ClusterResolutionResult(List addresses, - Map configs, List priorities, - Map localityWeights) { + Map configs, List priorities) { this.addresses = addresses; this.priorityChildConfigs = configs; this.priorities = priorities; - this.localityWeights = localityWeights; } } diff --git a/xds/src/main/java/io/grpc/xds/InternalXdsAttributes.java b/xds/src/main/java/io/grpc/xds/InternalXdsAttributes.java index 448e5fbd258..bd21a8ac13e 100644 --- a/xds/src/main/java/io/grpc/xds/InternalXdsAttributes.java +++ b/xds/src/main/java/io/grpc/xds/InternalXdsAttributes.java @@ -24,7 +24,6 @@ import io.grpc.internal.ObjectPool; import io.grpc.xds.XdsNameResolverProvider.CallCounterProvider; import io.grpc.xds.internal.security.SslContextProviderSupplier; -import java.util.Map; /** * Internal attributes used for xDS implementation. Do not use. @@ -58,8 +57,8 @@ public final class InternalXdsAttributes { * Map from localities to their weights. */ @NameResolver.ResolutionResultAttr - static final Attributes.Key> ATTR_LOCALITY_WEIGHTS = - Attributes.Key.create("io.grpc.xds.InternalXdsAttributes.localityWeights"); + static final Attributes.Key ATTR_LOCALITY_WEIGHT = + Attributes.Key.create("io.grpc.xds.InternalXdsAttributes.localityWeight"); /** * Name of the cluster that provides this EquivalentAddressGroup. diff --git a/xds/src/main/java/io/grpc/xds/WrrLocalityLoadBalancer.java b/xds/src/main/java/io/grpc/xds/WrrLocalityLoadBalancer.java index a961db02cce..b9196492624 100644 --- a/xds/src/main/java/io/grpc/xds/WrrLocalityLoadBalancer.java +++ b/xds/src/main/java/io/grpc/xds/WrrLocalityLoadBalancer.java @@ -21,6 +21,8 @@ import static io.grpc.xds.XdsLbPolicies.WEIGHTED_TARGET_POLICY_NAME; import com.google.common.base.MoreObjects; +import io.grpc.Attributes; +import io.grpc.EquivalentAddressGroup; import io.grpc.InternalLogId; import io.grpc.LoadBalancer; import io.grpc.LoadBalancerRegistry; @@ -68,15 +70,33 @@ public boolean acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) { // to produce the weighted target LB config. WrrLocalityConfig wrrLocalityConfig = (WrrLocalityConfig) resolvedAddresses.getLoadBalancingPolicyConfig(); - Map localityWeights = resolvedAddresses.getAttributes() - .get(InternalXdsAttributes.ATTR_LOCALITY_WEIGHTS); - - // Not having locality weights is a misconfiguration, and we have to return with an error. - if (localityWeights == null) { - Status unavailable = - Status.UNAVAILABLE.withDescription("wrr_locality error: no locality weights provided"); - helper.updateBalancingState(TRANSIENT_FAILURE, new ErrorPicker(unavailable)); - return false; + + // A map of locality weights is built up from the locality weight attributes in each address. + Map localityWeights = new HashMap<>(); + for (EquivalentAddressGroup eag : resolvedAddresses.getAddresses()) { + Attributes eagAttrs = eag.getAttributes(); + Locality locality = eagAttrs.get(InternalXdsAttributes.ATTR_LOCALITY); + Integer localityWeight = eagAttrs.get(InternalXdsAttributes.ATTR_LOCALITY_WEIGHT); + + if (locality == null) { + helper.updateBalancingState(TRANSIENT_FAILURE, new ErrorPicker( + Status.UNAVAILABLE.withDescription("wrr_locality error: no locality provided"))); + return false; + } + if (localityWeight == null) { + helper.updateBalancingState(TRANSIENT_FAILURE, new ErrorPicker( + Status.UNAVAILABLE.withDescription( + "wrr_locality error: no weight provided for locality " + locality))); + return false; + } + + if (!localityWeights.containsKey(locality)) { + localityWeights.put(locality, localityWeight); + } else if (!localityWeights.get(locality).equals(localityWeight)) { + logger.log(XdsLogLevel.WARNING, + "Locality {0} has both weights {1} and {2}, using weight {1}", locality, + localityWeights.get(locality), localityWeight); + } } // Weighted target LB expects a WeightedPolicySelection for each locality as it will create a @@ -88,14 +108,6 @@ public boolean acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) { wrrLocalityConfig.childPolicy)); } - // Remove the locality weights attribute now that we have consumed it. This is done simply for - // ease of debugging for the unsupported (and unlikely) scenario where WrrLocalityConfig has - // another wrr_locality as the child policy. The missing locality weight attribute would make - // the child wrr_locality fail early. - resolvedAddresses = resolvedAddresses.toBuilder() - .setAttributes(resolvedAddresses.getAttributes().toBuilder() - .discard(InternalXdsAttributes.ATTR_LOCALITY_WEIGHTS).build()).build(); - switchLb.switchTo(lbRegistry.getProvider(WEIGHTED_TARGET_POLICY_NAME)); switchLb.handleResolvedAddresses( resolvedAddresses.toBuilder() diff --git a/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java b/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java index b4b709d2ae2..4d58f88e0e8 100644 --- a/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java +++ b/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java @@ -327,8 +327,8 @@ public void edsClustersWithLeastRequestEndpointLbPolicy() { "least_request_experimental"); assertThat( - childBalancer.attributes.get(InternalXdsAttributes.ATTR_LOCALITY_WEIGHTS)).containsEntry( - locality1, 100); + childBalancer.addresses.get(0).getAttributes() + .get(InternalXdsAttributes.ATTR_LOCALITY_WEIGHT)).isEqualTo(100); } @Test @@ -410,8 +410,8 @@ public void edsClustersWithOutlierDetection() { "least_request_experimental"); assertThat( - childBalancer.attributes.get(InternalXdsAttributes.ATTR_LOCALITY_WEIGHTS)).containsEntry( - locality1, 100); + childBalancer.addresses.get(0).getAttributes() + .get(InternalXdsAttributes.ATTR_LOCALITY_WEIGHT)).isEqualTo(100); } @@ -507,11 +507,20 @@ public void onlyEdsClusters_receivedEndpoints() { assertThat(wrrLocalityConfig3.childPolicy.getProvider().getPolicyName()).isEqualTo( "round_robin"); - Map localityWeights = childBalancer.attributes.get( - InternalXdsAttributes.ATTR_LOCALITY_WEIGHTS); - assertThat(localityWeights).containsEntry(locality1, 70); - assertThat(localityWeights).containsEntry(locality2, 10); - assertThat(localityWeights).containsEntry(locality3, 20); + for (EquivalentAddressGroup eag : childBalancer.addresses) { + if (eag.getAttributes().get(InternalXdsAttributes.ATTR_LOCALITY) == locality1) { + assertThat(eag.getAttributes().get(InternalXdsAttributes.ATTR_LOCALITY_WEIGHT)) + .isEqualTo(70); + } + if (eag.getAttributes().get(InternalXdsAttributes.ATTR_LOCALITY) == locality2) { + assertThat(eag.getAttributes().get(InternalXdsAttributes.ATTR_LOCALITY_WEIGHT)) + .isEqualTo(10); + } + if (eag.getAttributes().get(InternalXdsAttributes.ATTR_LOCALITY) == locality3) { + assertThat(eag.getAttributes().get(InternalXdsAttributes.ATTR_LOCALITY_WEIGHT)) + .isEqualTo(20); + } + } } @SuppressWarnings("unchecked") @@ -687,9 +696,9 @@ public void handleEdsResource_ignoreLocalitiesWithNoHealthyEndpoints() { ImmutableMap.of(locality1, localityLbEndpoints1, locality2, localityLbEndpoints2)); FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); - Map localityWeights = childBalancer.attributes.get( - InternalXdsAttributes.ATTR_LOCALITY_WEIGHTS); - assertThat(localityWeights.keySet()).containsExactly(locality2); + for (EquivalentAddressGroup eag : childBalancer.addresses) { + assertThat(eag.getAttributes().get(InternalXdsAttributes.ATTR_LOCALITY)).isEqualTo(locality2); + } } @Test @@ -1315,7 +1324,6 @@ private final class FakeLoadBalancer extends LoadBalancer { private final Helper helper; private List addresses; private Object config; - private Attributes attributes; private Status upstreamError; private boolean shutdown; @@ -1328,7 +1336,6 @@ private final class FakeLoadBalancer extends LoadBalancer { public boolean acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) { addresses = resolvedAddresses.getAddresses(); config = resolvedAddresses.getLoadBalancingPolicyConfig(); - attributes = resolvedAddresses.getAttributes(); return true; } diff --git a/xds/src/test/java/io/grpc/xds/WrrLocalityLoadBalancerTest.java b/xds/src/test/java/io/grpc/xds/WrrLocalityLoadBalancerTest.java index 29777a5284f..344876aa348 100644 --- a/xds/src/test/java/io/grpc/xds/WrrLocalityLoadBalancerTest.java +++ b/xds/src/test/java/io/grpc/xds/WrrLocalityLoadBalancerTest.java @@ -25,7 +25,6 @@ import static org.mockito.Mockito.when; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; import com.google.common.testing.EqualsTester; import io.grpc.Attributes; import io.grpc.ConnectivityState; @@ -44,7 +43,9 @@ import io.grpc.xds.WrrLocalityLoadBalancer.WrrLocalityConfig; import io.grpc.xds.XdsSubchannelPickers.ErrorPicker; import java.net.SocketAddress; -import java.util.Map; +import java.util.Collections; +import java.util.List; +import java.util.Objects; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -74,8 +75,6 @@ public class WrrLocalityLoadBalancerTest { private LoadBalancer mockChildLb; @Mock private Helper mockHelper; - @Mock - private SocketAddress mockSocketAddress; @Captor private ArgumentCaptor resolvedAddressesCaptor; @@ -84,8 +83,6 @@ public class WrrLocalityLoadBalancerTest { @Captor private ArgumentCaptor errorPickerCaptor; - private final EquivalentAddressGroup eag = new EquivalentAddressGroup(mockSocketAddress); - private WrrLocalityLoadBalancer loadBalancer; private LoadBalancerRegistry lbRegistry = new LoadBalancerRegistry(); @@ -124,8 +121,10 @@ public void handleResolvedAddresses() { // The child config is delivered wrapped in the wrr_locality config and the locality weights // in a ResolvedAddresses attribute. WrrLocalityConfig wlConfig = new WrrLocalityConfig(childPolicy); - Map localityWeights = ImmutableMap.of(localityOne, 1, localityTwo, 2); - deliverAddresses(wlConfig, localityWeights); + deliverAddresses(wlConfig, + ImmutableList.of( + makeAddress("addr1", localityOne, 1), + makeAddress("addr2", localityTwo, 2))); // Assert that the child policy and the locality weights were correctly mapped to a // WeightedTargetConfig. @@ -148,7 +147,8 @@ public void handleResolvedAddresses_noLocalityWeights() { // The child config is delivered wrapped in the wrr_locality config and the locality weights // in a ResolvedAddresses attribute. WrrLocalityConfig wlConfig = new WrrLocalityConfig(childPolicy); - deliverAddresses(wlConfig, null); + deliverAddresses(wlConfig, ImmutableList.of( + makeAddress("addr", Locality.create("test-region", "test-zone", "test-subzone"), null))); // With no locality weights, we should get a TRANSIENT_FAILURE. verify(mockHelper).getAuthority(); @@ -170,8 +170,8 @@ public void handleNameResolutionError_noChildLb() { @Test public void handleNameResolutionError_withChildLb() { deliverAddresses(new WrrLocalityConfig(new PolicySelection(mockChildProvider, null)), - ImmutableMap.of( - Locality.create("region", "zone", "subzone"), 1)); + ImmutableList.of( + makeAddress("addr1", Locality.create("test-region1", "test-zone", "test-subzone"), 1))); loadBalancer.handleNameResolutionError(Status.DEADLINE_EXCEEDED); verify(mockHelper, never()).updateBalancingState(isA(ConnectivityState.class), @@ -181,25 +181,25 @@ public void handleNameResolutionError_withChildLb() { @Test public void localityWeightAttributeNotPropagated() { - Locality locality = Locality.create("region1", "zone1", "subzone1"); PolicySelection childPolicy = new PolicySelection(mockChildProvider, null); WrrLocalityConfig wlConfig = new WrrLocalityConfig(childPolicy); - Map localityWeights = ImmutableMap.of(locality, 1); - deliverAddresses(wlConfig, localityWeights); + deliverAddresses(wlConfig, ImmutableList.of( + makeAddress("addr1", Locality.create("test-region1", "test-zone", "test-subzone"), 1))); // Assert that the child policy and the locality weights were correctly mapped to a // WeightedTargetConfig. verify(mockWeightedTargetLb).handleResolvedAddresses(resolvedAddressesCaptor.capture()); - assertThat(resolvedAddressesCaptor.getValue().getAttributes() - .get(InternalXdsAttributes.ATTR_LOCALITY_WEIGHTS)).isNull(); + + //assertThat(resolvedAddressesCaptor.getValue().getAttributes() + // .get(InternalXdsAttributes.ATTR_LOCALITY_WEIGHTS)).isNull(); } @Test public void shutdown() { deliverAddresses(new WrrLocalityConfig(new PolicySelection(mockChildProvider, null)), - ImmutableMap.of( - Locality.create("region", "zone", "subzone"), 1)); + ImmutableList.of( + makeAddress("addr", Locality.create("test-region", "test-zone", "test-subzone"), 1))); loadBalancer.shutdown(); verify(mockWeightedTargetLb).shutdown(); @@ -218,11 +218,55 @@ public void configEquality() { .testEquals(); } - private void deliverAddresses(WrrLocalityConfig config, Map localityWeights) { + private void deliverAddresses(WrrLocalityConfig config, List addresses) { loadBalancer.handleResolvedAddresses( - ResolvedAddresses.newBuilder().setAddresses(ImmutableList.of(eag)).setAttributes( - Attributes.newBuilder() - .set(InternalXdsAttributes.ATTR_LOCALITY_WEIGHTS, localityWeights).build()) - .setLoadBalancingPolicyConfig(config).build()); + ResolvedAddresses.newBuilder().setAddresses(addresses).setLoadBalancingPolicyConfig(config) + .build()); + } + + /** + * Create a locality-labeled address. + */ + private static EquivalentAddressGroup makeAddress(final String name, Locality locality, + Integer localityWeight) { + class FakeSocketAddress extends SocketAddress { + private final String name; + + private FakeSocketAddress(String name) { + this.name = name; + } + + @Override + public int hashCode() { + return Objects.hash(name); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof FakeSocketAddress)) { + return false; + } + FakeSocketAddress that = (FakeSocketAddress) o; + return Objects.equals(name, that.name); + } + + @Override + public String toString() { + return name; + } + } + + Attributes.Builder attrBuilder = Attributes.newBuilder() + .set(InternalXdsAttributes.ATTR_LOCALITY, locality); + if (localityWeight != null) { + attrBuilder.set(InternalXdsAttributes.ATTR_LOCALITY_WEIGHT, localityWeight); + } + + EquivalentAddressGroup eag = new EquivalentAddressGroup(new FakeSocketAddress(name), + attrBuilder.build()); + return AddressFilter.setPathFilter(eag, Collections.singletonList(locality.toString())); } } From a5f458a3a731e00ad8addef8c3b5edccc2c19582 Mon Sep 17 00:00:00 2001 From: apolcyn Date: Tue, 29 Nov 2022 14:02:48 -0800 Subject: [PATCH 17/39] xds: Limit ring hash max size to 4K (#9709) Implements grpc/proposal#338 for Java. --- .../xds/RingHashLoadBalancerProvider.java | 17 ++-- .../java/io/grpc/xds/RingHashOptions.java | 62 ++++++++++++++ .../xds/RingHashLoadBalancerProviderTest.java | 81 +++++++++++++++++-- 3 files changed, 147 insertions(+), 13 deletions(-) create mode 100644 xds/src/main/java/io/grpc/xds/RingHashOptions.java diff --git a/xds/src/main/java/io/grpc/xds/RingHashLoadBalancerProvider.java b/xds/src/main/java/io/grpc/xds/RingHashLoadBalancerProvider.java index 84c6dedf631..5bba0dc9b0a 100644 --- a/xds/src/main/java/io/grpc/xds/RingHashLoadBalancerProvider.java +++ b/xds/src/main/java/io/grpc/xds/RingHashLoadBalancerProvider.java @@ -26,6 +26,7 @@ import io.grpc.Status; import io.grpc.internal.JsonUtil; import io.grpc.xds.RingHashLoadBalancer.RingHashConfig; +import io.grpc.xds.RingHashOptions; import java.util.Map; /** @@ -39,11 +40,7 @@ public final class RingHashLoadBalancerProvider extends LoadBalancerProvider { static final long DEFAULT_MIN_RING_SIZE = 1024L; // Same as ClientXdsClient.DEFAULT_RING_HASH_LB_POLICY_MAX_RING_SIZE @VisibleForTesting - static final long DEFAULT_MAX_RING_SIZE = 8 * 1024 * 1024L; - // Maximum number of ring entries allowed. Setting this too large can result in slow - // ring construction and OOM error. - // Same as ClientXdsClient.MAX_RING_HASH_LB_POLICY_RING_SIZE - static final long MAX_RING_SIZE = 8 * 1024 * 1024L; + static final long DEFAULT_MAX_RING_SIZE = 4 * 1024L; private static final boolean enableRingHash = Strings.isNullOrEmpty(System.getenv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH")) @@ -73,14 +70,20 @@ public String getPolicyName() { public ConfigOrError parseLoadBalancingPolicyConfig(Map rawLoadBalancingPolicyConfig) { Long minRingSize = JsonUtil.getNumberAsLong(rawLoadBalancingPolicyConfig, "minRingSize"); Long maxRingSize = JsonUtil.getNumberAsLong(rawLoadBalancingPolicyConfig, "maxRingSize"); + long maxRingSizeCap = RingHashOptions.getRingSizeCap(); if (minRingSize == null) { minRingSize = DEFAULT_MIN_RING_SIZE; } if (maxRingSize == null) { maxRingSize = DEFAULT_MAX_RING_SIZE; } - if (minRingSize <= 0 || maxRingSize <= 0 || minRingSize > maxRingSize - || maxRingSize > MAX_RING_SIZE) { + if (minRingSize > maxRingSizeCap) { + minRingSize = maxRingSizeCap; + } + if (maxRingSize > maxRingSizeCap) { + maxRingSize = maxRingSizeCap; + } + if (minRingSize <= 0 || maxRingSize <= 0 || minRingSize > maxRingSize) { return ConfigOrError.fromError(Status.UNAVAILABLE.withDescription( "Invalid 'mingRingSize'/'maxRingSize'")); } diff --git a/xds/src/main/java/io/grpc/xds/RingHashOptions.java b/xds/src/main/java/io/grpc/xds/RingHashOptions.java new file mode 100644 index 00000000000..6bb3fc7887e --- /dev/null +++ b/xds/src/main/java/io/grpc/xds/RingHashOptions.java @@ -0,0 +1,62 @@ +/* + * Copyright 2021 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. + */ + +package io.grpc.xds; + +import com.google.common.annotations.VisibleForTesting; +import io.grpc.ExperimentalApi; + +/** + * Utility class that provides a way to configure ring hash size limits. This is applicable + * for clients that use the ring hash load balancing policy. Note that size limits involve + * a tradeoff between client memory consumption and accuracy of load balancing weight + * representations. Also see https://github.com/grpc/proposal/pull/338. + */ +@ExperimentalApi("https://github.com/grpc/grpc-java/issues/9718") +public final class RingHashOptions { + // Same as ClientXdsClient.DEFAULT_RING_HASH_LB_POLICY_MAX_RING_SIZE + @VisibleForTesting + static final long MAX_RING_SIZE_CAP = 8 * 1024 * 1024L; + @VisibleForTesting + // Same as RingHashLoadBalancerProvider.DEFAULT_MAX_RING_SIZE + static final long DEFAULT_RING_SIZE_CAP = 4 * 1024L; + + // Limits ring hash sizes to restrict client memory usage. + private static volatile long ringSizeCap = DEFAULT_RING_SIZE_CAP; + + private RingHashOptions() {} // Prevent instantiation + + /** + * Set the global limit for the min and max number of ring hash entries per ring. + * Note that this limit is clamped between 1 entry and 8,388,608 entries, and new + * limits lying outside that range will be silently moved to the nearest number within + * that range. Defaults initially to 4096 entries. + */ + @ExperimentalApi("https://github.com/grpc/grpc-java/issues/9718") + public static void setRingSizeCap(long ringSizeCap) { + ringSizeCap = Math.max(1, ringSizeCap); + ringSizeCap = Math.min(MAX_RING_SIZE_CAP, ringSizeCap); + RingHashOptions.ringSizeCap = ringSizeCap; + } + + /** + * Get the global limit for min and max ring hash sizes. + */ + @ExperimentalApi("https://github.com/grpc/grpc-java/issues/9718") + public static long getRingSizeCap() { + return RingHashOptions.ringSizeCap; + } +} diff --git a/xds/src/test/java/io/grpc/xds/RingHashLoadBalancerProviderTest.java b/xds/src/test/java/io/grpc/xds/RingHashLoadBalancerProviderTest.java index 9f972eaef92..87615a125c0 100644 --- a/xds/src/test/java/io/grpc/xds/RingHashLoadBalancerProviderTest.java +++ b/xds/src/test/java/io/grpc/xds/RingHashLoadBalancerProviderTest.java @@ -29,6 +29,7 @@ import io.grpc.SynchronizationContext; import io.grpc.internal.JsonParser; import io.grpc.xds.RingHashLoadBalancer.RingHashConfig; +import io.grpc.xds.RingHashOptions; import java.io.IOException; import java.lang.Thread.UncaughtExceptionHandler; import java.util.Locale; @@ -116,16 +117,84 @@ public void parseLoadBalancingConfig_invalid_minGreaterThanMax() throws IOExcept } @Test - public void parseLoadBalancingConfig_invalid_ringTooLarge() throws IOException { - long ringSize = RingHashLoadBalancerProvider.MAX_RING_SIZE + 1; + public void parseLoadBalancingConfig_ringTooLargeUsesCap() throws IOException { + long ringSize = RingHashOptions.MAX_RING_SIZE_CAP + 1; String lbConfig = String.format(Locale.US, "{\"minRingSize\" : 10, \"maxRingSize\" : %d}", ringSize); ConfigOrError configOrError = provider.parseLoadBalancingPolicyConfig(parseJsonObject(lbConfig)); - assertThat(configOrError.getError()).isNotNull(); - assertThat(configOrError.getError().getCode()).isEqualTo(Code.UNAVAILABLE); - assertThat(configOrError.getError().getDescription()) - .isEqualTo("Invalid 'mingRingSize'/'maxRingSize'"); + assertThat(configOrError.getConfig()).isNotNull(); + RingHashConfig config = (RingHashConfig) configOrError.getConfig(); + assertThat(config.minRingSize).isEqualTo(10); + assertThat(config.maxRingSize).isEqualTo(RingHashOptions.DEFAULT_RING_SIZE_CAP); + } + + @Test + public void parseLoadBalancingConfig_ringCapCanBeRaised() throws IOException { + RingHashOptions.setRingSizeCap(RingHashOptions.MAX_RING_SIZE_CAP); + long ringSize = RingHashOptions.MAX_RING_SIZE_CAP; + String lbConfig = + String.format( + Locale.US, "{\"minRingSize\" : %d, \"maxRingSize\" : %d}", ringSize, ringSize); + ConfigOrError configOrError = + provider.parseLoadBalancingPolicyConfig(parseJsonObject(lbConfig)); + assertThat(configOrError.getConfig()).isNotNull(); + RingHashConfig config = (RingHashConfig) configOrError.getConfig(); + assertThat(config.minRingSize).isEqualTo(RingHashOptions.MAX_RING_SIZE_CAP); + assertThat(config.maxRingSize).isEqualTo(RingHashOptions.MAX_RING_SIZE_CAP); + // Reset to avoid affecting subsequent test cases + RingHashOptions.setRingSizeCap(RingHashOptions.DEFAULT_RING_SIZE_CAP); + } + + @Test + public void parseLoadBalancingConfig_ringCapIsClampedTo8M() throws IOException { + RingHashOptions.setRingSizeCap(RingHashOptions.MAX_RING_SIZE_CAP + 1); + long ringSize = RingHashOptions.MAX_RING_SIZE_CAP + 1; + String lbConfig = + String.format( + Locale.US, "{\"minRingSize\" : %d, \"maxRingSize\" : %d}", ringSize, ringSize); + ConfigOrError configOrError = + provider.parseLoadBalancingPolicyConfig(parseJsonObject(lbConfig)); + assertThat(configOrError.getConfig()).isNotNull(); + RingHashConfig config = (RingHashConfig) configOrError.getConfig(); + assertThat(config.minRingSize).isEqualTo(RingHashOptions.MAX_RING_SIZE_CAP); + assertThat(config.maxRingSize).isEqualTo(RingHashOptions.MAX_RING_SIZE_CAP); + // Reset to avoid affecting subsequent test cases + RingHashOptions.setRingSizeCap(RingHashOptions.DEFAULT_RING_SIZE_CAP); + } + + @Test + public void parseLoadBalancingConfig_ringCapCanBeLowered() throws IOException { + RingHashOptions.setRingSizeCap(1); + long ringSize = 2; + String lbConfig = + String.format( + Locale.US, "{\"minRingSize\" : %d, \"maxRingSize\" : %d}", ringSize, ringSize); + ConfigOrError configOrError = + provider.parseLoadBalancingPolicyConfig(parseJsonObject(lbConfig)); + assertThat(configOrError.getConfig()).isNotNull(); + RingHashConfig config = (RingHashConfig) configOrError.getConfig(); + assertThat(config.minRingSize).isEqualTo(1); + assertThat(config.maxRingSize).isEqualTo(1); + // Reset to avoid affecting subsequent test cases + RingHashOptions.setRingSizeCap(RingHashOptions.DEFAULT_RING_SIZE_CAP); + } + + @Test + public void parseLoadBalancingConfig_ringCapLowerLimitIs1() throws IOException { + RingHashOptions.setRingSizeCap(0); + long ringSize = 2; + String lbConfig = + String.format( + Locale.US, "{\"minRingSize\" : %d, \"maxRingSize\" : %d}", ringSize, ringSize); + ConfigOrError configOrError = + provider.parseLoadBalancingPolicyConfig(parseJsonObject(lbConfig)); + assertThat(configOrError.getConfig()).isNotNull(); + RingHashConfig config = (RingHashConfig) configOrError.getConfig(); + assertThat(config.minRingSize).isEqualTo(1); + assertThat(config.maxRingSize).isEqualTo(1); + // Reset to avoid affecting subsequent test cases + RingHashOptions.setRingSizeCap(RingHashOptions.DEFAULT_RING_SIZE_CAP); } @Test From d6aa0ea3701f29e8275d61d330781e2088768bde Mon Sep 17 00:00:00 2001 From: cbianchi-7 <116770018+cbianchi-7@users.noreply.github.com> Date: Wed, 30 Nov 2022 10:37:32 -0800 Subject: [PATCH 18/39] binder: Promote out of experimental status (#9669) --- .../grpc/binder/AndroidComponentAddress.java | 8 +++-- .../java/io/grpc/binder/BinderInternal.java | 34 +++++++++++++++++++ .../io/grpc/binder/BinderServerBuilder.java | 16 ++++----- .../java/io/grpc/binder/IBinderReceiver.java | 8 ++--- .../java/io/grpc/binder/ParcelableUtils.java | 2 -- .../java/io/grpc/binder/SecurityPolicies.java | 9 ++++- .../java/io/grpc/binder/SecurityPolicy.java | 2 -- .../io/grpc/binder/ServerSecurityPolicy.java | 2 -- 8 files changed, 57 insertions(+), 24 deletions(-) create mode 100644 binder/src/main/java/io/grpc/binder/BinderInternal.java diff --git a/binder/src/main/java/io/grpc/binder/AndroidComponentAddress.java b/binder/src/main/java/io/grpc/binder/AndroidComponentAddress.java index cb4f7f794cf..8a70f28021f 100644 --- a/binder/src/main/java/io/grpc/binder/AndroidComponentAddress.java +++ b/binder/src/main/java/io/grpc/binder/AndroidComponentAddress.java @@ -22,7 +22,6 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import io.grpc.ExperimentalApi; import java.net.SocketAddress; /** @@ -41,8 +40,7 @@ * fields, namely, an action of {@link ApiConstants#ACTION_BIND}, an empty category set and null * type and data URI. */ -@ExperimentalApi("https://github.com/grpc/grpc-java/issues/8022") -public class AndroidComponentAddress extends SocketAddress { // NOTE: Only temporarily non-final. +public final class AndroidComponentAddress extends SocketAddress { private static final long serialVersionUID = 0L; private final Intent bindIntent; // An "explicit" Intent. In other words, getComponent() != null. @@ -103,6 +101,10 @@ public static AndroidComponentAddress forComponent(ComponentName component) { new Intent(ApiConstants.ACTION_BIND).setComponent(component)); } + /** + * Returns the Authority which is the package name of the target app. + * See {@link android.content.ComponentName}. + */ public String getAuthority() { return getComponent().getPackageName(); } diff --git a/binder/src/main/java/io/grpc/binder/BinderInternal.java b/binder/src/main/java/io/grpc/binder/BinderInternal.java new file mode 100644 index 00000000000..ba7d78b2888 --- /dev/null +++ b/binder/src/main/java/io/grpc/binder/BinderInternal.java @@ -0,0 +1,34 @@ +/* + * Copyright 2022 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. + */ + +package io.grpc.binder; + +import android.os.IBinder; +import io.grpc.Internal; + +/** + * Helper class to expose IBinderReceiver methods for legacy internal builders. + */ +@Internal +public class BinderInternal { + + /** + * Set the receiver's {@link IBinder} using {@link IBinderReceiver#set(IBinder)}. + */ + static void setIBinder(IBinderReceiver receiver, IBinder binder) { + receiver.set(binder); + } +} diff --git a/binder/src/main/java/io/grpc/binder/BinderServerBuilder.java b/binder/src/main/java/io/grpc/binder/BinderServerBuilder.java index c4674a76bbe..f37c522863d 100644 --- a/binder/src/main/java/io/grpc/binder/BinderServerBuilder.java +++ b/binder/src/main/java/io/grpc/binder/BinderServerBuilder.java @@ -23,8 +23,6 @@ import android.os.IBinder; import com.google.common.base.Supplier; import com.google.errorprone.annotations.DoNotCall; -import io.grpc.CompressorRegistry; -import io.grpc.DecompressorRegistry; import io.grpc.ExperimentalApi; import io.grpc.Server; import io.grpc.ServerBuilder; @@ -48,7 +46,6 @@ /** * Builder for a server that services requests from an Android Service. */ -@ExperimentalApi("https://github.com/grpc/grpc-java/issues/8022") public final class BinderServerBuilder extends ForwardingServerBuilder { @@ -96,15 +93,10 @@ private BinderServerBuilder( streamTracerFactories, securityPolicy, inboundParcelablePolicy); - binderReceiver.set(server.getHostBinder()); + BinderInternal.setIBinder(binderReceiver, server.getHostBinder()); return server; }); - // Disable compression by default, since there's little benefit when all communication is - // on-device, and it means sending supported-encoding headers with every call. - decompressorRegistry(DecompressorRegistry.emptyInstance()); - compressorRegistry(CompressorRegistry.newEmptyInstance()); - // Disable stats and tracing by default. serverImplBuilder.setStatsEnabled(false); serverImplBuilder.setTracingEnabled(false); @@ -116,12 +108,14 @@ protected ServerBuilder delegate() { } /** Enable stats collection using census. */ + @ExperimentalApi("https://github.com/grpc/grpc-java/issues/8022") public BinderServerBuilder enableStats() { serverImplBuilder.setStatsEnabled(true); return this; } /** Enable tracing using census. */ + @ExperimentalApi("https://github.com/grpc/grpc-java/issues/8022") public BinderServerBuilder enableTracing() { serverImplBuilder.setTracingEnabled(true); return this; @@ -156,12 +150,16 @@ public BinderServerBuilder securityPolicy(ServerSecurityPolicy securityPolicy) { } /** Sets the policy for inbound parcelable objects. */ + @ExperimentalApi("https://github.com/grpc/grpc-java/issues/8022") public BinderServerBuilder inboundParcelablePolicy( InboundParcelablePolicy inboundParcelablePolicy) { this.inboundParcelablePolicy = checkNotNull(inboundParcelablePolicy, "inboundParcelablePolicy"); return this; } + /** + * Always fails. TLS is not supported in BinderServer. + */ @Override public BinderServerBuilder useTransportSecurity(File certChain, File privateKey) { throw new UnsupportedOperationException("TLS not supported in BinderServer"); diff --git a/binder/src/main/java/io/grpc/binder/IBinderReceiver.java b/binder/src/main/java/io/grpc/binder/IBinderReceiver.java index bd8e1f50af9..adf4a0d3d8e 100644 --- a/binder/src/main/java/io/grpc/binder/IBinderReceiver.java +++ b/binder/src/main/java/io/grpc/binder/IBinderReceiver.java @@ -17,24 +17,22 @@ package io.grpc.binder; import android.os.IBinder; -import io.grpc.ExperimentalApi; import javax.annotation.Nullable; /** A container for at most one instance of {@link IBinder}, useful as an "out parameter". */ -@ExperimentalApi("https://github.com/grpc/grpc-java/issues/8022") public final class IBinderReceiver { - @Nullable private IBinder value; + @Nullable private volatile IBinder value; /** Constructs a new, initially empty, container. */ public IBinderReceiver() {} /** Returns the contents of this container or null if it is empty. */ @Nullable - public synchronized IBinder get() { + public IBinder get() { return value; } - public synchronized void set(IBinder value) { + protected void set(IBinder value) { this.value = value; } } diff --git a/binder/src/main/java/io/grpc/binder/ParcelableUtils.java b/binder/src/main/java/io/grpc/binder/ParcelableUtils.java index 164de7de8b8..969344ea68d 100644 --- a/binder/src/main/java/io/grpc/binder/ParcelableUtils.java +++ b/binder/src/main/java/io/grpc/binder/ParcelableUtils.java @@ -17,7 +17,6 @@ package io.grpc.binder; import android.os.Parcelable; -import io.grpc.ExperimentalApi; import io.grpc.Metadata; import io.grpc.binder.internal.MetadataHelper; @@ -26,7 +25,6 @@ * *

This class models the same pattern as the {@code ProtoLiteUtils} class. */ -@ExperimentalApi("https://github.com/grpc/grpc-java/issues/8022") public final class ParcelableUtils { private ParcelableUtils() {} diff --git a/binder/src/main/java/io/grpc/binder/SecurityPolicies.java b/binder/src/main/java/io/grpc/binder/SecurityPolicies.java index 653ae90bd77..6af47b726f5 100644 --- a/binder/src/main/java/io/grpc/binder/SecurityPolicies.java +++ b/binder/src/main/java/io/grpc/binder/SecurityPolicies.java @@ -42,7 +42,6 @@ /** Static factory methods for creating standard security policies. */ @CheckReturnValue -@ExperimentalApi("https://github.com/grpc/grpc-java/issues/8022") public final class SecurityPolicies { private static final int MY_UID = Process.myUid(); @@ -50,10 +49,14 @@ public final class SecurityPolicies { private SecurityPolicies() {} + @ExperimentalApi("https://github.com/grpc/grpc-java/issues/8022") public static ServerSecurityPolicy serverInternalOnly() { return new ServerSecurityPolicy(); } + /** + * Creates a default {@link SecurityPolicy} that checks authorization based on UID. + */ public static SecurityPolicy internalOnly() { return new SecurityPolicy() { @Override @@ -66,6 +69,7 @@ public Status checkAuthorization(int uid) { }; } + @ExperimentalApi("https://github.com/grpc/grpc-java/issues/8022") public static SecurityPolicy permissionDenied(String description) { Status denied = Status.PERMISSION_DENIED.withDescription(description); return new SecurityPolicy() { @@ -84,6 +88,7 @@ public Status checkAuthorization(int uid) { * @param requiredSignature the allowed signature of the allowed package. * @throws NullPointerException if any of the inputs are {@code null}. */ + @ExperimentalApi("https://github.com/grpc/grpc-java/issues/8022") public static SecurityPolicy hasSignature( PackageManager packageManager, String packageName, Signature requiredSignature) { return oneOfSignatures( @@ -99,6 +104,7 @@ public static SecurityPolicy hasSignature( * @throws NullPointerException if any of the inputs are {@code null}. * @throws IllegalArgumentException if {@code requiredSignatureSha256Hash} is not of length 32. */ + @ExperimentalApi("https://github.com/grpc/grpc-java/issues/8022") public static SecurityPolicy hasSignatureSha256Hash( PackageManager packageManager, String packageName, byte[] requiredSignatureSha256Hash) { return oneOfSignatureSha256Hash( @@ -114,6 +120,7 @@ public static SecurityPolicy hasSignatureSha256Hash( * @throws NullPointerException if any of the inputs are {@code null}. * @throws IllegalArgumentException if {@code requiredSignatures} is empty. */ + @ExperimentalApi("https://github.com/grpc/grpc-java/issues/8022") public static SecurityPolicy oneOfSignatures( PackageManager packageManager, String packageName, diff --git a/binder/src/main/java/io/grpc/binder/SecurityPolicy.java b/binder/src/main/java/io/grpc/binder/SecurityPolicy.java index d13f3a863fd..6b0fb40310a 100644 --- a/binder/src/main/java/io/grpc/binder/SecurityPolicy.java +++ b/binder/src/main/java/io/grpc/binder/SecurityPolicy.java @@ -16,7 +16,6 @@ package io.grpc.binder; -import io.grpc.ExperimentalApi; import io.grpc.Status; import javax.annotation.CheckReturnValue; @@ -37,7 +36,6 @@ * re-installation of the applications involved. */ @CheckReturnValue -@ExperimentalApi("https://github.com/grpc/grpc-java/issues/8022") public abstract class SecurityPolicy { protected SecurityPolicy() {} diff --git a/binder/src/main/java/io/grpc/binder/ServerSecurityPolicy.java b/binder/src/main/java/io/grpc/binder/ServerSecurityPolicy.java index 46a124e1f47..d91a487a57c 100644 --- a/binder/src/main/java/io/grpc/binder/ServerSecurityPolicy.java +++ b/binder/src/main/java/io/grpc/binder/ServerSecurityPolicy.java @@ -17,7 +17,6 @@ package io.grpc.binder; import com.google.common.collect.ImmutableMap; -import io.grpc.ExperimentalApi; import io.grpc.Status; import java.util.HashMap; import java.util.Map; @@ -28,7 +27,6 @@ * * Contains a default policy, and optional policies for each server. */ -@ExperimentalApi("https://github.com/grpc/grpc-java/issues/8022") public final class ServerSecurityPolicy { private final SecurityPolicy defaultPolicy; From c145473756fe371bc73510585a5473d2cbab50f1 Mon Sep 17 00:00:00 2001 From: Larry Safran <107004254+larry-safran@users.noreply.github.com> Date: Wed, 30 Nov 2022 21:58:57 +0000 Subject: [PATCH 19/39] Improve error message when deadline is exceeded, making it clear which deadline (Context or CallOptions) was exceeded and making the grammar clearer. (#9713) --- .../java/io/grpc/internal/ClientCallImpl.java | 21 ++++++++++++---- .../io/grpc/internal/DelayedClientCall.java | 24 ++++++++++++++++--- .../io/grpc/internal/ClientCallImplTest.java | 2 +- .../integration/AbstractInteropTest.java | 4 ++-- .../java/io/grpc/xds/XdsNameResolverTest.java | 2 +- 5 files changed, 42 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/io/grpc/internal/ClientCallImpl.java b/core/src/main/java/io/grpc/internal/ClientCallImpl.java index 31286c2bd7b..000ede77057 100644 --- a/core/src/main/java/io/grpc/internal/ClientCallImpl.java +++ b/core/src/main/java/io/grpc/internal/ClientCallImpl.java @@ -72,6 +72,7 @@ final class ClientCallImpl extends ClientCall { private static final Logger log = Logger.getLogger(ClientCallImpl.class.getName()); private static final byte[] FULL_STREAM_DECOMPRESSION_ENCODINGS = "gzip".getBytes(Charset.forName("US-ASCII")); + private static final double NANO_TO_SECS = 1.0 * TimeUnit.SECONDS.toNanos(1); private final MethodDescriptor method; private final Tag tag; @@ -259,10 +260,12 @@ public void runInContext() { } else { ClientStreamTracer[] tracers = GrpcUtil.getClientStreamTracers(callOptions, headers, 0, false); - stream = new FailingClientStream( - DEADLINE_EXCEEDED.withDescription( - "ClientCall started after deadline exceeded: " + effectiveDeadline), - tracers); + String deadlineName = + isFirstMin(callOptions.getDeadline(), context.getDeadline()) ? "CallOptions" : "Context"; + String description = String.format( + "ClientCall started after %s deadline was exceeded .9%f seconds ago", deadlineName, + effectiveDeadline.timeRemaining(TimeUnit.NANOSECONDS) / NANO_TO_SECS); + stream = new FailingClientStream(DEADLINE_EXCEEDED.withDescription(description), tracers); } if (callExecutorIsDirect) { @@ -431,6 +434,16 @@ private static Deadline min(@Nullable Deadline deadline0, @Nullable Deadline dea return deadline0.minimum(deadline1); } + private static boolean isFirstMin(@Nullable Deadline deadline0, @Nullable Deadline deadline1) { + if (deadline0 == null) { + return false; + } + if (deadline1 == null) { + return true; + } + return deadline0.isBefore(deadline1); + } + @Override public void request(int numMessages) { PerfMark.startTask("ClientCall.request", tag); diff --git a/core/src/main/java/io/grpc/internal/DelayedClientCall.java b/core/src/main/java/io/grpc/internal/DelayedClientCall.java index 42cedddd0e7..ee600e52d68 100644 --- a/core/src/main/java/io/grpc/internal/DelayedClientCall.java +++ b/core/src/main/java/io/grpc/internal/DelayedClientCall.java @@ -81,6 +81,17 @@ protected DelayedClientCall( initialDeadlineMonitor = scheduleDeadlineIfNeeded(scheduler, deadline); } + // If one argument is null, consider the other the "Before" + private boolean isAbeforeB(@Nullable Deadline a, @Nullable Deadline b) { + if (b == null) { + return true; + } else if (a == null) { + return false; + } + + return a.isBefore(b); + } + @Nullable private ScheduledFuture scheduleDeadlineIfNeeded( ScheduledExecutorService scheduler, @Nullable Deadline deadline) { @@ -90,8 +101,9 @@ private ScheduledFuture scheduleDeadlineIfNeeded( } long remainingNanos = Long.MAX_VALUE; if (deadline != null) { - remainingNanos = Math.min(remainingNanos, deadline.timeRemaining(NANOSECONDS)); + remainingNanos = deadline.timeRemaining(NANOSECONDS); } + if (contextDeadline != null && contextDeadline.timeRemaining(NANOSECONDS) < remainingNanos) { remainingNanos = contextDeadline.timeRemaining(NANOSECONDS); if (logger.isLoggable(Level.FINE)) { @@ -110,13 +122,19 @@ private ScheduledFuture scheduleDeadlineIfNeeded( logger.fine(builder.toString()); } } + long seconds = Math.abs(remainingNanos) / TimeUnit.SECONDS.toNanos(1); long nanos = Math.abs(remainingNanos) % TimeUnit.SECONDS.toNanos(1); final StringBuilder buf = new StringBuilder(); + String deadlineName = isAbeforeB(contextDeadline, deadline) ? "Context" : "CallOptions"; if (remainingNanos < 0) { - buf.append("ClientCall started after deadline exceeded. Deadline exceeded after -"); + buf.append("ClientCall started after "); + buf.append(deadlineName); + buf.append(" deadline was exceeded. Deadline has been exceeded for "); } else { - buf.append("Deadline exceeded after "); + buf.append("Deadline "); + buf.append(deadlineName); + buf.append(" will be exceeded in "); } buf.append(seconds); buf.append(String.format(Locale.US, ".%09d", nanos)); diff --git a/core/src/test/java/io/grpc/internal/ClientCallImplTest.java b/core/src/test/java/io/grpc/internal/ClientCallImplTest.java index e409f2f9df4..687a89abdd8 100644 --- a/core/src/test/java/io/grpc/internal/ClientCallImplTest.java +++ b/core/src/test/java/io/grpc/internal/ClientCallImplTest.java @@ -786,7 +786,7 @@ public void deadlineExceededBeforeCallStarted() { verify(callListener, timeout(1000)).onClose(statusCaptor.capture(), any(Metadata.class)); assertEquals(Status.Code.DEADLINE_EXCEEDED, statusCaptor.getValue().getCode()); assertThat(statusCaptor.getValue().getDescription()) - .startsWith("ClientCall started after deadline exceeded"); + .startsWith("ClientCall started after CallOptions deadline was exceeded"); verifyNoInteractions(clientStreamProvider); } diff --git a/interop-testing/src/main/java/io/grpc/testing/integration/AbstractInteropTest.java b/interop-testing/src/main/java/io/grpc/testing/integration/AbstractInteropTest.java index bd11bac8a9c..d04873c5a92 100644 --- a/interop-testing/src/main/java/io/grpc/testing/integration/AbstractInteropTest.java +++ b/interop-testing/src/main/java/io/grpc/testing/integration/AbstractInteropTest.java @@ -1241,7 +1241,7 @@ public void deadlineInPast() throws Exception { } catch (StatusRuntimeException ex) { assertEquals(Status.Code.DEADLINE_EXCEEDED, ex.getStatus().getCode()); assertThat(ex.getStatus().getDescription()) - .startsWith("ClientCall started after deadline exceeded"); + .startsWith("ClientCall started after CallOptions deadline was exceeded"); } // CensusStreamTracerModule record final status in the interceptor, thus is guaranteed to be @@ -1274,7 +1274,7 @@ public void deadlineInPast() throws Exception { } catch (StatusRuntimeException ex) { assertEquals(Status.Code.DEADLINE_EXCEEDED, ex.getStatus().getCode()); assertThat(ex.getStatus().getDescription()) - .startsWith("ClientCall started after deadline exceeded"); + .startsWith("ClientCall started after CallOptions deadline was exceeded"); } if (metricsExpected()) { MetricsRecord clientStartRecord = clientStatsRecorder.pollRecord(5, TimeUnit.SECONDS); diff --git a/xds/src/test/java/io/grpc/xds/XdsNameResolverTest.java b/xds/src/test/java/io/grpc/xds/XdsNameResolverTest.java index 2deab4ae688..f4475ebe37a 100644 --- a/xds/src/test/java/io/grpc/xds/XdsNameResolverTest.java +++ b/xds/src/test/java/io/grpc/xds/XdsNameResolverTest.java @@ -1736,7 +1736,7 @@ public long nanoTime() { assertThat(testCall).isNull(); verifyRpcDelayedThenAborted(observer, 4000L, Status.DEADLINE_EXCEEDED.withDescription( "Deadline exceeded after up to 5000 ns of fault-injected delay:" - + " Deadline exceeded after 0.000004000s. ")); + + " Deadline CallOptions will be exceeded in 0.000004000s. ")); } @Test From 78415f55d3b7cc89ddc5393461653b78b6174340 Mon Sep 17 00:00:00 2001 From: Terry Wilson Date: Thu, 1 Dec 2022 09:37:10 -0800 Subject: [PATCH 20/39] xds: Include additional EAG attributes on updates (#9723) ClusterImplLoadBalancer adds the ATTR_CLUSTER_NAME and ATTR_SSL_CONTEXT_PROVIDER_SUPPLIER attributes to the EAG list when it creates a new subchannel, but they are lost on subsequent address updates. This change assures the attributes are also included on address updates. --- .../io/grpc/xds/ClusterImplLoadBalancer.java | 33 ++++++++++++------- .../grpc/xds/ClusterImplLoadBalancerTest.java | 12 +++++++ 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/ClusterImplLoadBalancer.java b/xds/src/main/java/io/grpc/xds/ClusterImplLoadBalancer.java index 2482085adfb..b225b01af7a 100644 --- a/xds/src/main/java/io/grpc/xds/ClusterImplLoadBalancer.java +++ b/xds/src/main/java/io/grpc/xds/ClusterImplLoadBalancer.java @@ -194,17 +194,7 @@ public void updateBalancingState(ConnectivityState newState, SubchannelPicker ne @Override public Subchannel createSubchannel(CreateSubchannelArgs args) { - List addresses = new ArrayList<>(); - for (EquivalentAddressGroup eag : args.getAddresses()) { - Attributes.Builder attrBuilder = eag.getAttributes().toBuilder().set( - InternalXdsAttributes.ATTR_CLUSTER_NAME, cluster); - if (enableSecurity && sslContextProviderSupplier != null) { - attrBuilder.set( - InternalXdsAttributes.ATTR_SSL_CONTEXT_PROVIDER_SUPPLIER, - sslContextProviderSupplier); - } - addresses.add(new EquivalentAddressGroup(eag.getAddresses(), attrBuilder.build())); - } + List addresses = withAdditionalAttributes(args.getAddresses()); Locality locality = args.getAddresses().get(0).getAttributes().get( InternalXdsAttributes.ATTR_LOCALITY); // all addresses should be in the same locality // Endpoint addresses resolved by ClusterResolverLoadBalancer should always contain @@ -229,6 +219,11 @@ public void shutdown() { delegate().shutdown(); } + @Override + public void updateAddresses(List addresses) { + delegate().updateAddresses(withAdditionalAttributes(addresses)); + } + @Override protected Subchannel delegate() { return subchannel; @@ -236,6 +231,22 @@ protected Subchannel delegate() { }; } + private List withAdditionalAttributes( + List addresses) { + List newAddresses = new ArrayList<>(); + for (EquivalentAddressGroup eag : addresses) { + Attributes.Builder attrBuilder = eag.getAttributes().toBuilder().set( + InternalXdsAttributes.ATTR_CLUSTER_NAME, cluster); + if (enableSecurity && sslContextProviderSupplier != null) { + attrBuilder.set( + InternalXdsAttributes.ATTR_SSL_CONTEXT_PROVIDER_SUPPLIER, + sslContextProviderSupplier); + } + newAddresses.add(new EquivalentAddressGroup(eag.getAddresses(), attrBuilder.build())); + } + return newAddresses; + } + @Override protected Helper delegate() { return helper; diff --git a/xds/src/test/java/io/grpc/xds/ClusterImplLoadBalancerTest.java b/xds/src/test/java/io/grpc/xds/ClusterImplLoadBalancerTest.java index 142786280a8..6d19e166a0b 100644 --- a/xds/src/test/java/io/grpc/xds/ClusterImplLoadBalancerTest.java +++ b/xds/src/test/java/io/grpc/xds/ClusterImplLoadBalancerTest.java @@ -470,6 +470,7 @@ public void endpointAddressesAttachedWithClusterName() { assertThat(downstreamBalancers).hasSize(1); // one leaf balancer FakeLoadBalancer leafBalancer = Iterables.getOnlyElement(downstreamBalancers); assertThat(leafBalancer.name).isEqualTo("round_robin"); + // Simulates leaf load balancer creating subchannels. CreateSubchannelArgs args = CreateSubchannelArgs.newBuilder() @@ -480,6 +481,13 @@ public void endpointAddressesAttachedWithClusterName() { assertThat(eag.getAttributes().get(InternalXdsAttributes.ATTR_CLUSTER_NAME)) .isEqualTo(CLUSTER); } + + // An address update should also retain the cluster attribute. + subchannel.updateAddresses(leafBalancer.addresses); + for (EquivalentAddressGroup eag : subchannel.getAllAddresses()) { + assertThat(eag.getAttributes().get(InternalXdsAttributes.ATTR_CLUSTER_NAME)) + .isEqualTo(CLUSTER); + } } @Test @@ -761,6 +769,10 @@ public List getAllAddresses() { public Attributes getAttributes() { return attrs; } + + @Override + public void updateAddresses(List addrs) { + } } private final class FakeXdsClient extends XdsClient { From b51cd9fd99d12f488c70ee5534681e982c8c1449 Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Thu, 1 Dec 2022 11:09:40 -0800 Subject: [PATCH 21/39] core: Replace AtomicInteger.updateAndGet with compareAndSet updateAndGet is only available in API level 24+. It is unclear why AnimalSniffer didn't detect this. This was noticed when doing the import, but the Android CI has also been failing because of it. --- .../main/java/io/grpc/internal/RetriableStream.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/io/grpc/internal/RetriableStream.java b/core/src/main/java/io/grpc/internal/RetriableStream.java index c8c45c61f85..46da45aebd4 100644 --- a/core/src/main/java/io/grpc/internal/RetriableStream.java +++ b/core/src/main/java/io/grpc/internal/RetriableStream.java @@ -225,9 +225,13 @@ private void commitAndRun(Substream winningSubstream) { @Nullable // returns null when cancelled private Substream createSubstream(int previousAttemptCount, boolean isTransparentRetry) { // increment only when >= 0, i.e. not cancelled - if (inFlightSubStreams.updateAndGet(value -> value < 0 ? value : value + 1) < 0) { - return null; - } + int inFlight; + do { + inFlight = inFlightSubStreams.get(); + if (inFlight < 0) { + return null; + } + } while (!inFlightSubStreams.compareAndSet(inFlight, inFlight + 1)); Substream sub = new Substream(previousAttemptCount); // one tracer per substream final ClientStreamTracer bufferSizeTracer = new BufferSizeTracer(sub); From df974455ae12650fc6450b1ee800f29db7ca42e8 Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Thu, 1 Dec 2022 11:06:30 -0800 Subject: [PATCH 22/39] binder: Remove unused imports --- .../java/io/grpc/binder/BinderSecurityTest.java | 4 ---- .../src/main/java/io/grpc/binder/BinderChannelBuilder.java | 4 ---- .../src/main/java/io/grpc/binder/BinderServerBuilder.java | 7 ------- 3 files changed, 15 deletions(-) diff --git a/binder/src/androidTest/java/io/grpc/binder/BinderSecurityTest.java b/binder/src/androidTest/java/io/grpc/binder/BinderSecurityTest.java index 27fc293e2a7..e3b9978fb36 100644 --- a/binder/src/androidTest/java/io/grpc/binder/BinderSecurityTest.java +++ b/binder/src/androidTest/java/io/grpc/binder/BinderSecurityTest.java @@ -19,10 +19,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; -import android.app.Service; import android.content.Context; -import android.content.Intent; -import android.os.IBinder; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.common.base.Function; @@ -41,7 +38,6 @@ import io.grpc.protobuf.lite.ProtoLiteUtils; import io.grpc.stub.ClientCalls; import io.grpc.stub.ServerCalls; -import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; diff --git a/binder/src/main/java/io/grpc/binder/BinderChannelBuilder.java b/binder/src/main/java/io/grpc/binder/BinderChannelBuilder.java index 8364645a10e..214eb6dc4c5 100644 --- a/binder/src/main/java/io/grpc/binder/BinderChannelBuilder.java +++ b/binder/src/main/java/io/grpc/binder/BinderChannelBuilder.java @@ -19,15 +19,11 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; -import android.app.Application; -import android.content.ComponentName; import android.content.Context; import androidx.core.content.ContextCompat; import com.google.errorprone.annotations.DoNotCall; import io.grpc.ChannelCredentials; import io.grpc.ChannelLogger; -import io.grpc.CompressorRegistry; -import io.grpc.DecompressorRegistry; import io.grpc.ExperimentalApi; import io.grpc.ForwardingChannelBuilder; import io.grpc.ManagedChannel; diff --git a/binder/src/main/java/io/grpc/binder/BinderServerBuilder.java b/binder/src/main/java/io/grpc/binder/BinderServerBuilder.java index f37c522863d..eaa94bffc45 100644 --- a/binder/src/main/java/io/grpc/binder/BinderServerBuilder.java +++ b/binder/src/main/java/io/grpc/binder/BinderServerBuilder.java @@ -21,27 +21,20 @@ import android.app.Service; import android.os.IBinder; -import com.google.common.base.Supplier; import com.google.errorprone.annotations.DoNotCall; import io.grpc.ExperimentalApi; import io.grpc.Server; import io.grpc.ServerBuilder; -import io.grpc.ServerStreamTracer; import io.grpc.binder.internal.BinderServer; import io.grpc.binder.internal.BinderTransportSecurity; import io.grpc.ForwardingServerBuilder; import io.grpc.internal.FixedObjectPool; import io.grpc.internal.GrpcUtil; -import io.grpc.internal.InternalServer; import io.grpc.internal.ServerImplBuilder; -import io.grpc.internal.ServerImplBuilder.ClientTransportServersBuilder; import io.grpc.internal.ObjectPool; import io.grpc.internal.SharedResourcePool; import java.io.File; -import java.io.IOException; -import java.util.List; import java.util.concurrent.ScheduledExecutorService; -import javax.annotation.Nullable; /** * Builder for a server that services requests from an Android Service. From dceb76438544e696129033a00f2fed8bf6427336 Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Thu, 17 Nov 2022 18:09:43 -0800 Subject: [PATCH 23/39] api: Avoid initializing CallOptions.Builder fields that will be overwritten The JIT probably cleans this up, but it is a bit confusing and needless. --- api/src/main/java/io/grpc/CallOptions.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/io/grpc/CallOptions.java b/api/src/main/java/io/grpc/CallOptions.java index 16684275dea..4b180c56e07 100644 --- a/api/src/main/java/io/grpc/CallOptions.java +++ b/api/src/main/java/io/grpc/CallOptions.java @@ -41,7 +41,14 @@ public final class CallOptions { /** * A blank {@code CallOptions} that all fields are not set. */ - public static final CallOptions DEFAULT = new Builder().build(); + public static final CallOptions DEFAULT; + + static { + Builder b = new Builder(); + b.customOptions = new Object[0][2]; + b.streamTracerFactories = Collections.emptyList(); + DEFAULT = b.build(); + } @Nullable private final Deadline deadline; @@ -92,9 +99,9 @@ static class Builder { String authority; CallCredentials credentials; String compressorName; - Object[][] customOptions = new Object[0][2]; + Object[][] customOptions; // Unmodifiable list - List streamTracerFactories = Collections.emptyList(); + List streamTracerFactories; Boolean waitForReady; Integer maxInboundMessageSize; Integer maxOutboundMessageSize; From e36275e9511c85e86c4ba9538ff0658e20ed2cb1 Mon Sep 17 00:00:00 2001 From: cbianchi-7 Date: Thu, 1 Dec 2022 10:10:26 -0800 Subject: [PATCH 24/39] Additional changes that were added post-submission of PR 9669 for promoting out of experimental status. --- .../src/main/java/io/grpc/binder/AndroidComponentAddress.java | 3 ++- binder/src/main/java/io/grpc/binder/BinderInternal.java | 2 +- binder/src/main/java/io/grpc/binder/SecurityPolicies.java | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/binder/src/main/java/io/grpc/binder/AndroidComponentAddress.java b/binder/src/main/java/io/grpc/binder/AndroidComponentAddress.java index 8a70f28021f..90197ee8382 100644 --- a/binder/src/main/java/io/grpc/binder/AndroidComponentAddress.java +++ b/binder/src/main/java/io/grpc/binder/AndroidComponentAddress.java @@ -103,7 +103,8 @@ public static AndroidComponentAddress forComponent(ComponentName component) { /** * Returns the Authority which is the package name of the target app. - * See {@link android.content.ComponentName}. + * + *

See {@link android.content.ComponentName}. */ public String getAuthority() { return getComponent().getPackageName(); diff --git a/binder/src/main/java/io/grpc/binder/BinderInternal.java b/binder/src/main/java/io/grpc/binder/BinderInternal.java index ba7d78b2888..ad0fe74e559 100644 --- a/binder/src/main/java/io/grpc/binder/BinderInternal.java +++ b/binder/src/main/java/io/grpc/binder/BinderInternal.java @@ -26,7 +26,7 @@ public class BinderInternal { /** - * Set the receiver's {@link IBinder} using {@link IBinderReceiver#set(IBinder)}. + * Sets the receiver's {@link IBinder} using {@link IBinderReceiver#set(IBinder)}. */ static void setIBinder(IBinderReceiver receiver, IBinder binder) { receiver.set(binder); diff --git a/binder/src/main/java/io/grpc/binder/SecurityPolicies.java b/binder/src/main/java/io/grpc/binder/SecurityPolicies.java index 6af47b726f5..1a31ef823d3 100644 --- a/binder/src/main/java/io/grpc/binder/SecurityPolicies.java +++ b/binder/src/main/java/io/grpc/binder/SecurityPolicies.java @@ -55,7 +55,8 @@ public static ServerSecurityPolicy serverInternalOnly() { } /** - * Creates a default {@link SecurityPolicy} that checks authorization based on UID. + * Creates a default {@link SecurityPolicy} that allows access only to callers with the same UID + * as the current process. */ public static SecurityPolicy internalOnly() { return new SecurityPolicy() { From 9dac8cf3522640770b27b95b3cd76521da379193 Mon Sep 17 00:00:00 2001 From: Smilencer Date: Fri, 2 Dec 2022 05:17:34 +0800 Subject: [PATCH 25/39] examples: add name resolve and load balance (#9700) --- examples/BUILD.bazel | 37 ++++++ examples/build.gradle | 32 +++++ examples/pom.xml | 6 +- .../loadbalance/ExampleNameResolver.java | 110 ++++++++++++++++++ .../ExampleNameResolverProvider.java | 47 ++++++++ .../loadbalance/LoadBalanceClient.java | 85 ++++++++++++++ .../loadbalance/LoadBalanceServer.java | 94 +++++++++++++++ .../nameresolve/ExampleNameResolver.java | 108 +++++++++++++++++ .../ExampleNameResolverProvider.java | 47 ++++++++ .../nameresolve/NameResolveClient.java | 85 ++++++++++++++ .../nameresolve/NameResolveServer.java | 94 +++++++++++++++ 11 files changed, 742 insertions(+), 3 deletions(-) create mode 100644 examples/src/main/java/io/grpc/examples/loadbalance/ExampleNameResolver.java create mode 100644 examples/src/main/java/io/grpc/examples/loadbalance/ExampleNameResolverProvider.java create mode 100644 examples/src/main/java/io/grpc/examples/loadbalance/LoadBalanceClient.java create mode 100644 examples/src/main/java/io/grpc/examples/loadbalance/LoadBalanceServer.java create mode 100644 examples/src/main/java/io/grpc/examples/nameresolve/ExampleNameResolver.java create mode 100644 examples/src/main/java/io/grpc/examples/nameresolve/ExampleNameResolverProvider.java create mode 100644 examples/src/main/java/io/grpc/examples/nameresolve/NameResolveClient.java create mode 100644 examples/src/main/java/io/grpc/examples/nameresolve/NameResolveServer.java diff --git a/examples/BUILD.bazel b/examples/BUILD.bazel index e7f00381ad1..2a5ed52b35c 100644 --- a/examples/BUILD.bazel +++ b/examples/BUILD.bazel @@ -135,3 +135,40 @@ java_binary( ":examples", ], ) + +java_binary( + name = "load-balance-client", + testonly = 1, + main_class = "io.grpc.examples.loadbalance.LoadBalanceClient", + runtime_deps = [ + ":examples", + ], +) + +java_binary( + name = "load-balance-server", + testonly = 1, + main_class = "io.grpc.examples.loadbalance.LoadBalanceServer", + runtime_deps = [ + ":examples", + ], +) + +java_binary( + name = "name-resolve-client", + testonly = 1, + main_class = "io.grpc.examples.nameresolve.NameResolveClient", + runtime_deps = [ + ":examples", + ], +) + +java_binary( + name = "name-resolve-server", + testonly = 1, + main_class = "io.grpc.examples.nameresolve.NameResolveServer", + runtime_deps = [ + ":examples", + ], +) + diff --git a/examples/build.gradle b/examples/build.gradle index db21f6edd2e..79ab93a242f 100644 --- a/examples/build.gradle +++ b/examples/build.gradle @@ -140,6 +140,34 @@ task manualFlowControlServer(type: CreateStartScripts) { classpath = startScripts.classpath } +task loadBalanceServer(type: CreateStartScripts) { + mainClass = 'io.grpc.examples.loadbalance.LoadBalanceServer' + applicationName = 'load-balance-server' + outputDir = new File(project.buildDir, 'tmp/scripts/' + name) + classpath = startScripts.classpath +} + +task loadBalanceClient(type: CreateStartScripts) { + mainClass = 'io.grpc.examples.loadbalance.LoadBalanceClient' + applicationName = 'load-balance-client' + outputDir = new File(project.buildDir, 'tmp/scripts/' + name) + classpath = startScripts.classpath +} + +task nameResolveServer(type: CreateStartScripts) { + mainClass = 'io.grpc.examples.nameresolve.NameResolveServer' + applicationName = 'name-resolve-server' + outputDir = new File(project.buildDir, 'tmp/scripts/' + name) + classpath = startScripts.classpath +} + +task nameResolveClient(type: CreateStartScripts) { + mainClass = 'io.grpc.examples.nameresolve.NameResolveClient' + applicationName = 'name-resolve-client' + outputDir = new File(project.buildDir, 'tmp/scripts/' + name) + classpath = startScripts.classpath +} + applicationDistribution.into('bin') { from(routeGuideServer) from(routeGuideClient) @@ -152,5 +180,9 @@ applicationDistribution.into('bin') { from(compressingHelloWorldClient) from(manualFlowControlClient) from(manualFlowControlServer) + from(loadBalanceServer) + from(loadBalanceClient) + from(nameResolveServer) + from(nameResolveClient) fileMode = 0755 } diff --git a/examples/pom.xml b/examples/pom.xml index c4ecdfe4f93..9e57a781612 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -15,9 +15,9 @@ 1.52.0-SNAPSHOT 3.21.7 3.21.7 - - 1.7 - 1.7 + + 1.8 + 1.8 diff --git a/examples/src/main/java/io/grpc/examples/loadbalance/ExampleNameResolver.java b/examples/src/main/java/io/grpc/examples/loadbalance/ExampleNameResolver.java new file mode 100644 index 00000000000..f562f0ac107 --- /dev/null +++ b/examples/src/main/java/io/grpc/examples/loadbalance/ExampleNameResolver.java @@ -0,0 +1,110 @@ +/* + * Copyright 2022 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. + */ + +package io.grpc.examples.loadbalance; + +import com.google.common.collect.ImmutableMap; +import io.grpc.EquivalentAddressGroup; +import io.grpc.NameResolver; +import io.grpc.Status; + +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.URI; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static io.grpc.examples.loadbalance.LoadBalanceClient.exampleServiceName; + +public class ExampleNameResolver extends NameResolver { + + private Listener2 listener; + + private final URI uri; + + private final Map> addrStore; + + public ExampleNameResolver(URI targetUri) { + this.uri = targetUri; + // This is a fake name resolver, so we just hard code the address here. + addrStore = ImmutableMap.>builder() + .put(exampleServiceName, + Stream.iterate(LoadBalanceServer.startPort,p->p+1) + .limit(LoadBalanceServer.serverCount) + .map(port->new InetSocketAddress("localhost",port)) + .collect(Collectors.toList()) + ) + .build(); + } + + @Override + public String getServiceAuthority() { + // Be consistent with behavior in grpc-go, authority is saved in Host field of URI. + if (uri.getHost() != null) { + return uri.getHost(); + } + return "no host"; + } + + @Override + public void shutdown() { + } + + @Override + public void start(Listener2 listener) { + this.listener = listener; + this.resolve(); + } + + @Override + public void refresh() { + this.resolve(); + } + + private void resolve() { + List addresses = addrStore.get(uri.getPath().substring(1)); + try { + List equivalentAddressGroup = addresses.stream() + // convert to socket address + .map(this::toSocketAddress) + // every socket address is a single EquivalentAddressGroup, so they can be accessed randomly + .map(Arrays::asList) + .map(this::addrToEquivalentAddressGroup) + .collect(Collectors.toList()); + + ResolutionResult resolutionResult = ResolutionResult.newBuilder() + .setAddresses(equivalentAddressGroup) + .build(); + + this.listener.onResult(resolutionResult); + + } catch (Exception e){ + // when error occurs, notify listener + this.listener.onError(Status.UNAVAILABLE.withDescription("Unable to resolve host ").withCause(e)); + } + } + + private SocketAddress toSocketAddress(InetSocketAddress address) { + return new InetSocketAddress(address.getHostName(), address.getPort()); + } + + private EquivalentAddressGroup addrToEquivalentAddressGroup(List addrList) { + return new EquivalentAddressGroup(addrList); + } +} diff --git a/examples/src/main/java/io/grpc/examples/loadbalance/ExampleNameResolverProvider.java b/examples/src/main/java/io/grpc/examples/loadbalance/ExampleNameResolverProvider.java new file mode 100644 index 00000000000..ee966fd044c --- /dev/null +++ b/examples/src/main/java/io/grpc/examples/loadbalance/ExampleNameResolverProvider.java @@ -0,0 +1,47 @@ +/* + * Copyright 2022 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. + */ + +package io.grpc.examples.loadbalance; + +import io.grpc.NameResolver; +import io.grpc.NameResolverProvider; + +import java.net.URI; + +import static io.grpc.examples.loadbalance.LoadBalanceClient.exampleScheme; + +public class ExampleNameResolverProvider extends NameResolverProvider { + @Override + public NameResolver newNameResolver(URI targetUri, NameResolver.Args args) { + return new ExampleNameResolver(targetUri); + } + + @Override + protected boolean isAvailable() { + return true; + } + + @Override + protected int priority() { + return 5; + } + + @Override + // gRPC choose the first NameResolverProvider that supports the target URI scheme. + public String getDefaultScheme() { + return exampleScheme; + } +} diff --git a/examples/src/main/java/io/grpc/examples/loadbalance/LoadBalanceClient.java b/examples/src/main/java/io/grpc/examples/loadbalance/LoadBalanceClient.java new file mode 100644 index 00000000000..97444922871 --- /dev/null +++ b/examples/src/main/java/io/grpc/examples/loadbalance/LoadBalanceClient.java @@ -0,0 +1,85 @@ +/* + * Copyright 2022 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. + */ + +package io.grpc.examples.loadbalance; + +import io.grpc.*; +import io.grpc.examples.helloworld.GreeterGrpc; +import io.grpc.examples.helloworld.HelloReply; +import io.grpc.examples.helloworld.HelloRequest; + +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class LoadBalanceClient { + private static final Logger logger = Logger.getLogger(LoadBalanceClient.class.getName()); + + public static final String exampleScheme = "example"; + public static final String exampleServiceName = "lb.example.grpc.io"; + + private final GreeterGrpc.GreeterBlockingStub blockingStub; + + public LoadBalanceClient(Channel channel) { + blockingStub = GreeterGrpc.newBlockingStub(channel); + } + + public void greet(String name) { + HelloRequest request = HelloRequest.newBuilder().setName(name).build(); + HelloReply response; + try { + response = blockingStub.sayHello(request); + } catch (StatusRuntimeException e) { + logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus()); + return; + } + logger.info("Greeting: " + response.getMessage()); + } + + + public static void main(String[] args) throws Exception { + NameResolverRegistry.getDefaultRegistry().register(new ExampleNameResolverProvider()); + + String target = String.format("%s:///%s", exampleScheme, exampleServiceName); + + logger.info("Use default first_pick load balance policy"); + ManagedChannel channel = ManagedChannelBuilder.forTarget(target) + .usePlaintext() + .build(); + try { + LoadBalanceClient client = new LoadBalanceClient(channel); + for (int i = 0; i < 5; i++) { + client.greet("request" + i); + } + } finally { + channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS); + } + + logger.info("Change to round_robin policy"); + channel = ManagedChannelBuilder.forTarget(target) + .defaultLoadBalancingPolicy("round_robin") + .usePlaintext() + .build(); + try { + LoadBalanceClient client = new LoadBalanceClient(channel); + for (int i = 0; i < 5; i++) { + client.greet("request" + i); + } + } finally { + channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS); + } + } +} diff --git a/examples/src/main/java/io/grpc/examples/loadbalance/LoadBalanceServer.java b/examples/src/main/java/io/grpc/examples/loadbalance/LoadBalanceServer.java new file mode 100644 index 00000000000..c97d209497a --- /dev/null +++ b/examples/src/main/java/io/grpc/examples/loadbalance/LoadBalanceServer.java @@ -0,0 +1,94 @@ +/* + * Copyright 2022 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. + */ + +package io.grpc.examples.loadbalance; + +import io.grpc.Server; +import io.grpc.ServerBuilder; +import io.grpc.examples.helloworld.GreeterGrpc; +import io.grpc.examples.helloworld.HelloReply; +import io.grpc.examples.helloworld.HelloRequest; +import io.grpc.stub.StreamObserver; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; + +public class LoadBalanceServer { + private static final Logger logger = Logger.getLogger(LoadBalanceServer.class.getName()); + static public final int serverCount = 3; + static public final int startPort = 50051; + private Server[] servers; + + private void start() throws IOException { + servers = new Server[serverCount]; + for (int i = 0; i < serverCount; i++) { + int port = startPort + i; + servers[i] = ServerBuilder.forPort(port) + .addService(new GreeterImpl(port)) + .build() + .start(); + logger.info("Server started, listening on " + port); + } + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + System.err.println("*** shutting down gRPC server since JVM is shutting down"); + try { + LoadBalanceServer.this.stop(); + } catch (InterruptedException e) { + e.printStackTrace(System.err); + } + System.err.println("*** server shut down"); + })); + } + + private void stop() throws InterruptedException { + for (int i = 0; i < serverCount; i++) { + if (servers[i] != null) { + servers[i].shutdown().awaitTermination(30, TimeUnit.SECONDS); + } + } + } + + private void blockUntilShutdown() throws InterruptedException { + for (int i = 0; i < serverCount; i++) { + if (servers[i] != null) { + servers[i].awaitTermination(); + } + } + } + + public static void main(String[] args) throws IOException, InterruptedException { + final LoadBalanceServer server = new LoadBalanceServer(); + server.start(); + server.blockUntilShutdown(); + } + + static class GreeterImpl extends GreeterGrpc.GreeterImplBase { + + int port; + + public GreeterImpl(int port) { + this.port = port; + } + + @Override + public void sayHello(HelloRequest req, StreamObserver responseObserver) { + HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName() + " from server<" + this.port + ">").build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + } + } +} diff --git a/examples/src/main/java/io/grpc/examples/nameresolve/ExampleNameResolver.java b/examples/src/main/java/io/grpc/examples/nameresolve/ExampleNameResolver.java new file mode 100644 index 00000000000..95bf20dd580 --- /dev/null +++ b/examples/src/main/java/io/grpc/examples/nameresolve/ExampleNameResolver.java @@ -0,0 +1,108 @@ +/* + * Copyright 2022 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. + */ + +package io.grpc.examples.nameresolve; + +import com.google.common.collect.ImmutableMap; +import io.grpc.EquivalentAddressGroup; +import io.grpc.NameResolver; +import io.grpc.Status; + +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.URI; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static io.grpc.examples.loadbalance.LoadBalanceClient.exampleServiceName; + +public class ExampleNameResolver extends NameResolver { + + private final URI uri; + private final Map> addrStore; + private Listener2 listener; + + public ExampleNameResolver(URI targetUri) { + this.uri = targetUri; + // This is a fake name resolver, so we just hard code the address here. + addrStore = ImmutableMap.>builder() + .put(exampleServiceName, + Stream.iterate(NameResolveServer.startPort, p -> p + 1) + .limit(NameResolveServer.serverCount) + .map(port -> new InetSocketAddress("localhost", port)) + .collect(Collectors.toList()) + ) + .build(); + } + + @Override + public String getServiceAuthority() { + // Be consistent with behavior in grpc-go, authority is saved in Host field of URI. + if (uri.getHost() != null) { + return uri.getHost(); + } + return "no host"; + } + + @Override + public void shutdown() { + } + + @Override + public void start(Listener2 listener) { + this.listener = listener; + this.resolve(); + } + + @Override + public void refresh() { + this.resolve(); + } + + private void resolve() { + List addresses = addrStore.get(uri.getPath().substring(1)); + try { + List equivalentAddressGroup = addresses.stream() + // convert to socket address + .map(this::toSocketAddress) + // every socket address is a single EquivalentAddressGroup, so they can be accessed randomly + .map(Arrays::asList) + .map(this::addrToEquivalentAddressGroup) + .collect(Collectors.toList()); + + ResolutionResult resolutionResult = ResolutionResult.newBuilder() + .setAddresses(equivalentAddressGroup) + .build(); + + this.listener.onResult(resolutionResult); + + } catch (Exception e) { + // when error occurs, notify listener + this.listener.onError(Status.UNAVAILABLE.withDescription("Unable to resolve host ").withCause(e)); + } + } + + private SocketAddress toSocketAddress(InetSocketAddress address) { + return new InetSocketAddress(address.getHostName(), address.getPort()); + } + + private EquivalentAddressGroup addrToEquivalentAddressGroup(List addrList) { + return new EquivalentAddressGroup(addrList); + } +} diff --git a/examples/src/main/java/io/grpc/examples/nameresolve/ExampleNameResolverProvider.java b/examples/src/main/java/io/grpc/examples/nameresolve/ExampleNameResolverProvider.java new file mode 100644 index 00000000000..cd05f3214f6 --- /dev/null +++ b/examples/src/main/java/io/grpc/examples/nameresolve/ExampleNameResolverProvider.java @@ -0,0 +1,47 @@ +/* + * Copyright 2022 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. + */ + +package io.grpc.examples.nameresolve; + +import io.grpc.NameResolver; +import io.grpc.NameResolverProvider; + +import java.net.URI; + +import static io.grpc.examples.loadbalance.LoadBalanceClient.exampleScheme; + +public class ExampleNameResolverProvider extends NameResolverProvider { + @Override + public NameResolver newNameResolver(URI targetUri, NameResolver.Args args) { + return new ExampleNameResolver(targetUri); + } + + @Override + protected boolean isAvailable() { + return true; + } + + @Override + protected int priority() { + return 5; + } + + @Override + // gRPC choose the first NameResolverProvider that supports the target URI scheme. + public String getDefaultScheme() { + return exampleScheme; + } +} diff --git a/examples/src/main/java/io/grpc/examples/nameresolve/NameResolveClient.java b/examples/src/main/java/io/grpc/examples/nameresolve/NameResolveClient.java new file mode 100644 index 00000000000..ac6fdd32549 --- /dev/null +++ b/examples/src/main/java/io/grpc/examples/nameresolve/NameResolveClient.java @@ -0,0 +1,85 @@ +/* + * Copyright 2022 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. + */ + +package io.grpc.examples.nameresolve; + +import io.grpc.*; +import io.grpc.examples.helloworld.GreeterGrpc; +import io.grpc.examples.helloworld.HelloReply; +import io.grpc.examples.helloworld.HelloRequest; + +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class NameResolveClient { + public static final String exampleScheme = "example"; + public static final String exampleServiceName = "lb.example.grpc.io"; + private static final Logger logger = Logger.getLogger(NameResolveClient.class.getName()); + private final GreeterGrpc.GreeterBlockingStub blockingStub; + + public NameResolveClient(Channel channel) { + blockingStub = GreeterGrpc.newBlockingStub(channel); + } + + public static void main(String[] args) throws Exception { + NameResolverRegistry.getDefaultRegistry().register(new ExampleNameResolverProvider()); + + logger.info("Use default DNS resolver"); + ManagedChannel channel = ManagedChannelBuilder.forTarget("localhost:50051") + .usePlaintext() + .build(); + try { + NameResolveClient client = new NameResolveClient(channel); + for (int i = 0; i < 5; i++) { + client.greet("request" + i); + } + } finally { + channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS); + } + + logger.info("Change to use example name resolver"); + /* + Dial to "example:///resolver.example.grpc.io", use {@link ExampleNameResolver} to create connection + "resolver.example.grpc.io" is converted to {@link java.net.URI.path} + */ + channel = ManagedChannelBuilder.forTarget( + String.format("%s:///%s", exampleScheme, exampleServiceName)) + .defaultLoadBalancingPolicy("round_robin") + .usePlaintext() + .build(); + try { + NameResolveClient client = new NameResolveClient(channel); + for (int i = 0; i < 5; i++) { + client.greet("request" + i); + } + } finally { + channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS); + } + } + + public void greet(String name) { + HelloRequest request = HelloRequest.newBuilder().setName(name).build(); + HelloReply response; + try { + response = blockingStub.sayHello(request); + } catch (StatusRuntimeException e) { + logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus()); + return; + } + logger.info("Greeting: " + response.getMessage()); + } +} diff --git a/examples/src/main/java/io/grpc/examples/nameresolve/NameResolveServer.java b/examples/src/main/java/io/grpc/examples/nameresolve/NameResolveServer.java new file mode 100644 index 00000000000..0a402485906 --- /dev/null +++ b/examples/src/main/java/io/grpc/examples/nameresolve/NameResolveServer.java @@ -0,0 +1,94 @@ +/* + * Copyright 2022 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. + */ + +package io.grpc.examples.nameresolve; + +import io.grpc.Server; +import io.grpc.ServerBuilder; +import io.grpc.examples.helloworld.GreeterGrpc; +import io.grpc.examples.helloworld.HelloReply; +import io.grpc.examples.helloworld.HelloRequest; +import io.grpc.stub.StreamObserver; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; + +public class NameResolveServer { + static public final int serverCount = 3; + static public final int startPort = 50051; + private static final Logger logger = Logger.getLogger(NameResolveServer.class.getName()); + private Server[] servers; + + public static void main(String[] args) throws IOException, InterruptedException { + final NameResolveServer server = new NameResolveServer(); + server.start(); + server.blockUntilShutdown(); + } + + private void start() throws IOException { + servers = new Server[serverCount]; + for (int i = 0; i < serverCount; i++) { + int port = startPort + i; + servers[i] = ServerBuilder.forPort(port) + .addService(new GreeterImpl(port)) + .build() + .start(); + logger.info("Server started, listening on " + port); + } + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + System.err.println("*** shutting down gRPC server since JVM is shutting down"); + try { + NameResolveServer.this.stop(); + } catch (InterruptedException e) { + e.printStackTrace(System.err); + } + System.err.println("*** server shut down"); + })); + } + + private void stop() throws InterruptedException { + for (int i = 0; i < serverCount; i++) { + if (servers[i] != null) { + servers[i].shutdown().awaitTermination(30, TimeUnit.SECONDS); + } + } + } + + private void blockUntilShutdown() throws InterruptedException { + for (int i = 0; i < serverCount; i++) { + if (servers[i] != null) { + servers[i].awaitTermination(); + } + } + } + + static class GreeterImpl extends GreeterGrpc.GreeterImplBase { + + int port; + + public GreeterImpl(int port) { + this.port = port; + } + + @Override + public void sayHello(HelloRequest req, StreamObserver responseObserver) { + HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName() + " from server<" + this.port + ">").build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + } + } +} From c87fc052244a25e639746a099eb8c162af1bce75 Mon Sep 17 00:00:00 2001 From: yifeizhuang Date: Fri, 2 Dec 2022 10:35:26 -0800 Subject: [PATCH 26/39] xds: remove retained resources logics for RDS and EDS resources (#9724) We use state-of-the-world approach. For LDS/CDS, the control plane must return all resources that the client has subscribed to in each request. If some LDS/CDS resources are gone in a new update, their corresponding RDS/EDS resources names will be onAbsent(), unless there is cached data that is in use by other subscribers in other components. The motivations to remove this "retained resource" logic between resource types are: 1. Already handled by the subscribers, e.g. a CDS state would shut down its childLBs on new updates. XdsResolver for LdsUpdate would cancel all existing RDS subscriptions. Therefore the onAbsent() notification is effectively no-op. 2. Complexity. --- .../main/java/io/grpc/xds/XdsClientImpl.java | 57 +------------- .../java/io/grpc/xds/XdsClusterResource.java | 20 ++--- .../java/io/grpc/xds/XdsEndpointResource.java | 8 +- .../java/io/grpc/xds/XdsListenerResource.java | 39 ++++------ .../java/io/grpc/xds/XdsResourceType.java | 22 +++--- .../grpc/xds/XdsRouteConfigureResource.java | 8 +- .../io/grpc/xds/XdsClientImplDataTest.java | 74 +++++++++---------- .../io/grpc/xds/XdsClientImplTestBase.java | 43 +++++------ 8 files changed, 94 insertions(+), 177 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/XdsClientImpl.java b/xds/src/main/java/io/grpc/xds/XdsClientImpl.java index a30b4755a16..f05210b51c6 100644 --- a/xds/src/main/java/io/grpc/xds/XdsClientImpl.java +++ b/xds/src/main/java/io/grpc/xds/XdsClientImpl.java @@ -48,8 +48,6 @@ import io.grpc.xds.LoadStatsManager2.ClusterLocalityStats; import io.grpc.xds.XdsClient.ResourceStore; import io.grpc.xds.XdsClient.XdsResponseHandler; -import io.grpc.xds.XdsClusterResource.CdsUpdate; -import io.grpc.xds.XdsListenerResource.LdsUpdate; import io.grpc.xds.XdsLogger.XdsLogLevel; import java.net.URI; import java.util.Collection; @@ -107,7 +105,6 @@ public void uncaughtException(Thread t, Throwable e) { private final XdsLogger logger; private volatile boolean isShutdown; - // TODO(zdapeng): rename to XdsClientImpl XdsClientImpl( XdsChannelFactory xdsChannelFactory, Bootstrapper.BootstrapInfo bootstrapInfo, @@ -398,7 +395,6 @@ private void handleResourceUpdate(XdsResourceType.Arg xdsResourceType.typeName(), args.versionInfo, args.nonce, result.unpackedResources); Map> parsedResources = result.parsedResources; Set invalidResources = result.invalidResources; - Set retainedResources = result.retainedResources; List errors = result.errors; String errorDetail = null; if (errors.isEmpty()) { @@ -432,16 +428,14 @@ private void handleResourceUpdate(XdsResourceType.Arg } // Nothing else to do for incremental ADS resources. - if (xdsResourceType.dependentResource() == null) { + if (!xdsResourceType.isFullStateOfTheWorld()) { continue; } // Handle State of the World ADS: invalid resources. if (invalidResources.contains(resourceName)) { // The resource is missing. Reuse the cached resource if possible. - if (subscriber.data != null) { - retainDependentResource(subscriber, retainedResources); - } else { + if (subscriber.data == null) { // No cached data. Notify the watchers of an invalid update. subscriber.onError(Status.UNAVAILABLE.withDescription(errorDetail)); } @@ -451,49 +445,6 @@ private void handleResourceUpdate(XdsResourceType.Arg // For State of the World services, notify watchers when their watched resource is missing // from the ADS update. subscriber.onAbsent(); - // Retain any dependent resources if the resource deletion is ignored - // per bootstrap ignore_resource_deletion server feature. - if (!subscriber.absent) { - retainDependentResource(subscriber, retainedResources); - } - } - - // LDS/CDS responses represents the state of the world, RDS/EDS resources not referenced in - // LDS/CDS resources should be deleted. - if (xdsResourceType.dependentResource() != null) { - XdsResourceType dependency = xdsResourceType.dependentResource(); - Map> dependentSubscribers = - resourceSubscribers.get(dependency); - if (dependentSubscribers == null) { - return; - } - for (String resource : dependentSubscribers.keySet()) { - if (!retainedResources.contains(resource)) { - dependentSubscribers.get(resource).onAbsent(); - } - } - } - } - - private void retainDependentResource( - ResourceSubscriber subscriber, Set retainedResources) { - if (subscriber.data == null) { - return; - } - String resourceName = null; - if (subscriber.type == XdsListenerResource.getInstance()) { - LdsUpdate ldsUpdate = (LdsUpdate) subscriber.data; - io.grpc.xds.HttpConnectionManager hcm = ldsUpdate.httpConnectionManager(); - if (hcm != null) { - resourceName = hcm.rdsName(); - } - } else if (subscriber.type == XdsClusterResource.getInstance()) { - CdsUpdate cdsUpdate = (CdsUpdate) subscriber.data; - resourceName = cdsUpdate.edsServiceName(); - } - - if (resourceName != null) { - retainedResources.add(resourceName); } } @@ -657,9 +608,7 @@ void onAbsent() { // and the resource is reusable. boolean ignoreResourceDeletionEnabled = serverInfo != null && serverInfo.ignoreResourceDeletion(); - boolean isStateOfTheWorld = (type == XdsListenerResource.getInstance() - || type == XdsClusterResource.getInstance()); - if (ignoreResourceDeletionEnabled && isStateOfTheWorld && data != null) { + if (ignoreResourceDeletionEnabled && type.isFullStateOfTheWorld() && data != null) { if (!resourceDeletionIgnored) { logger.log(XdsLogLevel.FORCE_WARNING, "xds server {0}: ignoring deletion for resource type {1} name {2}}", diff --git a/xds/src/main/java/io/grpc/xds/XdsClusterResource.java b/xds/src/main/java/io/grpc/xds/XdsClusterResource.java index 82a977f7df4..c0d6ebeefd4 100644 --- a/xds/src/main/java/io/grpc/xds/XdsClusterResource.java +++ b/xds/src/main/java/io/grpc/xds/XdsClusterResource.java @@ -88,10 +88,9 @@ String typeUrlV2() { return ADS_TYPE_URL_CDS_V2; } - @Nullable @Override - XdsResourceType dependentResource() { - return XdsEndpointResource.getInstance(); + boolean isFullStateOfTheWorld() { + return true; } @Override @@ -101,8 +100,7 @@ Class unpackedClassName() { } @Override - CdsUpdate doParse(Args args, Message unpackedMessage, - Set retainedResources, boolean isResourceV3) + CdsUpdate doParse(Args args, Message unpackedMessage, boolean isResourceV3) throws ResourceInvalidException { if (!(unpackedMessage instanceof Cluster)) { throw new ResourceInvalidException("Invalid message type: " + unpackedMessage.getClass()); @@ -111,12 +109,12 @@ CdsUpdate doParse(Args args, Message unpackedMessage, if (args.bootstrapInfo != null && args.bootstrapInfo.certProviders() != null) { certProviderInstances = args.bootstrapInfo.certProviders().keySet(); } - return processCluster((Cluster) unpackedMessage, retainedResources, certProviderInstances, + return processCluster((Cluster) unpackedMessage, certProviderInstances, args.serverInfo, args.loadBalancerRegistry); } @VisibleForTesting - static CdsUpdate processCluster(Cluster cluster, Set retainedEdsResources, + static CdsUpdate processCluster(Cluster cluster, Set certProviderInstances, Bootstrapper.ServerInfo serverInfo, LoadBalancerRegistry loadBalancerRegistry) @@ -124,7 +122,7 @@ static CdsUpdate processCluster(Cluster cluster, Set retainedEdsResource StructOrError structOrError; switch (cluster.getClusterDiscoveryTypeCase()) { case TYPE: - structOrError = parseNonAggregateCluster(cluster, retainedEdsResources, + structOrError = parseNonAggregateCluster(cluster, certProviderInstances, serverInfo); break; case CLUSTER_TYPE: @@ -178,8 +176,7 @@ private static StructOrError parseAggregateCluster(Cluster cl } private static StructOrError parseNonAggregateCluster( - Cluster cluster, Set edsResources, Set certProviderInstances, - Bootstrapper.ServerInfo serverInfo) { + Cluster cluster, Set certProviderInstances, Bootstrapper.ServerInfo serverInfo) { String clusterName = cluster.getName(); Bootstrapper.ServerInfo lrsServerInfo = null; Long maxConcurrentRequests = null; @@ -249,9 +246,6 @@ private static StructOrError parseNonAggregateCluster( // If the service_name field is set, that value will be used for the EDS request. if (!edsClusterConfig.getServiceName().isEmpty()) { edsServiceName = edsClusterConfig.getServiceName(); - edsResources.add(edsServiceName); - } else { - edsResources.add(clusterName); } return StructOrError.fromStruct(CdsUpdate.forEds( clusterName, edsServiceName, lrsServerInfo, maxConcurrentRequests, upstreamTlsContext, diff --git a/xds/src/main/java/io/grpc/xds/XdsEndpointResource.java b/xds/src/main/java/io/grpc/xds/XdsEndpointResource.java index c126d643311..a44fea0c575 100644 --- a/xds/src/main/java/io/grpc/xds/XdsEndpointResource.java +++ b/xds/src/main/java/io/grpc/xds/XdsEndpointResource.java @@ -78,10 +78,9 @@ String typeUrlV2() { return ADS_TYPE_URL_EDS_V2; } - @Nullable @Override - XdsResourceType dependentResource() { - return null; + boolean isFullStateOfTheWorld() { + return false; } @Override @@ -90,8 +89,7 @@ Class unpackedClassName() { } @Override - EdsUpdate doParse(Args args, Message unpackedMessage, - Set retainedResources, boolean isResourceV3) + EdsUpdate doParse(Args args, Message unpackedMessage, boolean isResourceV3) throws ResourceInvalidException { if (!(unpackedMessage instanceof ClusterLoadAssignment)) { throw new ResourceInvalidException("Invalid message type: " + unpackedMessage.getClass()); diff --git a/xds/src/main/java/io/grpc/xds/XdsListenerResource.java b/xds/src/main/java/io/grpc/xds/XdsListenerResource.java index 5f7d6a27aa4..f367bd96908 100644 --- a/xds/src/main/java/io/grpc/xds/XdsListenerResource.java +++ b/xds/src/main/java/io/grpc/xds/XdsListenerResource.java @@ -97,15 +97,13 @@ String typeUrlV2() { return ADS_TYPE_URL_LDS_V2; } - @Nullable @Override - XdsResourceType dependentResource() { - return XdsRouteConfigureResource.getInstance(); + boolean isFullStateOfTheWorld() { + return true; } @Override - LdsUpdate doParse(Args args, Message unpackedMessage, Set retainedResources, - boolean isResourceV3) + LdsUpdate doParse(Args args, Message unpackedMessage, boolean isResourceV3) throws ResourceInvalidException { if (!(unpackedMessage instanceof Listener)) { throw new ResourceInvalidException("Invalid message type: " + unpackedMessage.getClass()); @@ -114,15 +112,14 @@ LdsUpdate doParse(Args args, Message unpackedMessage, Set retainedResour if (listener.hasApiListener()) { return processClientSideListener( - listener, retainedResources, args, enableFaultInjection && isResourceV3); + listener, args, enableFaultInjection && isResourceV3); } else { return processServerSideListener( - listener, retainedResources, args, enableRbac && isResourceV3); + listener, args, enableRbac && isResourceV3); } } - private LdsUpdate processClientSideListener( - Listener listener, Set rdsResources, Args args, boolean parseHttpFilter) + private LdsUpdate processClientSideListener(Listener listener, Args args, boolean parseHttpFilter) throws ResourceInvalidException { // Unpack HttpConnectionManager from the Listener. HttpConnectionManager hcm; @@ -135,24 +132,22 @@ private LdsUpdate processClientSideListener( "Could not parse HttpConnectionManager config from ApiListener", e); } return LdsUpdate.forApiListener(parseHttpConnectionManager( - hcm, rdsResources, args.filterRegistry, parseHttpFilter, true /* isForClient */)); + hcm, args.filterRegistry, parseHttpFilter, true /* isForClient */)); } - private LdsUpdate processServerSideListener( - Listener proto, Set rdsResources, Args args, boolean parseHttpFilter) + private LdsUpdate processServerSideListener(Listener proto, Args args, boolean parseHttpFilter) throws ResourceInvalidException { Set certProviderInstances = null; if (args.bootstrapInfo != null && args.bootstrapInfo.certProviders() != null) { certProviderInstances = args.bootstrapInfo.certProviders().keySet(); } - return LdsUpdate.forTcpListener(parseServerSideListener( - proto, rdsResources, args.tlsContextManager, args.filterRegistry, certProviderInstances, - parseHttpFilter)); + return LdsUpdate.forTcpListener(parseServerSideListener(proto, args.tlsContextManager, + args.filterRegistry, certProviderInstances, parseHttpFilter)); } @VisibleForTesting static EnvoyServerProtoData.Listener parseServerSideListener( - Listener proto, Set rdsResources, TlsContextManager tlsContextManager, + Listener proto, TlsContextManager tlsContextManager, FilterRegistry filterRegistry, Set certProviderInstances, boolean parseHttpFilter) throws ResourceInvalidException { if (!proto.getTrafficDirection().equals(TrafficDirection.INBOUND) @@ -190,13 +185,13 @@ static EnvoyServerProtoData.Listener parseServerSideListener( Set uniqueSet = new HashSet<>(); for (io.envoyproxy.envoy.config.listener.v3.FilterChain fc : proto.getFilterChainsList()) { filterChains.add( - parseFilterChain(fc, rdsResources, tlsContextManager, filterRegistry, uniqueSet, + parseFilterChain(fc, tlsContextManager, filterRegistry, uniqueSet, certProviderInstances, parseHttpFilter)); } FilterChain defaultFilterChain = null; if (proto.hasDefaultFilterChain()) { defaultFilterChain = parseFilterChain( - proto.getDefaultFilterChain(), rdsResources, tlsContextManager, filterRegistry, + proto.getDefaultFilterChain(), tlsContextManager, filterRegistry, null, certProviderInstances, parseHttpFilter); } @@ -206,7 +201,7 @@ static EnvoyServerProtoData.Listener parseServerSideListener( @VisibleForTesting static FilterChain parseFilterChain( - io.envoyproxy.envoy.config.listener.v3.FilterChain proto, Set rdsResources, + io.envoyproxy.envoy.config.listener.v3.FilterChain proto, TlsContextManager tlsContextManager, FilterRegistry filterRegistry, Set uniqueSet, Set certProviderInstances, boolean parseHttpFilters) throws ResourceInvalidException { @@ -235,7 +230,7 @@ static FilterChain parseFilterChain( + filter.getName() + " failed to unpack message", e); } io.grpc.xds.HttpConnectionManager httpConnectionManager = parseHttpConnectionManager( - hcmProto, rdsResources, filterRegistry, parseHttpFilters, false /* isForClient */); + hcmProto, filterRegistry, parseHttpFilters, false /* isForClient */); EnvoyServerProtoData.DownstreamTlsContext downstreamTlsContext = null; if (proto.hasTransportSocket()) { @@ -466,7 +461,7 @@ private static FilterChainMatch parseFilterChainMatch( @VisibleForTesting static io.grpc.xds.HttpConnectionManager parseHttpConnectionManager( - HttpConnectionManager proto, Set rdsResources, FilterRegistry filterRegistry, + HttpConnectionManager proto, FilterRegistry filterRegistry, boolean parseHttpFilter, boolean isForClient) throws ResourceInvalidException { if (enableRbac && proto.getXffNumTrustedHops() != 0) { throw new ResourceInvalidException( @@ -541,8 +536,6 @@ static io.grpc.xds.HttpConnectionManager parseHttpConnectionManager( throw new ResourceInvalidException( "HttpConnectionManager contains invalid RDS: must specify ADS or self ConfigSource"); } - // Collect the RDS resource referenced by this HttpConnectionManager. - rdsResources.add(rds.getRouteConfigName()); return io.grpc.xds.HttpConnectionManager.forRdsName( maxStreamDuration, rds.getRouteConfigName(), filterConfigs); } diff --git a/xds/src/main/java/io/grpc/xds/XdsResourceType.java b/xds/src/main/java/io/grpc/xds/XdsResourceType.java index a377ee35d7a..987151d899d 100644 --- a/xds/src/main/java/io/grpc/xds/XdsResourceType.java +++ b/xds/src/main/java/io/grpc/xds/XdsResourceType.java @@ -85,9 +85,12 @@ abstract class XdsResourceType { abstract String typeUrlV2(); - // Non-null for State of the World resources. - @Nullable - abstract XdsResourceType dependentResource(); + // Do not confuse with the SotW approach: it is the mechanism in which the client must specify all + // resource names it is interested in with each request. Different resource types may behave + // differently in this approach. For LDS and CDS resources, the server must return all resources + // that the client has subscribed to in each request. For RDS and EDS, the server may only return + // the resources that need an update. + abstract boolean isFullStateOfTheWorld(); static class Args { final ServerInfo serverInfo; @@ -125,7 +128,6 @@ ValidatedResourceUpdate parse(Args args, List resources) { Set unpackedResources = new HashSet<>(resources.size()); Set invalidResources = new HashSet<>(); List errors = new ArrayList<>(); - Set retainedResources = new HashSet<>(); for (int i = 0; i < resources.size(); i++) { Any resource = resources.get(i); @@ -156,7 +158,7 @@ ValidatedResourceUpdate parse(Args args, List resources) { T resourceUpdate; try { - resourceUpdate = doParse(args, unpackedMessage, retainedResources, isResourceV3); + resourceUpdate = doParse(args, unpackedMessage, isResourceV3); } catch (XdsClientImpl.ResourceInvalidException e) { errors.add(String.format("%s response %s '%s' validation error: %s", typeName(), unpackedClassName().getSimpleName(), cname, e.getMessage())); @@ -168,12 +170,11 @@ ValidatedResourceUpdate parse(Args args, List resources) { parsedResources.put(cname, new ParsedResource(resourceUpdate, resource)); } return new ValidatedResourceUpdate(parsedResources, unpackedResources, invalidResources, - errors, retainedResources); + errors); } - abstract T doParse(Args args, Message unpackedMessage, Set retainedResources, - boolean isResourceV3) + abstract T doParse(Args args, Message unpackedMessage, boolean isResourceV3) throws ResourceInvalidException; /** @@ -231,19 +232,16 @@ static final class ValidatedResourceUpdate { Set unpackedResources; Set invalidResources; List errors; - Set retainedResources; // validated resource update public ValidatedResourceUpdate(Map> parsedResources, Set unpackedResources, Set invalidResources, - List errors, - Set retainedResources) { + List errors) { this.parsedResources = parsedResources; this.unpackedResources = unpackedResources; this.invalidResources = invalidResources; this.errors = errors; - this.retainedResources = retainedResources; } } diff --git a/xds/src/main/java/io/grpc/xds/XdsRouteConfigureResource.java b/xds/src/main/java/io/grpc/xds/XdsRouteConfigureResource.java index 166809c87e1..d5a0eecc0e6 100644 --- a/xds/src/main/java/io/grpc/xds/XdsRouteConfigureResource.java +++ b/xds/src/main/java/io/grpc/xds/XdsRouteConfigureResource.java @@ -107,10 +107,9 @@ String typeUrlV2() { return ADS_TYPE_URL_RDS_V2; } - @Nullable @Override - XdsResourceType dependentResource() { - return null; + boolean isFullStateOfTheWorld() { + return false; } @Override @@ -119,8 +118,7 @@ Class unpackedClassName() { } @Override - RdsUpdate doParse(XdsResourceType.Args args, Message unpackedMessage, - Set retainedResources, boolean isResourceV3) + RdsUpdate doParse(XdsResourceType.Args args, Message unpackedMessage, boolean isResourceV3) throws ResourceInvalidException { if (!(unpackedMessage instanceof RouteConfiguration)) { throw new ResourceInvalidException("Invalid message type: " + unpackedMessage.getClass()); diff --git a/xds/src/test/java/io/grpc/xds/XdsClientImplDataTest.java b/xds/src/test/java/io/grpc/xds/XdsClientImplDataTest.java index 993fb910f3e..8c6ccc27806 100644 --- a/xds/src/test/java/io/grpc/xds/XdsClientImplDataTest.java +++ b/xds/src/test/java/io/grpc/xds/XdsClientImplDataTest.java @@ -135,10 +135,8 @@ import io.grpc.xds.internal.Matchers.HeaderMatcher; import java.util.Arrays; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import javax.annotation.Nullable; @@ -1301,7 +1299,7 @@ public void parseHttpConnectionManager_xffNumTrustedHopsUnsupported() thrown.expect(ResourceInvalidException.class); thrown.expectMessage("HttpConnectionManager with xff_num_trusted_hops unsupported"); XdsListenerResource.parseHttpConnectionManager( - hcm, new HashSet(), filterRegistry, false /* does not matter */, + hcm, filterRegistry, false /* does not matter */, true /* does not matter */); } @@ -1315,7 +1313,7 @@ public void parseHttpConnectionManager_OriginalIpDetectionExtensionsMustEmpty() thrown.expect(ResourceInvalidException.class); thrown.expectMessage("HttpConnectionManager with original_ip_detection_extensions unsupported"); XdsListenerResource.parseHttpConnectionManager( - hcm, new HashSet(), filterRegistry, false /* does not matter */, false); + hcm, filterRegistry, false /* does not matter */, false); } @Test @@ -1330,7 +1328,7 @@ public void parseHttpConnectionManager_missingRdsAndInlinedRouteConfiguration() thrown.expect(ResourceInvalidException.class); thrown.expectMessage("HttpConnectionManager neither has inlined route_config nor RDS"); XdsListenerResource.parseHttpConnectionManager( - hcm, new HashSet(), filterRegistry, false /* does not matter */, + hcm, filterRegistry, false /* does not matter */, true /* does not matter */); } @@ -1349,7 +1347,7 @@ public void parseHttpConnectionManager_duplicateHttpFilters() throws ResourceInv thrown.expect(ResourceInvalidException.class); thrown.expectMessage("HttpConnectionManager contains duplicate HttpFilter: envoy.filter.foo"); XdsListenerResource.parseHttpConnectionManager( - hcm, new HashSet(), filterRegistry, true /* parseHttpFilter */, + hcm, filterRegistry, true /* parseHttpFilter */, true /* does not matter */); } @@ -1367,7 +1365,7 @@ public void parseHttpConnectionManager_lastNotTerminal() throws ResourceInvalidE thrown.expect(ResourceInvalidException.class); thrown.expectMessage("The last HttpFilter must be a terminal filter: envoy.filter.bar"); XdsListenerResource.parseHttpConnectionManager( - hcm, new HashSet(), filterRegistry, true /* parseHttpFilter */, + hcm, filterRegistry, true /* parseHttpFilter */, true /* does not matter */); } @@ -1385,7 +1383,7 @@ public void parseHttpConnectionManager_terminalNotLast() throws ResourceInvalidE thrown.expect(ResourceInvalidException.class); thrown.expectMessage("A terminal HttpFilter must be the last filter: terminal"); XdsListenerResource.parseHttpConnectionManager( - hcm, new HashSet(), filterRegistry, true /* parseHttpFilter */, + hcm, filterRegistry, true /* parseHttpFilter */, true); } @@ -1401,7 +1399,7 @@ public void parseHttpConnectionManager_unknownFilters() throws ResourceInvalidEx thrown.expect(ResourceInvalidException.class); thrown.expectMessage("The last HttpFilter must be a terminal filter: envoy.filter.bar"); XdsListenerResource.parseHttpConnectionManager( - hcm, new HashSet(), filterRegistry, true /* parseHttpFilter */, + hcm, filterRegistry, true /* parseHttpFilter */, true /* does not matter */); } @@ -1413,7 +1411,7 @@ public void parseHttpConnectionManager_emptyFilters() throws ResourceInvalidExce thrown.expect(ResourceInvalidException.class); thrown.expectMessage("Missing HttpFilter in HttpConnectionManager."); XdsListenerResource.parseHttpConnectionManager( - hcm, new HashSet(), filterRegistry, true /* parseHttpFilter */, + hcm, filterRegistry, true /* parseHttpFilter */, true /* does not matter */); } @@ -1459,7 +1457,7 @@ public void parseHttpConnectionManager_clusterSpecifierPlugin() throws Exception .build(); io.grpc.xds.HttpConnectionManager parsedHcm = XdsListenerResource.parseHttpConnectionManager( - hcm, new HashSet(), filterRegistry, false /* parseHttpFilter */, + hcm, filterRegistry, false /* parseHttpFilter */, true /* does not matter */); VirtualHost virtualHost = Iterables.getOnlyElement(parsedHcm.virtualHosts()); @@ -1536,7 +1534,7 @@ public void parseHttpConnectionManager_duplicatePluginName() throws Exception { thrown.expectMessage("Multiple ClusterSpecifierPlugins with the same name: rls-plugin-1"); XdsListenerResource.parseHttpConnectionManager( - hcm, new HashSet(), filterRegistry, false /* parseHttpFilter */, + hcm, filterRegistry, false /* parseHttpFilter */, true /* does not matter */); } @@ -1585,7 +1583,7 @@ public void parseHttpConnectionManager_pluginNameNotFound() throws Exception { thrown.expectMessage("ClusterSpecifierPlugin for [invalid-plugin-name] not found"); XdsListenerResource.parseHttpConnectionManager( - hcm, new HashSet(), filterRegistry, false /* parseHttpFilter */, + hcm, filterRegistry, false /* parseHttpFilter */, true /* does not matter */); } @@ -1655,8 +1653,8 @@ public void parseHttpConnectionManager_optionalPlugin() throws ResourceInvalidEx .addRoutes(optionalRoute)) .build(); io.grpc.xds.HttpConnectionManager parsedHcm = XdsListenerResource.parseHttpConnectionManager( - HttpConnectionManager.newBuilder().setRouteConfig(routeConfig).build(), - new HashSet<>(), filterRegistry, false /* parseHttpFilter */, true /* does not matter */); + HttpConnectionManager.newBuilder().setRouteConfig(routeConfig).build(), filterRegistry, + false /* parseHttpFilter */, true /* does not matter */); // Verify that the only route left is the one with the registered RLS plugin `rls-plugin-1`, // while the route with unregistered optional `optional-plugin-`1 has been skipped. @@ -1671,7 +1669,6 @@ public void parseHttpConnectionManager_optionalPlugin() throws ResourceInvalidEx @Test public void parseHttpConnectionManager_validateRdsConfigSource() throws Exception { XdsResourceType.enableRouteLookup = true; - Set rdsResources = new HashSet<>(); HttpConnectionManager hcm1 = HttpConnectionManager.newBuilder() @@ -1681,7 +1678,7 @@ public void parseHttpConnectionManager_validateRdsConfigSource() throws Exceptio ConfigSource.newBuilder().setAds(AggregatedConfigSource.getDefaultInstance()))) .build(); XdsListenerResource.parseHttpConnectionManager( - hcm1, rdsResources, filterRegistry, false /* parseHttpFilter */, + hcm1, filterRegistry, false /* parseHttpFilter */, true /* does not matter */); HttpConnectionManager hcm2 = @@ -1692,7 +1689,7 @@ public void parseHttpConnectionManager_validateRdsConfigSource() throws Exceptio ConfigSource.newBuilder().setSelf(SelfConfigSource.getDefaultInstance()))) .build(); XdsListenerResource.parseHttpConnectionManager( - hcm2, rdsResources, filterRegistry, false /* parseHttpFilter */, + hcm2, filterRegistry, false /* parseHttpFilter */, true /* does not matter */); HttpConnectionManager hcm3 = @@ -1707,7 +1704,7 @@ public void parseHttpConnectionManager_validateRdsConfigSource() throws Exceptio thrown.expectMessage( "HttpConnectionManager contains invalid RDS: must specify ADS or self ConfigSource"); XdsListenerResource.parseHttpConnectionManager( - hcm3, rdsResources, filterRegistry, false /* parseHttpFilter */, + hcm3, filterRegistry, false /* parseHttpFilter */, true /* does not matter */); } @@ -1892,7 +1889,7 @@ public void parseCluster_ringHashLbPolicy_defaultLbConfig() throws ResourceInval .build(); CdsUpdate update = XdsClusterResource.processCluster( - cluster, new HashSet(), null, LRS_SERVER_INFO, + cluster, null, LRS_SERVER_INFO, LoadBalancerRegistry.getDefaultRegistry()); LbConfig lbConfig = ServiceConfigUtil.unwrapLoadBalancingConfig(update.lbPolicyConfig()); assertThat(lbConfig.getPolicyName()).isEqualTo("ring_hash_experimental"); @@ -1914,7 +1911,7 @@ public void parseCluster_leastRequestLbPolicy_defaultLbConfig() throws ResourceI .build(); CdsUpdate update = XdsClusterResource.processCluster( - cluster, new HashSet(), null, LRS_SERVER_INFO, + cluster, null, LRS_SERVER_INFO, LoadBalancerRegistry.getDefaultRegistry()); LbConfig lbConfig = ServiceConfigUtil.unwrapLoadBalancingConfig(update.lbPolicyConfig()); assertThat(lbConfig.getPolicyName()).isEqualTo("wrr_locality_experimental"); @@ -1942,13 +1939,12 @@ public void parseCluster_transportSocketMatches_exception() throws ResourceInval thrown.expect(ResourceInvalidException.class); thrown.expectMessage( "Cluster cluster-foo.googleapis.com: transport-socket-matches not supported."); - XdsClusterResource.processCluster(cluster, new HashSet(), null, LRS_SERVER_INFO, + XdsClusterResource.processCluster(cluster, null, LRS_SERVER_INFO, LoadBalancerRegistry.getDefaultRegistry()); } @Test public void parseCluster_validateEdsSourceConfig() throws ResourceInvalidException { - Set retainedEdsResources = new HashSet<>(); Cluster cluster1 = Cluster.newBuilder() .setName("cluster-foo.googleapis.com") .setType(DiscoveryType.EDS) @@ -1960,7 +1956,7 @@ public void parseCluster_validateEdsSourceConfig() throws ResourceInvalidExcepti .setServiceName("service-foo.googleapis.com")) .setLbPolicy(LbPolicy.ROUND_ROBIN) .build(); - XdsClusterResource.processCluster(cluster1, retainedEdsResources, null, LRS_SERVER_INFO, + XdsClusterResource.processCluster(cluster1, null, LRS_SERVER_INFO, LoadBalancerRegistry.getDefaultRegistry()); Cluster cluster2 = Cluster.newBuilder() @@ -1974,7 +1970,7 @@ public void parseCluster_validateEdsSourceConfig() throws ResourceInvalidExcepti .setServiceName("service-foo.googleapis.com")) .setLbPolicy(LbPolicy.ROUND_ROBIN) .build(); - XdsClusterResource.processCluster(cluster2, retainedEdsResources, null, LRS_SERVER_INFO, + XdsClusterResource.processCluster(cluster2, null, LRS_SERVER_INFO, LoadBalancerRegistry.getDefaultRegistry()); Cluster cluster3 = Cluster.newBuilder() @@ -1993,7 +1989,7 @@ public void parseCluster_validateEdsSourceConfig() throws ResourceInvalidExcepti thrown.expectMessage( "Cluster cluster-foo.googleapis.com: field eds_cluster_config must be set to indicate to" + " use EDS over ADS or self ConfigSource"); - XdsClusterResource.processCluster(cluster3, retainedEdsResources, null, LRS_SERVER_INFO, + XdsClusterResource.processCluster(cluster3, null, LRS_SERVER_INFO, LoadBalancerRegistry.getDefaultRegistry()); } @@ -2007,7 +2003,7 @@ public void parseServerSideListener_invalidTrafficDirection() throws ResourceInv thrown.expect(ResourceInvalidException.class); thrown.expectMessage("Listener listener1 with invalid traffic direction: OUTBOUND"); XdsListenerResource.parseServerSideListener( - listener, new HashSet(), null, filterRegistry, null, true /* does not matter */); + listener, null, filterRegistry, null, true /* does not matter */); } @Test @@ -2017,7 +2013,7 @@ public void parseServerSideListener_noTrafficDirection() throws ResourceInvalidE .setName("listener1") .build(); XdsListenerResource.parseServerSideListener( - listener, new HashSet(), null, filterRegistry, null, true /* does not matter */); + listener, null, filterRegistry, null, true /* does not matter */); } @Test @@ -2031,7 +2027,7 @@ public void parseServerSideListener_listenerFiltersPresent() throws ResourceInva thrown.expect(ResourceInvalidException.class); thrown.expectMessage("Listener listener1 cannot have listener_filters"); XdsListenerResource.parseServerSideListener( - listener, new HashSet(), null, filterRegistry, null, true /* does not matter */); + listener, null, filterRegistry, null, true /* does not matter */); } @Test @@ -2045,7 +2041,7 @@ public void parseServerSideListener_useOriginalDst() throws ResourceInvalidExcep thrown.expect(ResourceInvalidException.class); thrown.expectMessage("Listener listener1 cannot have use_original_dst set to true"); XdsListenerResource.parseServerSideListener( - listener, new HashSet(), null, filterRegistry, null, true /* does not matter */); + listener,null, filterRegistry, null, true /* does not matter */); } @Test @@ -2094,7 +2090,7 @@ public void parseServerSideListener_nonUniqueFilterChainMatch() throws ResourceI thrown.expect(ResourceInvalidException.class); thrown.expectMessage("FilterChainMatch must be unique. Found duplicate:"); XdsListenerResource.parseServerSideListener( - listener, new HashSet(), null, filterRegistry, null, true /* does not matter */); + listener, null, filterRegistry, null, true /* does not matter */); } @Test @@ -2143,7 +2139,7 @@ public void parseServerSideListener_nonUniqueFilterChainMatch_sameFilter() thrown.expect(ResourceInvalidException.class); thrown.expectMessage("FilterChainMatch must be unique. Found duplicate:"); XdsListenerResource.parseServerSideListener( - listener, new HashSet(), null, filterRegistry, null, true /* does not matter */); + listener,null, filterRegistry, null, true /* does not matter */); } @Test @@ -2192,7 +2188,7 @@ public void parseServerSideListener_uniqueFilterChainMatch() throws ResourceInva .addAllFilterChains(Arrays.asList(filterChain1, filterChain2)) .build(); XdsListenerResource.parseServerSideListener( - listener, new HashSet(), null, filterRegistry, null, true /* does not matter */); + listener, null, filterRegistry, null, true /* does not matter */); } @Test @@ -2207,7 +2203,7 @@ public void parseFilterChain_noHcm() throws ResourceInvalidException { thrown.expectMessage( "FilterChain filter-chain-foo should contain exact one HttpConnectionManager filter"); XdsListenerResource.parseFilterChain( - filterChain, new HashSet(), null, filterRegistry, null, null, + filterChain, null, filterRegistry, null, null, true /* does not matter */); } @@ -2226,7 +2222,7 @@ public void parseFilterChain_duplicateFilter() throws ResourceInvalidException { thrown.expectMessage( "FilterChain filter-chain-foo should contain exact one HttpConnectionManager filter"); XdsListenerResource.parseFilterChain( - filterChain, new HashSet(), null, filterRegistry, null, null, + filterChain, null, filterRegistry, null, null, true /* does not matter */); } @@ -2245,7 +2241,7 @@ public void parseFilterChain_filterMissingTypedConfig() throws ResourceInvalidEx "FilterChain filter-chain-foo contains filter envoy.http_connection_manager " + "without typed_config"); XdsListenerResource.parseFilterChain( - filterChain, new HashSet(), null, filterRegistry, null, null, + filterChain, null, filterRegistry, null, null, true /* does not matter */); } @@ -2268,7 +2264,7 @@ public void parseFilterChain_unsupportedFilter() throws ResourceInvalidException "FilterChain filter-chain-foo contains filter unsupported with unsupported " + "typed_config type unsupported-type-url"); XdsListenerResource.parseFilterChain( - filterChain, new HashSet(), null, filterRegistry, null, null, + filterChain, null, filterRegistry, null, null, true /* does not matter */); } @@ -2296,10 +2292,10 @@ public void parseFilterChain_noName() throws ResourceInvalidException { .build(); EnvoyServerProtoData.FilterChain parsedFilterChain1 = XdsListenerResource.parseFilterChain( - filterChain1, new HashSet(), null, filterRegistry, null, + filterChain1, null, filterRegistry, null, null, true /* does not matter */); EnvoyServerProtoData.FilterChain parsedFilterChain2 = XdsListenerResource.parseFilterChain( - filterChain2, new HashSet(), null, filterRegistry, null, + filterChain2, null, filterRegistry, null, null, true /* does not matter */); assertThat(parsedFilterChain1.name()).isEqualTo(parsedFilterChain2.name()); } diff --git a/xds/src/test/java/io/grpc/xds/XdsClientImplTestBase.java b/xds/src/test/java/io/grpc/xds/XdsClientImplTestBase.java index 31d10abd841..ca996af074a 100644 --- a/xds/src/test/java/io/grpc/xds/XdsClientImplTestBase.java +++ b/xds/src/test/java/io/grpc/xds/XdsClientImplTestBase.java @@ -806,19 +806,14 @@ public void ldsResponseErrorHandling_subscribedResourceInvalid_withRdsSubscripti verifyResourceMetadataAcked(LDS, "C", resourcesV1.get("C"), VERSION_1, TIME_INCREMENT); } call.verifyRequestNack(LDS, subscribedResourceNames, VERSION_1, "0001", NODE, errorsV2); - // {A.1} -> does not exist, missing from {A} + // {A.1} -> version 1 // {B.1} -> version 1 // {C.1} -> does not exist because {C} does not exist - verifyResourceMetadataDoesNotExist(RDS, "A.1"); + verifyResourceMetadataAcked(RDS, "A.1", resourcesV11.get("A.1"), VERSION_1, TIME_INCREMENT * 2); verifyResourceMetadataAcked(RDS, "B.1", resourcesV11.get("B.1"), VERSION_1, TIME_INCREMENT * 2); - if (!ignoreResourceDeletion()) { - verifyResourceMetadataDoesNotExist(RDS, "C.1"); - } else { - // When resource deletion is disabled, {C.1} is not deleted when {C} is deleted. - // Verify {C.1} stays in the previous version VERSION_1. - verifyResourceMetadataAcked(RDS, "C.1", resourcesV11.get("C.1"), VERSION_1, - TIME_INCREMENT * 2); - } + // Verify {C.1} stays in the previous version VERSION_1, no matter {C} is deleted or not. + verifyResourceMetadataAcked(RDS, "C.1", resourcesV11.get("C.1"), VERSION_1, + TIME_INCREMENT * 2); } @Test @@ -1556,8 +1551,8 @@ public void rdsResourceDeletedByLdsApiListener() { call.sendResponse(LDS, testListenerVhosts, VERSION_2, "0001"); verify(ldsResourceWatcher, times(2)).onChanged(ldsUpdateCaptor.capture()); verifyGoldenListenerVhosts(ldsUpdateCaptor.getValue()); - verify(rdsResourceWatcher).onResourceDoesNotExist(RDS_RESOURCE); - verifyResourceMetadataDoesNotExist(RDS, RDS_RESOURCE); + verifyNoMoreInteractions(rdsResourceWatcher); + verifyResourceMetadataAcked(RDS, RDS_RESOURCE, testRouteConfig, VERSION_1, TIME_INCREMENT * 2); verifyResourceMetadataAcked( LDS, LDS_RESOURCE, testListenerVhosts, VERSION_2, TIME_INCREMENT * 3); verifySubscribedResourcesMetadataSizes(1, 0, 1, 0); @@ -1624,8 +1619,8 @@ public void rdsResourcesDeletedByLdsTcpListener() { parsedFilterChain = Iterables.getOnlyElement( ldsUpdateCaptor.getValue().listener().filterChains()); assertThat(parsedFilterChain.httpConnectionManager().virtualHosts()).hasSize(VHOST_SIZE); - verify(rdsResourceWatcher).onResourceDoesNotExist(RDS_RESOURCE); - verifyResourceMetadataDoesNotExist(RDS, RDS_RESOURCE); + verify(rdsResourceWatcher, never()).onResourceDoesNotExist(RDS_RESOURCE); + verifyResourceMetadataAcked(RDS, RDS_RESOURCE, testRouteConfig, VERSION_1, TIME_INCREMENT * 2); verifyResourceMetadataAcked( LDS, LISTENER_RESOURCE, packedListener, VERSION_2, TIME_INCREMENT * 3); verifySubscribedResourcesMetadataSizes(1, 0, 1, 0); @@ -1896,19 +1891,14 @@ public void cdsResponseErrorHandling_subscribedResourceInvalid_withEdsSubscripti verifyResourceMetadataAcked(CDS, "C", resourcesV1.get("C"), VERSION_1, TIME_INCREMENT); } call.verifyRequestNack(CDS, subscribedResourceNames, VERSION_1, "0001", NODE, errorsV2); - // {A.1} -> does not exist, missing from {A} + // {A.1} -> version 1 // {B.1} -> version 1 // {C.1} -> does not exist because {C} does not exist - verifyResourceMetadataDoesNotExist(EDS, "A.1"); + verifyResourceMetadataAcked(EDS, "A.1", resourcesV11.get("A.1"), VERSION_1, TIME_INCREMENT * 2); verifyResourceMetadataAcked(EDS, "B.1", resourcesV11.get("B.1"), VERSION_1, TIME_INCREMENT * 2); - if (!ignoreResourceDeletion()) { - verifyResourceMetadataDoesNotExist(EDS, "C.1"); - } else { - // When resource deletion is disabled, {C.1} is not deleted when {C} is deleted. - // Verify {C.1} stays in the previous version VERSION_1. - verifyResourceMetadataAcked(EDS, "C.1", resourcesV11.get("C.1"), VERSION_1, - TIME_INCREMENT * 2); - } + // Verify {C.1} stays in the previous version VERSION_1. {C1} deleted or not does not matter. + verifyResourceMetadataAcked(EDS, "C.1", resourcesV11.get("C.1"), VERSION_1, + TIME_INCREMENT * 2); } @Test @@ -3026,10 +3016,11 @@ public void edsResourceDeletedByCds() { assertThat(cdsUpdateCaptor.getValue().edsServiceName()).isNull(); // Note that the endpoint must be deleted even if the ignore_resource_deletion feature. // This happens because the cluster CDS_RESOURCE is getting replaced, and not deleted. - verify(edsResourceWatcher).onResourceDoesNotExist(EDS_RESOURCE); + verify(edsResourceWatcher, never()).onResourceDoesNotExist(EDS_RESOURCE); verify(edsResourceWatcher, never()).onResourceDoesNotExist(resource); verifyNoMoreInteractions(cdsWatcher, edsWatcher); - verifyResourceMetadataDoesNotExist(EDS, EDS_RESOURCE); + verifyResourceMetadataAcked( + EDS, EDS_RESOURCE, clusterLoadAssignments.get(0), VERSION_1, TIME_INCREMENT * 2); verifyResourceMetadataAcked( EDS, resource, clusterLoadAssignments.get(1), VERSION_1, TIME_INCREMENT * 2); // no change verifyResourceMetadataAcked(CDS, resource, clusters.get(0), VERSION_2, TIME_INCREMENT * 3); From 79f4411d20baa917f119fc603ce3857640feb0dc Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Fri, 2 Dec 2022 13:19:59 -0800 Subject: [PATCH 27/39] xds: Remove outdated comment about observing total weight total_weight is deprecated and serves no value. --- xds/src/main/java/io/grpc/xds/XdsRouteConfigureResource.java | 1 - 1 file changed, 1 deletion(-) diff --git a/xds/src/main/java/io/grpc/xds/XdsRouteConfigureResource.java b/xds/src/main/java/io/grpc/xds/XdsRouteConfigureResource.java index d5a0eecc0e6..0dfc32f805e 100644 --- a/xds/src/main/java/io/grpc/xds/XdsRouteConfigureResource.java +++ b/xds/src/main/java/io/grpc/xds/XdsRouteConfigureResource.java @@ -521,7 +521,6 @@ static StructOrError parseRouteAction( } weightedClusters.add(clusterWeightOrError.getStruct()); } - // TODO(chengyuanzhang): validate if the sum of weights equals to total weight. return StructOrError.fromStruct(VirtualHost.Route.RouteAction.forWeightedClusters( weightedClusters, hashPolicies, timeoutNano, retryPolicy)); case CLUSTER_SPECIFIER_PLUGIN: From 3e5fa7c5df67d6820be2cd0c31032e0d4161284b Mon Sep 17 00:00:00 2001 From: Larry Safran <107004254+larry-safran@users.noreply.github.com> Date: Fri, 2 Dec 2022 23:15:48 +0000 Subject: [PATCH 28/39] xds:Fix ConcurrentModificationException in PriorityLoadBalancer (#9728) Fix ConcurrentModificationException in PriorityLoadBalancer by making copy of children values to iterate rather than directly using children in for loop. --- .../io/grpc/xds/PriorityLoadBalancer.java | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/PriorityLoadBalancer.java b/xds/src/main/java/io/grpc/xds/PriorityLoadBalancer.java index 0a9def370e3..3e539f54b06 100644 --- a/xds/src/main/java/io/grpc/xds/PriorityLoadBalancer.java +++ b/xds/src/main/java/io/grpc/xds/PriorityLoadBalancer.java @@ -37,6 +37,8 @@ import io.grpc.xds.PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig; import io.grpc.xds.XdsLogger.XdsLogLevel; import io.grpc.xds.XdsSubchannelPickers.ErrorPicker; +import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -59,6 +61,8 @@ final class PriorityLoadBalancer extends LoadBalancer { // Includes all active and deactivated children. Mutable. New entries are only added from priority // 0 up to the selected priority. An entry is only deleted 15 minutes after its deactivation. + // Note that because all configuration updates should be atomic, updates to children can happen + // outside of the synchronization context. Therefore copy values before looping over them. private final Map children = new HashMap<>(); // Following fields are only null initially. @@ -91,15 +95,20 @@ public boolean acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) { priorityNames = config.priorities; priorityConfigs = config.childConfigs; Set prioritySet = new HashSet<>(config.priorities); - for (String priority : children.keySet()) { + ArrayList childKeys = new ArrayList<>(children.keySet()); + for (String priority : childKeys) { if (!prioritySet.contains(priority)) { - children.get(priority).deactivate(); + ChildLbState childLbState = children.get(priority); + if (childLbState != null) { + childLbState.deactivate(); + } } } handlingResolvedAddresses = true; for (String priority : priorityNames) { - if (children.containsKey(priority)) { - children.get(priority).updateResolvedAddresses(); + ChildLbState childLbState = children.get(priority); + if (childLbState != null) { + childLbState.updateResolvedAddresses(); } } handlingResolvedAddresses = false; @@ -111,7 +120,8 @@ public boolean acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) { public void handleNameResolutionError(Status error) { logger.log(XdsLogLevel.WARNING, "Received name resolution error: {0}", error); boolean gotoTransientFailure = true; - for (ChildLbState child : children.values()) { + Collection childValues = new ArrayList<>(children.values()); + for (ChildLbState child : childValues) { if (priorityNames.contains(child.priority)) { child.lb.handleNameResolutionError(error); gotoTransientFailure = false; @@ -125,7 +135,8 @@ public void handleNameResolutionError(Status error) { @Override public void shutdown() { logger.log(XdsLogLevel.INFO, "Shutdown"); - for (ChildLbState child : children.values()) { + Collection childValues = new ArrayList<>(children.values()); + for (ChildLbState child : childValues) { child.tearDown(); } children.clear(); From e14cba0bae8a9f54215e57d054f0580e549f8e88 Mon Sep 17 00:00:00 2001 From: Larry Safran <107004254+larry-safran@users.noreply.github.com> Date: Sat, 3 Dec 2022 00:04:17 +0000 Subject: [PATCH 29/39] Update clarifying comment per code review. (#9730) --- xds/src/main/java/io/grpc/xds/PriorityLoadBalancer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/PriorityLoadBalancer.java b/xds/src/main/java/io/grpc/xds/PriorityLoadBalancer.java index 3e539f54b06..e833b3777b8 100644 --- a/xds/src/main/java/io/grpc/xds/PriorityLoadBalancer.java +++ b/xds/src/main/java/io/grpc/xds/PriorityLoadBalancer.java @@ -61,8 +61,8 @@ final class PriorityLoadBalancer extends LoadBalancer { // Includes all active and deactivated children. Mutable. New entries are only added from priority // 0 up to the selected priority. An entry is only deleted 15 minutes after its deactivation. - // Note that because all configuration updates should be atomic, updates to children can happen - // outside of the synchronization context. Therefore copy values before looping over them. + // Note that calling into a child can cause the child to call back into the LB policy and modify + // the map. Therefore copy values before looping over them. private final Map children = new HashMap<>(); // Following fields are only null initially. From bf0b92a963a45cf66fe2cf553604ce2fc2f88eaa Mon Sep 17 00:00:00 2001 From: Mohan Li <67390330+mohanli-ml@users.noreply.github.com> Date: Tue, 6 Dec 2022 08:06:00 -0800 Subject: [PATCH 30/39] Log xDS node ID with verbosity INFO (#9731) Log xDS node ID so that we can better debug DirectPath issues. b/260634412 --- xds/src/main/java/io/grpc/xds/XdsClientImpl.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/xds/src/main/java/io/grpc/xds/XdsClientImpl.java b/xds/src/main/java/io/grpc/xds/XdsClientImpl.java index f05210b51c6..26392acc733 100644 --- a/xds/src/main/java/io/grpc/xds/XdsClientImpl.java +++ b/xds/src/main/java/io/grpc/xds/XdsClientImpl.java @@ -60,6 +60,8 @@ import java.util.Set; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.annotation.Nullable; /** @@ -67,6 +69,10 @@ */ final class XdsClientImpl extends XdsClient implements XdsResponseHandler, ResourceStore { + private static boolean LOG_XDS_NODE_ID = Boolean.parseBoolean( + System.getenv("GRPC_LOG_XDS_NODE_ID")); + private static final Logger classLogger = Logger.getLogger(XdsClientImpl.class.getName()); + // Longest time to wait, since the subscription to some resource, for concluding its absence. @VisibleForTesting static final int INITIAL_RESOURCE_FETCH_TIMEOUT_SEC = 15; @@ -126,6 +132,9 @@ public void uncaughtException(Thread t, Throwable e) { logId = InternalLogId.allocate("xds-client", null); logger = XdsLogger.withLogId(logId); logger.log(XdsLogLevel.INFO, "Created"); + if (LOG_XDS_NODE_ID) { + classLogger.log(Level.INFO, "xDS node ID: {0}", bootstrapInfo.node().getId()); + } } private void maybeCreateXdsChannelWithLrs(ServerInfo serverInfo) { From 786417085c3d04aeab140885baba2399da7b1cc2 Mon Sep 17 00:00:00 2001 From: yifeizhuang Date: Wed, 7 Dec 2022 13:16:21 -0800 Subject: [PATCH 31/39] xds: Nack xds response when weighted cluster total weight sums zero (#9738) --- .../grpc/xds/XdsRouteConfigureResource.java | 5 ++ .../io/grpc/xds/XdsClientImplDataTest.java | 22 +++++++++ .../io/grpc/xds/XdsClientImplTestBase.java | 46 +++++++++++++++++++ 3 files changed, 73 insertions(+) diff --git a/xds/src/main/java/io/grpc/xds/XdsRouteConfigureResource.java b/xds/src/main/java/io/grpc/xds/XdsRouteConfigureResource.java index 0dfc32f805e..e6c73d2df28 100644 --- a/xds/src/main/java/io/grpc/xds/XdsRouteConfigureResource.java +++ b/xds/src/main/java/io/grpc/xds/XdsRouteConfigureResource.java @@ -511,6 +511,7 @@ static StructOrError parseRouteAction( return StructOrError.fromError("No cluster found in weighted cluster list"); } List weightedClusters = new ArrayList<>(); + int clusterWeightSum = 0; for (io.envoyproxy.envoy.config.route.v3.WeightedCluster.ClusterWeight clusterWeight : clusterWeights) { StructOrError clusterWeightOrError = @@ -519,8 +520,12 @@ static StructOrError parseRouteAction( return StructOrError.fromError("RouteAction contains invalid ClusterWeight: " + clusterWeightOrError.getErrorDetail()); } + clusterWeightSum += clusterWeight.getWeight().getValue(); weightedClusters.add(clusterWeightOrError.getStruct()); } + if (clusterWeightSum <= 0) { + return StructOrError.fromError("Sum of cluster weights should be above 0."); + } return StructOrError.fromStruct(VirtualHost.Route.RouteAction.forWeightedClusters( weightedClusters, hashPolicies, timeoutNano, retryPolicy)); case CLUSTER_SPECIFIER_PLUGIN: diff --git a/xds/src/test/java/io/grpc/xds/XdsClientImplDataTest.java b/xds/src/test/java/io/grpc/xds/XdsClientImplDataTest.java index 8c6ccc27806..f47239c123d 100644 --- a/xds/src/test/java/io/grpc/xds/XdsClientImplDataTest.java +++ b/xds/src/test/java/io/grpc/xds/XdsClientImplDataTest.java @@ -521,6 +521,28 @@ public void parseRouteAction_withWeightedCluster() { ClusterWeight.create("cluster-bar", 70, ImmutableMap.of())); } + @Test + public void parseRouteAction_weightedClusterSum() { + io.envoyproxy.envoy.config.route.v3.RouteAction proto = + io.envoyproxy.envoy.config.route.v3.RouteAction.newBuilder() + .setWeightedClusters( + WeightedCluster.newBuilder() + .addClusters( + WeightedCluster.ClusterWeight + .newBuilder() + .setName("cluster-foo") + .setWeight(UInt32Value.newBuilder().setValue(0))) + .addClusters(WeightedCluster.ClusterWeight + .newBuilder() + .setName("cluster-bar") + .setWeight(UInt32Value.newBuilder().setValue(0)))) + .build(); + StructOrError struct = + XdsRouteConfigureResource.parseRouteAction(proto, filterRegistry, false, + ImmutableMap.of(), ImmutableSet.of()); + assertThat(struct.getErrorDetail()).isEqualTo("Sum of cluster weights should be above 0."); + } + @Test public void parseRouteAction_withTimeoutByGrpcTimeoutHeaderMax() { io.envoyproxy.envoy.config.route.v3.RouteAction proto = diff --git a/xds/src/test/java/io/grpc/xds/XdsClientImplTestBase.java b/xds/src/test/java/io/grpc/xds/XdsClientImplTestBase.java index ca996af074a..bc91f39cb2f 100644 --- a/xds/src/test/java/io/grpc/xds/XdsClientImplTestBase.java +++ b/xds/src/test/java/io/grpc/xds/XdsClientImplTestBase.java @@ -40,6 +40,7 @@ import com.google.protobuf.util.Durations; import io.envoyproxy.envoy.config.cluster.v3.OutlierDetection; import io.envoyproxy.envoy.config.route.v3.FilterConfig; +import io.envoyproxy.envoy.config.route.v3.WeightedCluster; import io.envoyproxy.envoy.extensions.filters.http.router.v3.Router; import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CertificateProviderPluginInstance; import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CommonTlsContext; @@ -1363,6 +1364,51 @@ public void rdsResponseErrorHandling_someResourcesFailedUnpack() { verify(rdsResourceWatcher).onChanged(any(RdsUpdate.class)); } + @Test + public void rdsResponseErrorHandling_nackWeightedSumZero() { + DiscoveryRpcCall call = startResourceWatcher(XdsRouteConfigureResource.getInstance(), + RDS_RESOURCE, rdsResourceWatcher); + verifyResourceMetadataRequested(RDS, RDS_RESOURCE); + + io.envoyproxy.envoy.config.route.v3.RouteAction routeAction = + io.envoyproxy.envoy.config.route.v3.RouteAction.newBuilder() + .setWeightedClusters( + WeightedCluster.newBuilder() + .addClusters( + WeightedCluster.ClusterWeight + .newBuilder() + .setName("cluster-foo") + .setWeight(UInt32Value.newBuilder().setValue(0))) + .addClusters(WeightedCluster.ClusterWeight + .newBuilder() + .setName("cluster-bar") + .setWeight(UInt32Value.newBuilder().setValue(0)))) + .build(); + io.envoyproxy.envoy.config.route.v3.Route route = + io.envoyproxy.envoy.config.route.v3.Route.newBuilder() + .setName("route-blade") + .setMatch( + io.envoyproxy.envoy.config.route.v3.RouteMatch.newBuilder() + .setPath("/service/method")) + .setRoute(routeAction) + .build(); + + Any zeroWeightSum = Any.pack(mf.buildRouteConfiguration(RDS_RESOURCE, + Arrays.asList(mf.buildVirtualHost(Arrays.asList(route), ImmutableMap.of())))); + List resources = ImmutableList.of(zeroWeightSum); + call.sendResponse(RDS, resources, VERSION_1, "0000"); + + List errors = ImmutableList.of( + "RDS response RouteConfiguration \'route-configuration.googleapis.com\' validation error: " + + "RouteConfiguration contains invalid virtual host: Virtual host [do not care] " + + "contains invalid route : Route [route-blade] contains invalid RouteAction: " + + "Sum of cluster weights should be above 0."); + verifySubscribedResourcesMetadataSizes(0, 0, 1, 0); + // The response is NACKed with the same error message. + call.verifyRequestNack(RDS, RDS_RESOURCE, "", "0000", NODE, errors); + verify(rdsResourceWatcher, never()).onChanged(any(RdsUpdate.class)); + } + /** * Tests a subscribed RDS resource transitioned to and from the invalid state. * From 9b5ca70f85001cf0ba9e3f85789cb9e9d826297e Mon Sep 17 00:00:00 2001 From: yifeizhuang Date: Wed, 7 Dec 2022 14:53:06 -0800 Subject: [PATCH 32/39] doc: add fake control plane xds test comments (#9735) --- .../FakeControlPlaneXdsIntegrationTest.java | 16 +++++++++++++++ .../grpc/xds/XdsTestControlPlaneService.java | 20 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/xds/src/test/java/io/grpc/xds/FakeControlPlaneXdsIntegrationTest.java b/xds/src/test/java/io/grpc/xds/FakeControlPlaneXdsIntegrationTest.java index 3f0927fb8d3..0c3cf61b28e 100644 --- a/xds/src/test/java/io/grpc/xds/FakeControlPlaneXdsIntegrationTest.java +++ b/xds/src/test/java/io/grpc/xds/FakeControlPlaneXdsIntegrationTest.java @@ -51,6 +51,22 @@ /** * Xds integration tests using a local control plane, implemented in {@link * XdsTestControlPlaneService}. Test cases can inject xds configs to the control plane for testing. + * + *

Test components: + * 1) A Control Plane {@link XdsTestControlPlaneService} accepts xds requests from multiple clients + * from the Data Plane, see {@link ControlPlaneRule}. + * 2) A test xDS server {@link XdsServerWrapper}, see {@link DataPlaneRule}. + * 3) A test xDS client that uses a testing scheme {@link XdsNameResolverProvider#createForTest}, + * see {@link DataPlaneRule}. + * + *

The configuration dependency and ephemeral port allocation requires the components to + * be initialized in a certain order: + * 1) Start the Control Plane server {@link XdsTestControlPlaneService}. After start the bootstrap + * information (w/ Control Plane's address) can be constructed for the Data Plane to initialize. + * 2) Set LDS and RDS config at the Control Plane. Get the bootstrap file from the Control + * Plane from 1). And then start the test xDS server (requires LDS/RDS and bootstrap file to start). + * 3) Construct EDS config w/ test server address from 2). Set CDS and EDS Config at the Control + * Plane. Then start the test xDS client (requires EDS to do xDS name resolution). */ @RunWith(JUnit4.class) public class FakeControlPlaneXdsIntegrationTest { diff --git a/xds/src/test/java/io/grpc/xds/XdsTestControlPlaneService.java b/xds/src/test/java/io/grpc/xds/XdsTestControlPlaneService.java index 82791a5582c..9a1ce3350de 100644 --- a/xds/src/test/java/io/grpc/xds/XdsTestControlPlaneService.java +++ b/xds/src/test/java/io/grpc/xds/XdsTestControlPlaneService.java @@ -33,6 +33,26 @@ import java.util.logging.Level; import java.util.logging.Logger; +/** +* A bidi-stream service that acts as a local xDS Control Plane. + * It accepts xDS config injection through a method call {@link #setXdsConfig}. Handling AdsStream + * response or updating xds config are run in syncContext. + * + *

The service maintains lookup tables: + * Subscriber table: map from each resource type, to a map from each client to subscribed resource + * names set. + * Resources table: store the resources in raw proto message. + * + *

xDS protocol requires version/nonce to avoid various race conditions. In this impl: + * Version stores the latest version number per each resource type. It is simply bumped up on each + * xds config set. + * Nonce stores the nonce number for each resource type and for each client. Incoming xDS requests + * share the same proto message type but may at different resources update phases: + * 1) Original: an initial xDS request. + * 2) NACK an xDS response. + * 3) ACK an xDS response. + * The service is capable of distinguish these cases when handling the request. + */ final class XdsTestControlPlaneService extends AggregatedDiscoveryServiceGrpc.AggregatedDiscoveryServiceImplBase { private static final Logger logger = Logger.getLogger(XdsTestControlPlaneService.class.getName()); From 2a0b86f7cd2a363cd1d19d56f9c47aead33261d6 Mon Sep 17 00:00:00 2001 From: yifeizhuang Date: Fri, 9 Dec 2022 15:21:47 -0800 Subject: [PATCH 33/39] binder: BinderInternal.setIBinder() is public static (#9743) --- binder/src/main/java/io/grpc/binder/BinderInternal.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/binder/src/main/java/io/grpc/binder/BinderInternal.java b/binder/src/main/java/io/grpc/binder/BinderInternal.java index ad0fe74e559..34f7793714f 100644 --- a/binder/src/main/java/io/grpc/binder/BinderInternal.java +++ b/binder/src/main/java/io/grpc/binder/BinderInternal.java @@ -28,7 +28,7 @@ public class BinderInternal { /** * Sets the receiver's {@link IBinder} using {@link IBinderReceiver#set(IBinder)}. */ - static void setIBinder(IBinderReceiver receiver, IBinder binder) { + public static void setIBinder(IBinderReceiver receiver, IBinder binder) { receiver.set(binder); } } From e325dc9112079ecd64e3099093ff0615e7e72de5 Mon Sep 17 00:00:00 2001 From: Greg Date: Wed, 14 Dec 2022 15:13:31 -0500 Subject: [PATCH 34/39] Replace ctx.host_configuration.host_path_separator with ctx.configuration.host_path_separator. (#9742) Replace ctx.host_configuration.host_path_separator with ctx.configuration.host_path_separator. This is because 1. we're removing ctx.host_configuration 2. host_path_separator's value doesn't depend on the configuration (the API is misleading by embedding it under ctx.configuration). So this is a no-op. Internal ref cl/494008561. --- java_grpc_library.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java_grpc_library.bzl b/java_grpc_library.bzl index 51e4f6996e8..11d6e393e98 100644 --- a/java_grpc_library.bzl +++ b/java_grpc_library.bzl @@ -85,7 +85,7 @@ def _java_rpc_library_impl(ctx): args = ctx.actions.args() args.add(toolchain.plugin, format = "--plugin=protoc-gen-rpc-plugin=%s") args.add("--rpc-plugin_out={0}:{1}".format(toolchain.plugin_arg, srcjar.path)) - args.add_joined("--descriptor_set_in", descriptor_set_in, join_with = ctx.host_configuration.host_path_separator) + args.add_joined("--descriptor_set_in", descriptor_set_in, join_with = ctx.configuration.host_path_separator) args.add_all(srcs, map_each = _path_ignoring_repository) ctx.actions.run( From f71447c077a86553a3e06a6c8b13e1af7fcc52b1 Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Mon, 19 Dec 2022 13:37:40 -0800 Subject: [PATCH 35/39] bazel: Include `@Generated` dep for autovalue Fixes #9755 --- BUILD.bazel | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/BUILD.bazel b/BUILD.bazel index a6d0e43dec3..40c04022673 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -64,5 +64,8 @@ java_library( exported_plugins = [":auto_value"], neverlink = 1, visibility = ["//:__subpackages__"], - exports = ["@com_google_auto_value_auto_value_annotations//jar"], + exports = [ + "@com_google_auto_value_auto_value_annotations//jar", + "@org_apache_tomcat_annotations_api//jar", # @Generated for Java 9+ + ], ) From a75ed4d5ba7a874ef6c0344a36f4e16d947e4fd3 Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Tue, 3 Jan 2023 10:12:18 -0800 Subject: [PATCH 36/39] bazel: Export deps from maven stand-in targets If an artifact on Maven Central exposes a type from gRPC on its API surface, then consumers of that artifact need that gRPC API in the compile classpath. Bazel handles this by making hjars for transitive dependencies, but if the dependencies are runtime_deps then Bazel won't generate hjars containing the needed symbols. We don't export netty-shaded because the classes already don't match Maven Central. If an artifact on Maven Central is exposing a netty-shaded class on its API surface, it wouldn't work anyway since the class simply doesn't exist for the Bazel build. Fixes #9772 --- core/BUILD.bazel | 7 +++---- netty/BUILD.bazel | 11 ++++++----- services/BUILD.bazel | 7 +++---- xds/BUILD.bazel | 7 +++---- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/core/BUILD.bazel b/core/BUILD.bazel index 60a08798d58..3ca51e66c94 100644 --- a/core/BUILD.bazel +++ b/core/BUILD.bazel @@ -65,13 +65,12 @@ java_library( ) # Mirrors the dependencies included in the artifact on Maven Central for usage -# with maven_install's override_targets. Purposefully does not export any -# symbols, as it should only be used as a dep for pre-compiled binaries on -# Maven Central. +# with maven_install's override_targets. Should only be used as a dep for +# pre-compiled binaries on Maven Central. java_library( name = "core_maven", visibility = ["//visibility:public"], - runtime_deps = [ + exports = [ ":inprocess", ":internal", ":util", diff --git a/netty/BUILD.bazel b/netty/BUILD.bazel index c1768b61e75..d2497d065ec 100644 --- a/netty/BUILD.bazel +++ b/netty/BUILD.bazel @@ -20,20 +20,21 @@ java_library( "@io_netty_netty_codec_http2//jar", "@io_netty_netty_codec_socks//jar", "@io_netty_netty_common//jar", - "@io_netty_netty_transport_native_unix_common//jar", "@io_netty_netty_handler//jar", "@io_netty_netty_handler_proxy//jar", "@io_netty_netty_resolver//jar", "@io_netty_netty_transport//jar", + "@io_netty_netty_transport_native_unix_common//jar", "@io_perfmark_perfmark_api//jar", ], ) # Mirrors the dependencies included in the artifact on Maven Central for usage -# with maven_install's override_targets. Purposefully does not export any -# symbols, as it should only be used as a dep for pre-compiled binaries on -# Maven Central. Not actually shaded; libraries should not be referencing -# unstable APIs so there should not be any references to the shaded package. +# with maven_install's override_targets. Should only be used as a dep for +# pre-compiled binaries on Maven Central. +# +# Not actually shaded; libraries should not be referencing unstable APIs so +# there should not be any references to the shaded package. java_library( name = "shaded_maven", visibility = ["//visibility:public"], diff --git a/services/BUILD.bazel b/services/BUILD.bazel index 2854b666ba1..f8cc6ad7620 100644 --- a/services/BUILD.bazel +++ b/services/BUILD.bazel @@ -3,12 +3,11 @@ load("//:java_grpc_library.bzl", "java_grpc_library") package(default_visibility = ["//visibility:public"]) # Mirrors the dependencies included in the artifact on Maven Central for usage -# with maven_install's override_targets. Purposefully does not export any -# symbols, as it should only be used as a dep for pre-compiled binaries on -# Maven Central. +# with maven_install's override_targets. Should only be used as a dep for +# pre-compiled binaries on Maven Central. java_library( name = "services_maven", - runtime_deps = [ + exports = [ ":admin", ":binarylog", ":channelz", diff --git a/xds/BUILD.bazel b/xds/BUILD.bazel index 6e228e636be..e62b183f9e8 100644 --- a/xds/BUILD.bazel +++ b/xds/BUILD.bazel @@ -1,13 +1,12 @@ load("//:java_grpc_library.bzl", "java_grpc_library") # Mirrors the dependencies included in the artifact on Maven Central for usage -# with maven_install's override_targets. Purposefully does not export any -# symbols, as it should only be used as a dep for pre-compiled binaries on -# Maven Central. +# with maven_install's override_targets. Should only be used as a dep for +# pre-compiled binaries on Maven Central. java_library( name = "xds_maven", visibility = ["//visibility:public"], - runtime_deps = [ + exports = [ ":orca", ":xds", ], From 142078f1703696087d55af27ef63ec6d3e6b5b07 Mon Sep 17 00:00:00 2001 From: Larry Safran <107004254+larry-safran@users.noreply.github.com> Date: Tue, 10 Jan 2023 18:19:31 +0000 Subject: [PATCH 37/39] Upgrade protobuf plugin version to 0.8.19. (#9801) --- README.md | 4 ++-- examples/android/clientcache/build.gradle | 2 +- examples/android/helloworld/build.gradle | 2 +- examples/android/routeguide/build.gradle | 2 +- examples/android/strictmode/build.gradle | 2 +- examples/build.gradle | 2 +- examples/example-alts/build.gradle | 2 +- examples/example-gauth/build.gradle | 2 +- examples/example-hostname/build.gradle | 2 +- examples/example-jwt-auth/build.gradle | 2 +- examples/example-orca/build.gradle | 2 +- examples/example-tls/build.gradle | 2 +- examples/example-xds/build.gradle | 2 +- 13 files changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 23109dc0c6d..d86c9bee521 100644 --- a/README.md +++ b/README.md @@ -148,7 +148,7 @@ For non-Android protobuf-based codegen integrated with the Gradle build system, you can use [protobuf-gradle-plugin][]: ```gradle plugins { - id 'com.google.protobuf' version '0.8.18' + id 'com.google.protobuf' version '0.8.19' } protobuf { @@ -181,7 +181,7 @@ use protobuf-gradle-plugin but specify the 'lite' options: ```gradle plugins { - id 'com.google.protobuf' version '0.8.18' + id 'com.google.protobuf' version '0.8.19' } protobuf { diff --git a/examples/android/clientcache/build.gradle b/examples/android/clientcache/build.gradle index 8a94a30191e..d033a64046d 100644 --- a/examples/android/clientcache/build.gradle +++ b/examples/android/clientcache/build.gradle @@ -7,7 +7,7 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:4.2.0' - classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.18" + classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.19" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/examples/android/helloworld/build.gradle b/examples/android/helloworld/build.gradle index 8a94a30191e..d033a64046d 100644 --- a/examples/android/helloworld/build.gradle +++ b/examples/android/helloworld/build.gradle @@ -7,7 +7,7 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:4.2.0' - classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.18" + classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.19" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/examples/android/routeguide/build.gradle b/examples/android/routeguide/build.gradle index b1083bb867a..7a37b9c0648 100644 --- a/examples/android/routeguide/build.gradle +++ b/examples/android/routeguide/build.gradle @@ -7,7 +7,7 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:4.2.0' - classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.18" + classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.19" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/examples/android/strictmode/build.gradle b/examples/android/strictmode/build.gradle index 8a94a30191e..d033a64046d 100644 --- a/examples/android/strictmode/build.gradle +++ b/examples/android/strictmode/build.gradle @@ -7,7 +7,7 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:4.2.0' - classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.18" + classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.19" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/examples/build.gradle b/examples/build.gradle index 79ab93a242f..64265732216 100644 --- a/examples/build.gradle +++ b/examples/build.gradle @@ -2,7 +2,7 @@ plugins { // Provide convenience executables for trying out the examples. id 'application' // ASSUMES GRADLE 5.6 OR HIGHER. Use plugin version 0.8.10 with earlier gradle versions - id 'com.google.protobuf' version '0.8.18' + id 'com.google.protobuf' version '0.8.19' // Generate IntelliJ IDEA's .idea & .iml project files id 'idea' } diff --git a/examples/example-alts/build.gradle b/examples/example-alts/build.gradle index 17696edafc8..38588e5ba6e 100644 --- a/examples/example-alts/build.gradle +++ b/examples/example-alts/build.gradle @@ -2,7 +2,7 @@ plugins { // Provide convenience executables for trying out the examples. id 'application' // ASSUMES GRADLE 5.6 OR HIGHER. Use plugin version 0.8.10 with earlier gradle versions - id 'com.google.protobuf' version '0.8.17' + id 'com.google.protobuf' version '0.8.19' // Generate IntelliJ IDEA's .idea & .iml project files id 'idea' } diff --git a/examples/example-gauth/build.gradle b/examples/example-gauth/build.gradle index 65a44069368..51d24f5f540 100644 --- a/examples/example-gauth/build.gradle +++ b/examples/example-gauth/build.gradle @@ -2,7 +2,7 @@ plugins { // Provide convenience executables for trying out the examples. id 'application' // ASSUMES GRADLE 5.6 OR HIGHER. Use plugin version 0.8.10 with earlier gradle versions - id 'com.google.protobuf' version '0.8.17' + id 'com.google.protobuf' version '0.8.19' // Generate IntelliJ IDEA's .idea & .iml project files id 'idea' } diff --git a/examples/example-hostname/build.gradle b/examples/example-hostname/build.gradle index 52612623673..d78c3847db0 100644 --- a/examples/example-hostname/build.gradle +++ b/examples/example-hostname/build.gradle @@ -2,7 +2,7 @@ plugins { id 'application' // Provide convenience executables for trying out the examples. id 'java' - id "com.google.protobuf" version "0.8.17" + id "com.google.protobuf" version "0.8.19" id 'com.google.cloud.tools.jib' version '3.1.4' // For releasing to Docker Hub } diff --git a/examples/example-jwt-auth/build.gradle b/examples/example-jwt-auth/build.gradle index 6493238c7be..f013b0668b5 100644 --- a/examples/example-jwt-auth/build.gradle +++ b/examples/example-jwt-auth/build.gradle @@ -2,7 +2,7 @@ plugins { // Provide convenience executables for trying out the examples. id 'application' // ASSUMES GRADLE 5.6 OR HIGHER. Use plugin version 0.8.10 with earlier gradle versions - id 'com.google.protobuf' version '0.8.17' + id 'com.google.protobuf' version '0.8.19' // Generate IntelliJ IDEA's .idea & .iml project files id 'idea' } diff --git a/examples/example-orca/build.gradle b/examples/example-orca/build.gradle index abd9201a26c..cdf8f1f05ba 100644 --- a/examples/example-orca/build.gradle +++ b/examples/example-orca/build.gradle @@ -1,7 +1,7 @@ plugins { id 'application' // Provide convenience executables for trying out the examples. // ASSUMES GRADLE 5.6 OR HIGHER. Use plugin version 0.8.10 with earlier gradle versions - id 'com.google.protobuf' version '0.8.17' + id 'com.google.protobuf' version '0.8.19' // Generate IntelliJ IDEA's .idea & .iml project files id 'idea' id 'java' diff --git a/examples/example-tls/build.gradle b/examples/example-tls/build.gradle index 0181e802598..bd9b615a11f 100644 --- a/examples/example-tls/build.gradle +++ b/examples/example-tls/build.gradle @@ -2,7 +2,7 @@ plugins { // Provide convenience executables for trying out the examples. id 'application' // ASSUMES GRADLE 5.6 OR HIGHER. Use plugin version 0.8.10 with earlier gradle versions - id 'com.google.protobuf' version '0.8.17' + id 'com.google.protobuf' version '0.8.19' // Generate IntelliJ IDEA's .idea & .iml project files id 'idea' } diff --git a/examples/example-xds/build.gradle b/examples/example-xds/build.gradle index cc89381fa9d..78d7fbb7408 100644 --- a/examples/example-xds/build.gradle +++ b/examples/example-xds/build.gradle @@ -1,7 +1,7 @@ plugins { id 'application' // Provide convenience executables for trying out the examples. // ASSUMES GRADLE 5.6 OR HIGHER. Use plugin version 0.8.10 with earlier gradle versions - id 'com.google.protobuf' version '0.8.17' + id 'com.google.protobuf' version '0.8.19' // Generate IntelliJ IDEA's .idea & .iml project files id 'idea' id 'java' From c450431bb05b7638bad5dbffdaa3fe7750a27024 Mon Sep 17 00:00:00 2001 From: larry-safran Date: Tue, 10 Jan 2023 13:08:26 -0800 Subject: [PATCH 38/39] Update README etc to reference 1.52.0 --- README.md | 30 ++++++++++++------------ cronet/README.md | 2 +- documentation/android-channel-builder.md | 4 ++-- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index d86c9bee521..6761e9fc741 100644 --- a/README.md +++ b/README.md @@ -44,8 +44,8 @@ For a guided tour, take a look at the [quick start guide](https://grpc.io/docs/languages/java/quickstart) or the more explanatory [gRPC basics](https://grpc.io/docs/languages/java/basics). -The [examples](https://github.com/grpc/grpc-java/tree/v1.51.0/examples) and the -[Android example](https://github.com/grpc/grpc-java/tree/v1.51.0/examples/android) +The [examples](https://github.com/grpc/grpc-java/tree/v1.52.0/examples) and the +[Android example](https://github.com/grpc/grpc-java/tree/v1.52.0/examples/android) are standalone projects that showcase the usage of gRPC. Download @@ -56,18 +56,18 @@ Download [the JARs][]. Or for Maven with non-Android, add to your `pom.xml`: io.grpc grpc-netty-shaded - 1.51.0 + 1.52.0 runtime io.grpc grpc-protobuf - 1.51.0 + 1.52.0 io.grpc grpc-stub - 1.51.0 + 1.52.0 org.apache.tomcat @@ -79,23 +79,23 @@ Download [the JARs][]. Or for Maven with non-Android, add to your `pom.xml`: Or for Gradle with non-Android, add to your dependencies: ```gradle -runtimeOnly 'io.grpc:grpc-netty-shaded:1.51.0' -implementation 'io.grpc:grpc-protobuf:1.51.0' -implementation 'io.grpc:grpc-stub:1.51.0' +runtimeOnly 'io.grpc:grpc-netty-shaded:1.52.0' +implementation 'io.grpc:grpc-protobuf:1.52.0' +implementation 'io.grpc:grpc-stub:1.52.0' compileOnly 'org.apache.tomcat:annotations-api:6.0.53' // necessary for Java 9+ ``` For Android client, use `grpc-okhttp` instead of `grpc-netty-shaded` and `grpc-protobuf-lite` instead of `grpc-protobuf`: ```gradle -implementation 'io.grpc:grpc-okhttp:1.51.0' -implementation 'io.grpc:grpc-protobuf-lite:1.51.0' -implementation 'io.grpc:grpc-stub:1.51.0' +implementation 'io.grpc:grpc-okhttp:1.52.0' +implementation 'io.grpc:grpc-protobuf-lite:1.52.0' +implementation 'io.grpc:grpc-stub:1.52.0' compileOnly 'org.apache.tomcat:annotations-api:6.0.53' // necessary for Java 9+ ``` [the JARs]: -https://search.maven.org/search?q=g:io.grpc%20AND%20v:1.51.0 +https://search.maven.org/search?q=g:io.grpc%20AND%20v:1.52.0 Development snapshots are available in [Sonatypes's snapshot repository](https://oss.sonatype.org/content/repositories/snapshots/). @@ -127,7 +127,7 @@ For protobuf-based codegen integrated with the Maven build system, you can use com.google.protobuf:protoc:3.21.7:exe:${os.detected.classifier} grpc-java - io.grpc:protoc-gen-grpc-java:1.51.0:exe:${os.detected.classifier} + io.grpc:protoc-gen-grpc-java:1.52.0:exe:${os.detected.classifier} @@ -157,7 +157,7 @@ protobuf { } plugins { grpc { - artifact = 'io.grpc:protoc-gen-grpc-java:1.51.0' + artifact = 'io.grpc:protoc-gen-grpc-java:1.52.0' } } generateProtoTasks { @@ -190,7 +190,7 @@ protobuf { } plugins { grpc { - artifact = 'io.grpc:protoc-gen-grpc-java:1.51.0' + artifact = 'io.grpc:protoc-gen-grpc-java:1.52.0' } } generateProtoTasks { diff --git a/cronet/README.md b/cronet/README.md index b29d19c99b6..1b4be783faf 100644 --- a/cronet/README.md +++ b/cronet/README.md @@ -26,7 +26,7 @@ In your app module's `build.gradle` file, include a dependency on both `grpc-cro Google Play Services Client Library for Cronet ``` -implementation 'io.grpc:grpc-cronet:1.51.0' +implementation 'io.grpc:grpc-cronet:1.52.0' implementation 'com.google.android.gms:play-services-cronet:16.0.0' ``` diff --git a/documentation/android-channel-builder.md b/documentation/android-channel-builder.md index 82bfff47e91..24c1e3890d8 100644 --- a/documentation/android-channel-builder.md +++ b/documentation/android-channel-builder.md @@ -36,8 +36,8 @@ In your `build.gradle` file, include a dependency on both `grpc-android` and `grpc-okhttp`: ``` -implementation 'io.grpc:grpc-android:1.51.0' -implementation 'io.grpc:grpc-okhttp:1.51.0' +implementation 'io.grpc:grpc-android:1.52.0' +implementation 'io.grpc:grpc-okhttp:1.52.0' ``` You also need permission to access the device's network state in your From a1a6d4f35c31b18a35d0b7c2bfb4155093128b86 Mon Sep 17 00:00:00 2001 From: larry-safran Date: Tue, 10 Jan 2023 13:15:07 -0800 Subject: [PATCH 39/39] Bump version to 1.52.0 --- build.gradle | 2 +- .../src/test/golden/TestDeprecatedService.java.txt | 2 +- compiler/src/test/golden/TestService.java.txt | 2 +- .../src/testLite/golden/TestDeprecatedService.java.txt | 2 +- compiler/src/testLite/golden/TestService.java.txt | 2 +- core/src/main/java/io/grpc/internal/GrpcUtil.java | 2 +- examples/android/clientcache/app/build.gradle | 10 +++++----- examples/android/helloworld/app/build.gradle | 8 ++++---- examples/android/routeguide/app/build.gradle | 8 ++++---- examples/android/strictmode/app/build.gradle | 8 ++++---- examples/build.gradle | 2 +- examples/example-alts/build.gradle | 2 +- examples/example-gauth/build.gradle | 2 +- examples/example-gauth/pom.xml | 4 ++-- examples/example-hostname/build.gradle | 2 +- examples/example-hostname/pom.xml | 4 ++-- examples/example-jwt-auth/build.gradle | 2 +- examples/example-jwt-auth/pom.xml | 4 ++-- examples/example-orca/build.gradle | 2 +- examples/example-tls/build.gradle | 2 +- examples/example-tls/pom.xml | 4 ++-- examples/example-xds/build.gradle | 2 +- examples/pom.xml | 4 ++-- 23 files changed, 41 insertions(+), 41 deletions(-) diff --git a/build.gradle b/build.gradle index 8ae24adbdb8..04ab724a2e3 100644 --- a/build.gradle +++ b/build.gradle @@ -20,7 +20,7 @@ subprojects { apply plugin: "net.ltgt.errorprone" group = "io.grpc" - version = "1.52.0-SNAPSHOT" // CURRENT_GRPC_VERSION + version = "1.52.0" // CURRENT_GRPC_VERSION repositories { maven { // The google mirror is less flaky than mavenCentral() diff --git a/compiler/src/test/golden/TestDeprecatedService.java.txt b/compiler/src/test/golden/TestDeprecatedService.java.txt index b3ca789493e..8b541b7c3f0 100644 --- a/compiler/src/test/golden/TestDeprecatedService.java.txt +++ b/compiler/src/test/golden/TestDeprecatedService.java.txt @@ -8,7 +8,7 @@ import static io.grpc.MethodDescriptor.generateFullMethodName; * */ @javax.annotation.Generated( - value = "by gRPC proto compiler (version 1.52.0-SNAPSHOT)", + value = "by gRPC proto compiler (version 1.52.0)", comments = "Source: grpc/testing/compiler/test.proto") @io.grpc.stub.annotations.GrpcGenerated @java.lang.Deprecated diff --git a/compiler/src/test/golden/TestService.java.txt b/compiler/src/test/golden/TestService.java.txt index 6ccfb179592..9ef5e4a0327 100644 --- a/compiler/src/test/golden/TestService.java.txt +++ b/compiler/src/test/golden/TestService.java.txt @@ -8,7 +8,7 @@ import static io.grpc.MethodDescriptor.generateFullMethodName; * */ @javax.annotation.Generated( - value = "by gRPC proto compiler (version 1.52.0-SNAPSHOT)", + value = "by gRPC proto compiler (version 1.52.0)", comments = "Source: grpc/testing/compiler/test.proto") @io.grpc.stub.annotations.GrpcGenerated public final class TestServiceGrpc { diff --git a/compiler/src/testLite/golden/TestDeprecatedService.java.txt b/compiler/src/testLite/golden/TestDeprecatedService.java.txt index a6b7dac6dfc..2a9f951e913 100644 --- a/compiler/src/testLite/golden/TestDeprecatedService.java.txt +++ b/compiler/src/testLite/golden/TestDeprecatedService.java.txt @@ -8,7 +8,7 @@ import static io.grpc.MethodDescriptor.generateFullMethodName; * */ @javax.annotation.Generated( - value = "by gRPC proto compiler (version 1.52.0-SNAPSHOT)", + value = "by gRPC proto compiler (version 1.52.0)", comments = "Source: grpc/testing/compiler/test.proto") @io.grpc.stub.annotations.GrpcGenerated @java.lang.Deprecated diff --git a/compiler/src/testLite/golden/TestService.java.txt b/compiler/src/testLite/golden/TestService.java.txt index abdd0a4751c..d5495156c4d 100644 --- a/compiler/src/testLite/golden/TestService.java.txt +++ b/compiler/src/testLite/golden/TestService.java.txt @@ -8,7 +8,7 @@ import static io.grpc.MethodDescriptor.generateFullMethodName; * */ @javax.annotation.Generated( - value = "by gRPC proto compiler (version 1.52.0-SNAPSHOT)", + value = "by gRPC proto compiler (version 1.52.0)", comments = "Source: grpc/testing/compiler/test.proto") @io.grpc.stub.annotations.GrpcGenerated public final class TestServiceGrpc { diff --git a/core/src/main/java/io/grpc/internal/GrpcUtil.java b/core/src/main/java/io/grpc/internal/GrpcUtil.java index dc96a880b11..3d3677eb134 100644 --- a/core/src/main/java/io/grpc/internal/GrpcUtil.java +++ b/core/src/main/java/io/grpc/internal/GrpcUtil.java @@ -217,7 +217,7 @@ public byte[] parseAsciiString(byte[] serialized) { public static final Splitter ACCEPT_ENCODING_SPLITTER = Splitter.on(',').trimResults(); - private static final String IMPLEMENTATION_VERSION = "1.52.0-SNAPSHOT"; // CURRENT_GRPC_VERSION + private static final String IMPLEMENTATION_VERSION = "1.52.0"; // CURRENT_GRPC_VERSION /** * The default timeout in nanos for a keepalive ping request. diff --git a/examples/android/clientcache/app/build.gradle b/examples/android/clientcache/app/build.gradle index 50317384e10..502b34a8310 100644 --- a/examples/android/clientcache/app/build.gradle +++ b/examples/android/clientcache/app/build.gradle @@ -34,7 +34,7 @@ android { protobuf { protoc { artifact = 'com.google.protobuf:protoc:3.21.7' } plugins { - grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION + grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.52.0' // CURRENT_GRPC_VERSION } } generateProtoTasks { @@ -54,12 +54,12 @@ dependencies { implementation 'com.android.support:appcompat-v7:27.0.2' // You need to build grpc-java to obtain these libraries below. - implementation 'io.grpc:grpc-okhttp:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-protobuf-lite:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-stub:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-okhttp:1.52.0' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-protobuf-lite:1.52.0' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-stub:1.52.0' // CURRENT_GRPC_VERSION implementation 'org.apache.tomcat:annotations-api:6.0.53' testImplementation 'junit:junit:4.12' testImplementation 'com.google.truth:truth:1.0.1' - testImplementation 'io.grpc:grpc-testing:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION + testImplementation 'io.grpc:grpc-testing:1.52.0' // CURRENT_GRPC_VERSION } diff --git a/examples/android/helloworld/app/build.gradle b/examples/android/helloworld/app/build.gradle index a7af5710c85..93adc585e6b 100644 --- a/examples/android/helloworld/app/build.gradle +++ b/examples/android/helloworld/app/build.gradle @@ -32,7 +32,7 @@ android { protobuf { protoc { artifact = 'com.google.protobuf:protoc:3.21.7' } plugins { - grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION + grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.52.0' // CURRENT_GRPC_VERSION } } generateProtoTasks { @@ -52,8 +52,8 @@ dependencies { implementation 'com.android.support:appcompat-v7:27.0.2' // You need to build grpc-java to obtain these libraries below. - implementation 'io.grpc:grpc-okhttp:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-protobuf-lite:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-stub:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-okhttp:1.52.0' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-protobuf-lite:1.52.0' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-stub:1.52.0' // CURRENT_GRPC_VERSION implementation 'org.apache.tomcat:annotations-api:6.0.53' } diff --git a/examples/android/routeguide/app/build.gradle b/examples/android/routeguide/app/build.gradle index 45ecf397124..91c8ad658c7 100644 --- a/examples/android/routeguide/app/build.gradle +++ b/examples/android/routeguide/app/build.gradle @@ -32,7 +32,7 @@ android { protobuf { protoc { artifact = 'com.google.protobuf:protoc:3.21.7' } plugins { - grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION + grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.52.0' // CURRENT_GRPC_VERSION } } generateProtoTasks { @@ -52,8 +52,8 @@ dependencies { implementation 'com.android.support:appcompat-v7:27.0.2' // You need to build grpc-java to obtain these libraries below. - implementation 'io.grpc:grpc-okhttp:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-protobuf-lite:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-stub:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-okhttp:1.52.0' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-protobuf-lite:1.52.0' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-stub:1.52.0' // CURRENT_GRPC_VERSION implementation 'org.apache.tomcat:annotations-api:6.0.53' } diff --git a/examples/android/strictmode/app/build.gradle b/examples/android/strictmode/app/build.gradle index cb08cc3454d..e77f7c8fdbe 100644 --- a/examples/android/strictmode/app/build.gradle +++ b/examples/android/strictmode/app/build.gradle @@ -33,7 +33,7 @@ android { protobuf { protoc { artifact = 'com.google.protobuf:protoc:3.21.7' } plugins { - grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION + grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.52.0' // CURRENT_GRPC_VERSION } } generateProtoTasks { @@ -53,8 +53,8 @@ dependencies { implementation 'com.android.support:appcompat-v7:28.0.0' // You need to build grpc-java to obtain these libraries below. - implementation 'io.grpc:grpc-okhttp:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-protobuf-lite:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-stub:1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-okhttp:1.52.0' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-protobuf-lite:1.52.0' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-stub:1.52.0' // CURRENT_GRPC_VERSION implementation 'org.apache.tomcat:annotations-api:6.0.53' } diff --git a/examples/build.gradle b/examples/build.gradle index 64265732216..4b80e67f607 100644 --- a/examples/build.gradle +++ b/examples/build.gradle @@ -22,7 +22,7 @@ targetCompatibility = 1.8 // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.52.0' // CURRENT_GRPC_VERSION def protobufVersion = '3.21.7' def protocVersion = protobufVersion diff --git a/examples/example-alts/build.gradle b/examples/example-alts/build.gradle index 38588e5ba6e..0fc499d3d99 100644 --- a/examples/example-alts/build.gradle +++ b/examples/example-alts/build.gradle @@ -23,7 +23,7 @@ targetCompatibility = 1.8 // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.52.0' // CURRENT_GRPC_VERSION def protocVersion = '3.21.7' dependencies { diff --git a/examples/example-gauth/build.gradle b/examples/example-gauth/build.gradle index 51d24f5f540..2da074f4f38 100644 --- a/examples/example-gauth/build.gradle +++ b/examples/example-gauth/build.gradle @@ -23,7 +23,7 @@ targetCompatibility = 1.8 // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.52.0' // CURRENT_GRPC_VERSION def protobufVersion = '3.21.7' def protocVersion = protobufVersion diff --git a/examples/example-gauth/pom.xml b/examples/example-gauth/pom.xml index fbda89ee251..2cd72aa6ef7 100644 --- a/examples/example-gauth/pom.xml +++ b/examples/example-gauth/pom.xml @@ -6,13 +6,13 @@ jar - 1.52.0-SNAPSHOT + 1.52.0 example-gauth https://github.com/grpc/grpc-java UTF-8 - 1.52.0-SNAPSHOT + 1.52.0 3.21.7 1.7 diff --git a/examples/example-hostname/build.gradle b/examples/example-hostname/build.gradle index d78c3847db0..f02b30af04e 100644 --- a/examples/example-hostname/build.gradle +++ b/examples/example-hostname/build.gradle @@ -21,7 +21,7 @@ targetCompatibility = 1.8 // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.52.0' // CURRENT_GRPC_VERSION def protobufVersion = '3.21.7' dependencies { diff --git a/examples/example-hostname/pom.xml b/examples/example-hostname/pom.xml index 224a8a99c41..b6384fad254 100644 --- a/examples/example-hostname/pom.xml +++ b/examples/example-hostname/pom.xml @@ -6,13 +6,13 @@ jar - 1.52.0-SNAPSHOT + 1.52.0 example-hostname https://github.com/grpc/grpc-java UTF-8 - 1.52.0-SNAPSHOT + 1.52.0 3.21.7 1.7 diff --git a/examples/example-jwt-auth/build.gradle b/examples/example-jwt-auth/build.gradle index f013b0668b5..f2373fa4b65 100644 --- a/examples/example-jwt-auth/build.gradle +++ b/examples/example-jwt-auth/build.gradle @@ -22,7 +22,7 @@ targetCompatibility = 1.8 // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.52.0' // CURRENT_GRPC_VERSION def protobufVersion = '3.21.7' def protocVersion = protobufVersion diff --git a/examples/example-jwt-auth/pom.xml b/examples/example-jwt-auth/pom.xml index 6bd4c0331d1..4b3abec4ec2 100644 --- a/examples/example-jwt-auth/pom.xml +++ b/examples/example-jwt-auth/pom.xml @@ -7,13 +7,13 @@ jar - 1.52.0-SNAPSHOT + 1.52.0 example-jwt-auth https://github.com/grpc/grpc-java UTF-8 - 1.52.0-SNAPSHOT + 1.52.0 3.21.7 3.21.7 diff --git a/examples/example-orca/build.gradle b/examples/example-orca/build.gradle index cdf8f1f05ba..8b247c4b37f 100644 --- a/examples/example-orca/build.gradle +++ b/examples/example-orca/build.gradle @@ -17,7 +17,7 @@ repositories { sourceCompatibility = 1.8 targetCompatibility = 1.8 -def grpcVersion = '1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.52.0' // CURRENT_GRPC_VERSION def protocVersion = '3.21.7' dependencies { diff --git a/examples/example-tls/build.gradle b/examples/example-tls/build.gradle index bd9b615a11f..76940b9a95d 100644 --- a/examples/example-tls/build.gradle +++ b/examples/example-tls/build.gradle @@ -23,7 +23,7 @@ targetCompatibility = 1.8 // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.52.0' // CURRENT_GRPC_VERSION def protocVersion = '3.21.7' dependencies { diff --git a/examples/example-tls/pom.xml b/examples/example-tls/pom.xml index ea87202b57e..de9d8b4ae3c 100644 --- a/examples/example-tls/pom.xml +++ b/examples/example-tls/pom.xml @@ -6,13 +6,13 @@ jar - 1.52.0-SNAPSHOT + 1.52.0 example-tls https://github.com/grpc/grpc-java UTF-8 - 1.52.0-SNAPSHOT + 1.52.0 3.21.7 2.0.54.Final diff --git a/examples/example-xds/build.gradle b/examples/example-xds/build.gradle index 78d7fbb7408..14c8dd1e89e 100644 --- a/examples/example-xds/build.gradle +++ b/examples/example-xds/build.gradle @@ -22,7 +22,7 @@ targetCompatibility = 1.8 // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.52.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.52.0' // CURRENT_GRPC_VERSION def nettyTcNativeVersion = '2.0.31.Final' def protocVersion = '3.21.7' diff --git a/examples/pom.xml b/examples/pom.xml index 9e57a781612..e90c527d7fa 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -6,13 +6,13 @@ jar - 1.52.0-SNAPSHOT + 1.52.0 examples https://github.com/grpc/grpc-java UTF-8 - 1.52.0-SNAPSHOT + 1.52.0 3.21.7 3.21.7

Homepage: