13
0
geforkt von Mirrors/Velocity

Add kqueue transport support

Dieser Commit ist enthalten in:
Andrew Steinborn 2018-08-08 10:10:11 -04:00
Ursprung 512b1c2403
Commit db8b7c807c
2 geänderte Dateien mit 64 neuen und 35 gelöschten Zeilen

Datei anzeigen

@ -28,6 +28,7 @@ dependencies {
compile "io.netty:netty-handler:${nettyVersion}" compile "io.netty:netty-handler:${nettyVersion}"
compile "io.netty:netty-transport-native-epoll:${nettyVersion}" compile "io.netty:netty-transport-native-epoll:${nettyVersion}"
compile "io.netty:netty-transport-native-epoll:${nettyVersion}:linux-x86_64" compile "io.netty:netty-transport-native-epoll:${nettyVersion}:linux-x86_64"
compile "io.netty:netty-transport-native-kqueue:${nettyVersion}:osx-x86_64"
compile "org.apache.logging.log4j:log4j-api:${log4jVersion}" compile "org.apache.logging.log4j:log4j-api:${log4jVersion}"
compile "org.apache.logging.log4j:log4j-core:${log4jVersion}" compile "org.apache.logging.log4j:log4j-core:${log4jVersion}"

Datei anzeigen

@ -24,6 +24,7 @@ import io.netty.channel.epoll.EpollDatagramChannel;
import io.netty.channel.epoll.EpollEventLoopGroup; import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel; import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.epoll.EpollSocketChannel; import io.netty.channel.epoll.EpollSocketChannel;
import io.netty.channel.kqueue.*;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramChannel; import io.netty.channel.socket.DatagramChannel;
import io.netty.channel.socket.ServerSocketChannel; import io.netty.channel.socket.ServerSocketChannel;
@ -37,6 +38,7 @@ import org.apache.logging.log4j.Logger;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.HashSet; import java.util.HashSet;
import java.util.Locale;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -53,46 +55,25 @@ import static com.velocitypowered.network.Connections.READ_TIMEOUT;
public final class ConnectionManager { public final class ConnectionManager {
private static final Logger logger = LogManager.getLogger(ConnectionManager.class); private static final Logger logger = LogManager.getLogger(ConnectionManager.class);
private static final String DISABLE_EPOLL_PROPERTY = "velocity.connection.disable-epoll";
private static final boolean DISABLE_EPOLL = Boolean.getBoolean(DISABLE_EPOLL_PROPERTY);
private final Set<Channel> endpoints = new HashSet<>(); private final Set<Channel> endpoints = new HashSet<>();
private final Class<? extends ServerSocketChannel> serverSocketChannelClass; private final TransportType transportType;
private final Class<? extends SocketChannel> socketChannelClass;
private final Class<? extends DatagramChannel> datagramChannelClass;
private final EventLoopGroup bossGroup; private final EventLoopGroup bossGroup;
private final EventLoopGroup workerGroup; private final EventLoopGroup workerGroup;
public ConnectionManager() { public ConnectionManager() {
final boolean epoll = canUseEpoll(); this.transportType = TransportType.bestType();
if (epoll) { this.bossGroup = transportType.createEventLoopGroup(true);
this.serverSocketChannelClass = EpollServerSocketChannel.class; this.workerGroup = transportType.createEventLoopGroup(false);
this.socketChannelClass = EpollSocketChannel.class; this.logChannelInformation();
this.datagramChannelClass = EpollDatagramChannel.class;
this.bossGroup = new EpollEventLoopGroup(0, createThreadFactory("Netty Epoll Boss #%d"));
this.workerGroup = new EpollEventLoopGroup(0, createThreadFactory("Netty Epoll Worker #%d"));
} else {
this.serverSocketChannelClass = NioServerSocketChannel.class;
this.socketChannelClass = NioSocketChannel.class;
this.datagramChannelClass = NioDatagramChannel.class;
this.bossGroup = new NioEventLoopGroup(0, createThreadFactory("Netty Nio Boss #%d"));
this.workerGroup = new NioEventLoopGroup(0, createThreadFactory("Netty Nio Worker #%d"));
}
this.logChannelInformation(epoll);
} }
private void logChannelInformation(final boolean epoll) { private void logChannelInformation() {
final StringBuilder sb = new StringBuilder(); logger.info("Using channel type {}", transportType);
sb.append("Using channel type ");
sb.append(epoll ? "epoll": "nio");
if(DISABLE_EPOLL) {
sb.append(String.format(" - epoll explicitly disabled using -D%s=true", DISABLE_EPOLL_PROPERTY));
}
logger.info(sb.toString()); // TODO: move to logger
} }
public void bind(final InetSocketAddress address) { public void bind(final InetSocketAddress address) {
final ServerBootstrap bootstrap = new ServerBootstrap() final ServerBootstrap bootstrap = new ServerBootstrap()
.channel(this.serverSocketChannelClass) .channel(this.transportType.serverSocketChannelClass)
.group(this.bossGroup, this.workerGroup) .group(this.bossGroup, this.workerGroup)
.childHandler(new ChannelInitializer<Channel>() { .childHandler(new ChannelInitializer<Channel>() {
@Override @Override
@ -129,7 +110,7 @@ public final class ConnectionManager {
public void queryBind(final String hostname, final int port) { public void queryBind(final String hostname, final int port) {
Bootstrap bootstrap = new Bootstrap() Bootstrap bootstrap = new Bootstrap()
.channel(datagramChannelClass) .channel(transportType.datagramChannelClass)
.group(this.workerGroup) .group(this.workerGroup)
.handler(new GS4QueryHandler()) .handler(new GS4QueryHandler())
.localAddress(hostname, port); .localAddress(hostname, port);
@ -147,7 +128,7 @@ public final class ConnectionManager {
public Bootstrap createWorker() { public Bootstrap createWorker() {
return new Bootstrap() return new Bootstrap()
.channel(this.socketChannelClass) .channel(this.transportType.socketChannelClass)
.group(this.workerGroup); .group(this.workerGroup);
} }
@ -162,14 +143,61 @@ public final class ConnectionManager {
} }
} }
private static boolean canUseEpoll() {
return Epoll.isAvailable() && !DISABLE_EPOLL;
}
private static ThreadFactory createThreadFactory(final String nameFormat) { private static ThreadFactory createThreadFactory(final String nameFormat) {
return new ThreadFactoryBuilder() return new ThreadFactoryBuilder()
.setNameFormat(nameFormat) .setNameFormat(nameFormat)
.setDaemon(true) .setDaemon(true)
.build(); .build();
} }
private enum TransportType {
NIO(NioServerSocketChannel.class, NioSocketChannel.class, NioDatagramChannel.class) {
@Override
public EventLoopGroup createEventLoopGroup(boolean boss) {
String name = "Netty NIO " + (boss ? "Boss" : "Worker") + " #%d";
return new NioEventLoopGroup(0, createThreadFactory(name));
}
},
EPOLL(EpollServerSocketChannel.class, EpollSocketChannel.class, EpollDatagramChannel.class) {
@Override
public EventLoopGroup createEventLoopGroup(boolean boss) {
String name = "Netty Epoll " + (boss ? "Boss" : "Worker") + " #%d";
return new EpollEventLoopGroup(0, createThreadFactory(name));
}
},
KQUEUE(KQueueServerSocketChannel.class, KQueueSocketChannel.class, KQueueDatagramChannel.class) {
@Override
public EventLoopGroup createEventLoopGroup(boolean boss) {
String name = "Netty Kqueue " + (boss ? "Boss" : "Worker") + " #%d";
return new KQueueEventLoopGroup(0, createThreadFactory(name));
}
};
private final Class<? extends ServerSocketChannel> serverSocketChannelClass;
private final Class<? extends SocketChannel> socketChannelClass;
private final Class<? extends DatagramChannel> datagramChannelClass;
TransportType(Class<? extends ServerSocketChannel> serverSocketChannelClass, Class<? extends SocketChannel> socketChannelClass, Class<? extends DatagramChannel> datagramChannelClass) {
this.serverSocketChannelClass = serverSocketChannelClass;
this.socketChannelClass = socketChannelClass;
this.datagramChannelClass = datagramChannelClass;
}
@Override
public String toString() {
return name().toLowerCase(Locale.US);
}
public abstract EventLoopGroup createEventLoopGroup(boolean boss);
public static TransportType bestType() {
if (Epoll.isAvailable()) {
return EPOLL;
} else if (KQueue.isAvailable()) {
return KQUEUE;
} else {
return NIO;
}
}
}
} }