Don't use reflection for epoll/unix domain sockets

The classes are available, even on Windows. Trying to use them though
won't work. You'll get an error like:
java.lang.UnsatisfiedLinkError: no netty-transport-native-epoll in java.library.path
This commit is contained in:
Eric Anderson 2015-05-21 11:54:04 -07:00
parent 3af3d1bee3
commit 65d73c0dc2
3 changed files with 44 additions and 54 deletions

View File

@ -39,12 +39,9 @@ dependencies {
project(':grpc-interop-testing'), project(':grpc-interop-testing'),
libraries.junit, libraries.junit,
libraries.mockito, libraries.mockito,
libraries.hdrhistogram libraries.hdrhistogram,
if (osdetector.os == "linux") { libraries.netty_tcnative,
// These are only available on linux. libraries.netty_transport_native_epoll
compile libraries.netty_tcnative,
libraries.netty_transport_native_epoll
}
alpnboot alpnboot_package_name alpnboot alpnboot_package_name
} }

View File

@ -44,8 +44,12 @@ import io.grpc.transport.netty.NegotiationType;
import io.grpc.transport.netty.NettyChannelBuilder; import io.grpc.transport.netty.NettyChannelBuilder;
import io.grpc.transport.okhttp.OkHttpChannelBuilder; import io.grpc.transport.okhttp.OkHttpChannelBuilder;
import io.netty.channel.EventLoopGroup; import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.EpollDomainSocketChannel;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.channel.unix.DomainSocketAddress;
import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslProvider; import io.netty.handler.ssl.SslProvider;
@ -79,24 +83,22 @@ final class Utils {
static SocketAddress parseSocketAddress(String value) { static SocketAddress parseSocketAddress(String value) {
if (value.startsWith(UNIX_DOMAIN_SOCKET_PREFIX)) { if (value.startsWith(UNIX_DOMAIN_SOCKET_PREFIX)) {
// Unix Domain Socket address. // Unix Domain Socket address.
// Create the underlying file for the Unix Domain Socket.
String filePath = value.substring(UNIX_DOMAIN_SOCKET_PREFIX.length());
File file = new File(filePath);
if (!file.isAbsolute()) {
throw new IllegalArgumentException("File path must be absolute: " + filePath);
}
try { try {
// Create the underlying file for the Unix Domain Socket.
String filePath = value.substring(UNIX_DOMAIN_SOCKET_PREFIX.length());
File file = new File(filePath);
if (!file.isAbsolute()) {
throw new IllegalArgumentException("File path must be absolute: " + filePath);
}
if (file.createNewFile()) { if (file.createNewFile()) {
// If this application created the file, delete it when the application exits. // If this application created the file, delete it when the application exits.
file.deleteOnExit(); file.deleteOnExit();
} }
// Create the SocketAddress referencing the file. } catch (IOException ex) {
Class<?> addressClass = Class.forName("io.netty.channel.unix.DomainSocketAddress"); throw new RuntimeException(ex);
return (SocketAddress) addressClass.getDeclaredConstructor(File.class)
.newInstance(file);
} catch (Exception e) {
throw new RuntimeException(e);
} }
// Create the SocketAddress referencing the file.
return new DomainSocketAddress(file);
} else { } else {
// Standard TCP/IP address. // Standard TCP/IP address.
String[] parts = value.split(":", 2); String[] parts = value.split(":", 2);
@ -146,45 +148,26 @@ final class Utils {
final EventLoopGroup group; final EventLoopGroup group;
final Class<? extends io.netty.channel.Channel> channelType; final Class<? extends io.netty.channel.Channel> channelType;
switch (config.transport) { switch (config.transport) {
case NETTY_NIO: { case NETTY_NIO:
group = new NioEventLoopGroup(); group = new NioEventLoopGroup();
channelType = NioSocketChannel.class; channelType = NioSocketChannel.class;
break; break;
}
case NETTY_EPOLL: { case NETTY_EPOLL:
try { // These classes only work on Linux.
// These classes are only available on linux. group = new EpollEventLoopGroup();
Class<?> groupClass = Class.forName("io.netty.channel.epoll.EpollEventLoopGroup"); channelType = EpollSocketChannel.class;
@SuppressWarnings("unchecked") break;
Class<? extends io.netty.channel.Channel> channelClass =
(Class<? extends io.netty.channel.Channel>) Class.forName( case NETTY_UNIX_DOMAIN_SOCKET:
"io.netty.channel.epoll.EpollSocketChannel"); // These classes only work on Linux.
group = (EventLoopGroup) groupClass.newInstance(); group = new EpollEventLoopGroup();
channelType = channelClass; channelType = EpollDomainSocketChannel.class;
break; break;
} catch (Exception e) {
throw new RuntimeException(e); default:
}
}
case NETTY_UNIX_DOMAIN_SOCKET: {
try {
// These classes are only available on linux.
Class<?> groupClass = Class.forName("io.netty.channel.epoll.EpollEventLoopGroup");
@SuppressWarnings("unchecked")
Class<? extends io.netty.channel.Channel> channelClass =
(Class<? extends io.netty.channel.Channel>) Class.forName(
"io.netty.channel.epoll.EpollDomainSocketChannel");
group = (EventLoopGroup) groupClass.newInstance();
channelType = channelClass;
break;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
default: {
// Should never get here. // Should never get here.
throw new IllegalArgumentException("Unsupported transport: " + config.transport); throw new IllegalArgumentException("Unsupported transport: " + config.transport);
}
} }
return NettyChannelBuilder return NettyChannelBuilder
.forAddress(config.address) .forAddress(config.address)

View File

@ -93,6 +93,16 @@ subprojects {
} }
} }
def tcnative_suffix = "";
if (osdetector.classifier in ["linux-x86_64", "osx-x86_64", "windows-x86_64"]) {
// The native code is only pre-compiled on certain platforms.
tcnative_suffix = ":" + osdetector.classifier
}
def epoll_suffix = "";
if (osdetector.classifier in ["linux-x86_64"]) {
// The native code is only pre-compiled on certain platforms.
epoll_suffix = ":" + osdetector.classifier
}
libraries = [ libraries = [
guava: 'com.google.guava:guava:18.0', guava: 'com.google.guava:guava:18.0',
// used to collect benchmark results // used to collect benchmark results
@ -108,8 +118,8 @@ subprojects {
protobuf_plugin: 'com.google.protobuf:protobuf-gradle-plugin:0.4.1', protobuf_plugin: 'com.google.protobuf:protobuf-gradle-plugin:0.4.1',
netty: 'io.netty:netty-codec-http2:4.1.0.Beta5', netty: 'io.netty:netty-codec-http2:4.1.0.Beta5',
netty_tcnative: "io.netty:netty-tcnative:1.1.33.Fork2:${osdetector.classifier}", netty_tcnative: 'io.netty:netty-tcnative:1.1.33.Fork2' + tcnative_suffix,
netty_transport_native_epoll: "io.netty:netty-transport-native-epoll:4.1.0.Beta5:${osdetector.classifier}", netty_transport_native_epoll: 'io.netty:netty-transport-native-epoll:4.1.0.Beta5' + epoll_suffix,
// Test dependencies. // Test dependencies.
junit: 'junit:junit:4.11', junit: 'junit:junit:4.11',