Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

netty: implement UdsNameResolver and UdsNettyChannelProvider #9113

Merged
merged 11 commits into from May 2, 2022
9 changes: 5 additions & 4 deletions netty/build.gradle
Expand Up @@ -17,20 +17,21 @@ evaluationDependsOn(project(':grpc-core').path)

dependencies {
api project(':grpc-core'),
libraries.netty,
libraries.netty_epoll
libraries.netty
implementation libraries.netty_proxy_handler,
libraries.guava,
libraries.errorprone,
libraries.perfmark
libraries.perfmark,
("io.netty:netty-transport-native-epoll:${nettyVersion}")
ejona86 marked this conversation as resolved.
Show resolved Hide resolved

// Tests depend on base class defined by core module.
testImplementation project(':grpc-core').sourceSets.test.output,
project(':grpc-api').sourceSets.test.output,
project(':grpc-testing'),
project(':grpc-testing-proto')
testRuntimeOnly libraries.netty_tcnative,
libraries.conscrypt
libraries.conscrypt,
libraries.netty_epoll
signature "org.codehaus.mojo.signature:java17:1.0@signature"
alpnagent libraries.jetty_alpn_agent
}
Expand Down
Expand Up @@ -22,7 +22,6 @@
import io.grpc.Internal;
import io.grpc.ManagedChannelProvider;
import io.grpc.internal.SharedResourcePool;
import io.netty.channel.epoll.EpollDomainSocketChannel;
import io.netty.channel.unix.DomainSocketAddress;
import java.net.SocketAddress;
import java.net.URI;
Expand Down Expand Up @@ -80,7 +79,7 @@ private static NettyChannelBuilder getNettyChannelBuilder(
builder =
builder
.eventLoopGroupPool(SharedResourcePool.forResource(Utils.UDS_CHANNELS_EVENT_LOOP_GROUP))
.channelType(EpollDomainSocketChannel.class);
.channelType(Utils.EPOLL_DOMAIN_CLIENT_CHANNEL_TYPE);
return builder;
}

Expand Down
17 changes: 15 additions & 2 deletions netty/src/main/java/io/grpc/netty/Utils.java
Expand Up @@ -44,7 +44,6 @@
import io.netty.channel.EventLoopGroup;
import io.netty.channel.ReflectiveChannelFactory;
import io.netty.channel.ServerChannel;
import io.netty.channel.epoll.Epoll;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
Expand Down Expand Up @@ -91,7 +90,7 @@ class Utils {
public static final Resource<EventLoopGroup> NIO_WORKER_EVENT_LOOP_GROUP
= new DefaultEventLoopGroupResource(0, "grpc-nio-worker-ELG", EventLoopGroupType.NIO);
public static final Resource<EventLoopGroup> UDS_CHANNELS_EVENT_LOOP_GROUP =
Epoll.isAvailable() ? new DefaultEventLoopGroupResource(1, "UdsChannels",
isEpollAvailable() ? new DefaultEventLoopGroupResource(1, "UdsChannels",
ejona86 marked this conversation as resolved.
Show resolved Hide resolved
EventLoopGroupType.EPOLL) : null;

public static final Resource<EventLoopGroup> DEFAULT_BOSS_EVENT_LOOP_GROUP;
Expand All @@ -109,6 +108,7 @@ private static final class ByteBufAllocatorPreferHeapHolder {

public static final ChannelFactory<? extends ServerChannel> DEFAULT_SERVER_CHANNEL_FACTORY;
public static final Class<? extends Channel> DEFAULT_CLIENT_CHANNEL_TYPE;
public static final Class<? extends Channel> EPOLL_DOMAIN_CLIENT_CHANNEL_TYPE;

@Nullable
private static final Constructor<? extends EventLoopGroup> EPOLL_EVENT_LOOP_GROUP_CONSTRUCTOR;
Expand All @@ -117,6 +117,7 @@ private static final class ByteBufAllocatorPreferHeapHolder {
// Decide default channel types and EventLoopGroup based on Epoll availability
if (isEpollAvailable()) {
DEFAULT_CLIENT_CHANNEL_TYPE = epollChannelType();
EPOLL_DOMAIN_CLIENT_CHANNEL_TYPE = epollDomainSocketChannelType();
DEFAULT_SERVER_CHANNEL_FACTORY = new ReflectiveChannelFactory<>(epollServerChannelType());
EPOLL_EVENT_LOOP_GROUP_CONSTRUCTOR = epollEventLoopGroupConstructor();
DEFAULT_BOSS_EVENT_LOOP_GROUP
Expand All @@ -127,6 +128,7 @@ private static final class ByteBufAllocatorPreferHeapHolder {
logger.log(Level.FINE, "Epoll is not available, using Nio.", getEpollUnavailabilityCause());
DEFAULT_SERVER_CHANNEL_FACTORY = nioServerChannelFactory();
DEFAULT_CLIENT_CHANNEL_TYPE = NioSocketChannel.class;
EPOLL_DOMAIN_CLIENT_CHANNEL_TYPE = null;
DEFAULT_BOSS_EVENT_LOOP_GROUP = NIO_BOSS_EVENT_LOOP_GROUP;
DEFAULT_WORKER_EVENT_LOOP_GROUP = NIO_WORKER_EVENT_LOOP_GROUP;
EPOLL_EVENT_LOOP_GROUP_CONSTRUCTOR = null;
Expand Down Expand Up @@ -331,6 +333,17 @@ private static Class<? extends Channel> epollChannelType() {
}
}

// Must call when epoll is available
private static Class<? extends Channel> epollDomainSocketChannelType() {
try {
Class<? extends Channel> channelType = Class
.forName("io.netty.channel.epoll.EpollDomainSocketChannel").asSubclass(Channel.class);
return channelType;
} catch (ClassNotFoundException e) {
throw new RuntimeException("Cannot load EpollDomainSocketChannel", e);
}
}

// Must call when epoll is available
private static Constructor<? extends EventLoopGroup> epollEventLoopGroupConstructor() {
try {
Expand Down
25 changes: 20 additions & 5 deletions netty/src/test/java/io/grpc/netty/UdsNettyChannelProviderTest.java
Expand Up @@ -36,22 +36,25 @@
import io.grpc.testing.protobuf.SimpleResponse;
import io.grpc.testing.protobuf.SimpleServiceGrpc;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.Epoll;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerDomainSocketChannel;
import io.netty.channel.unix.DomainSocketAddress;
import java.io.IOException;
import org.junit.After;
import org.junit.Assume;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/** Unit tests for {@link UdsNettyChannelProvider}. */
@RunWith(JUnit4.class)
public class UdsNettyChannelProviderTest {

private static final String TEST_SOCKET = "/tmp/test.socket";
@Rule public TemporaryFolder tempFolder = new TemporaryFolder();

private static final String TEST_SOCKET = "/test.socket";
sanjaypujare marked this conversation as resolved.
Show resolved Hide resolved
@Rule
public final GrpcCleanupRule cleanupRule = new GrpcCleanupRule();

Expand All @@ -61,6 +64,16 @@ public class UdsNettyChannelProviderTest {
private EventLoopGroup elg;
sanjaypujare marked this conversation as resolved.
Show resolved Hide resolved
private EventLoopGroup boss;

@After
public void tearDown() {
if (elg != null) {
elg.shutdownGracefully();
}
if (boss != null) {
boss.shutdownGracefully();
}
}

@Test
public void provided() {
for (ManagedChannelProvider current
Expand Down Expand Up @@ -123,6 +136,7 @@ public void newChannelBuilder_badScheme() {

@Test
public void managedChannelRegistry_newChannelBuilder() {
Assume.assumeTrue(Utils.isEpollAvailable());
ManagedChannelBuilder<?> managedChannelBuilder
= Grpc.newChannelBuilder("unix:///sock.sock", InsecureChannelCredentials.create());
assertThat(managedChannelBuilder).isNotNull();
Expand All @@ -134,10 +148,11 @@ public void managedChannelRegistry_newChannelBuilder() {

@Test
public void udsClientServerTestUsingProvider() throws IOException {
Assume.assumeTrue(Epoll.isAvailable());
createUdsServer(TEST_SOCKET);
Assume.assumeTrue(Utils.isEpollAvailable());
String socketPath = tempFolder.getRoot().getAbsolutePath() + TEST_SOCKET;
createUdsServer(socketPath);
ManagedChannelBuilder<?> channelBuilder =
Grpc.newChannelBuilder("unix://" + TEST_SOCKET, InsecureChannelCredentials.create());
Grpc.newChannelBuilder("unix://" + socketPath, InsecureChannelCredentials.create());
SimpleServiceGrpc.SimpleServiceBlockingStub stub =
SimpleServiceGrpc.newBlockingStub(cleanupRule.register(channelBuilder.build()));
assertThat(unaryRpc("buddy", stub)).isEqualTo("Hello buddy");
Expand Down