From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Hugo Planque Date: Mon, 18 Jan 2021 11:27:08 +0100 Subject: [PATCH] New Network System Co-authored-by: Ivan Pekov diff --git a/pom.xml b/pom.xml index 8af1a91102c5cc4c230f622e6629e46e95f17d44..9b7ed0de1054285dadff6aefc95c7207079504a6 100644 --- a/pom.xml +++ b/pom.xml @@ -53,9 +53,17 @@ io.netty netty-all - 4.1.50.Final + 4.1.58.Final + + + io.netty.incubator + netty-incubator-transport-native-io_uring + 0.0.3.Final + linux-x86_64 + + io.papermc minecraft-server diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index 87cf9cd88d1fb5ae70d19e5618ebfb67d281304a..a1c2bea7c93433434b4e4dfd0bb4b9620657c40d 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1740,6 +1740,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant a = new LazyInitVar<>(() -> { return new NioEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Server IO #%d").setDaemon(true).build()); }); public static final LazyInitVar b = new LazyInitVar<>(() -> { return new EpollEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Epoll Server IO #%d").setDaemon(true).build()); }); + */ + // Yatopia end private final MinecraftServer e; public volatile boolean c; private final List listeningChannels = Collections.synchronizedList(Lists.newArrayList()); @@ -52,15 +57,29 @@ public class ServerConnection { } // Paper end + // Yatopia start - New network system + private final NetworkType networkType; + private final EventLoopGroup boss, worker; + // Yatopia end + public ServerConnection(MinecraftServer minecraftserver) { this.e = minecraftserver; this.c = true; + + // Yatopia start - New network system + this.networkType = NetworkType.bestType(minecraftserver); + this.boss = networkType.createEventLoopGroup(NetworkType.LoopGroupType.BOSS); + this.worker = networkType.createEventLoopGroup(NetworkType.LoopGroupType.WORKER); + // Yatopia end } public void a(@Nullable InetAddress inetaddress, int i) throws IOException { + /* // Yatopia start - New network system List list = this.listeningChannels; + */ synchronized (this.listeningChannels) { + /* Class oclass; LazyInitVar lazyinitvar; @@ -73,16 +92,25 @@ public class ServerConnection { lazyinitvar = ServerConnection.a; ServerConnection.LOGGER.info("Using default channel type"); } + */ + // Tuinity start - indicate Velocity natives in use ServerConnection.LOGGER.info("Tuinity: Using " + com.velocitypowered.natives.util.Natives.compress.getLoadedVariant() + " compression from Velocity."); ServerConnection.LOGGER.info("Tuinity: Using " + com.velocitypowered.natives.util.Natives.cipher.getLoadedVariant() + " cipher from Velocity."); // Tuinity end - this.listeningChannels.add(((ServerBootstrap) ((ServerBootstrap) (new ServerBootstrap()).channel(oclass)).childHandler(new ChannelInitializer() { + ServerConnection.LOGGER.info("Yatopia: Using " + networkType.getName() + " network type."); + ServerBootstrap serverBootstrap = new ServerBootstrap(); + + if (org.yatopiamc.yatopia.server.YatopiaConfig.tcpFastOpen && networkType == NetworkType.EPOLL) { + serverBootstrap.option(EpollChannelOption.TCP_FASTOPEN, 3); // Will improve the connection with some speed + } + this.listeningChannels.add((((serverBootstrap).channelFactory(networkType.getServerSocketChannelFactory())).childHandler(new ChannelInitializer() { protected void initChannel(Channel channel) throws Exception { try { channel.config().setOption(ChannelOption.TCP_NODELAY, true); + channel.config().setOption(ChannelOption.IP_TOS, 0x18); // Change the priority of the packet to immediate } catch (ChannelException channelexception) { ; } @@ -97,7 +125,8 @@ public class ServerConnection { channel.pipeline().addLast("packet_handler", (ChannelHandler) object); ((NetworkManager) object).setPacketListener(new HandshakeListener(ServerConnection.this.e, (NetworkManager) object)); } - }).group((EventLoopGroup) lazyinitvar.a()).localAddress(inetaddress, i)).option(ChannelOption.AUTO_READ, false).bind().syncUninterruptibly()); // CraftBukkit + }).group(boss, worker).localAddress(inetaddress, i)).option(ChannelOption.AUTO_READ, false).bind().syncUninterruptibly()); // CraftBukkit + // Yatopia end } } diff --git a/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java b/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java index 35f212c2ac43ebea6ce9c4a333738c7a869ebc18..c4d0dabd408c7a943dafd6ca89b598cb4afb440e 100644 --- a/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java +++ b/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java @@ -303,4 +303,11 @@ public class YatopiaConfig { logPlayerLoginLoc = getBoolean("settings.log-player-login-location", logPlayerLoginLoc); } + public static boolean ioUringBeta = false; + public static boolean tcpFastOpen = false; + private static void newNetworkSystem() { + ioUringBeta = getBoolean("network.io-uring", ioUringBeta); + tcpFastOpen = getBoolean("network.ftcp-fastopen", tcpFastOpen); + } + } diff --git a/src/main/java/org/yatopiamc/yatopia/server/network/NettyThreadFactory.java b/src/main/java/org/yatopiamc/yatopia/server/network/NettyThreadFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..3e74e23f3cc44b7547d9f8575b411059e0e65449 --- /dev/null +++ b/src/main/java/org/yatopiamc/yatopia/server/network/NettyThreadFactory.java @@ -0,0 +1,27 @@ +package org.yatopiamc.yatopia.server.network; + +import io.netty.util.concurrent.FastThreadLocalThread; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Based off of Velocity's VelocityNettyThreadFactory + */ +public class NettyThreadFactory implements ThreadFactory { + + private final AtomicInteger threadNumber = new AtomicInteger(); + private final String networkTypeName, loopGroupTypeName; + + public NettyThreadFactory(String networkTypeName, String loopGroupTypeName) { + this.networkTypeName = networkTypeName; + this.loopGroupTypeName = loopGroupTypeName; + } + + @Override + public Thread newThread(Runnable r) { + return new FastThreadLocalThread( + r, + "Netty " + networkTypeName + " " + loopGroupTypeName + " #" + threadNumber.getAndIncrement() + ); + } +} diff --git a/src/main/java/org/yatopiamc/yatopia/server/network/NetworkType.java b/src/main/java/org/yatopiamc/yatopia/server/network/NetworkType.java new file mode 100644 index 0000000000000000000000000000000000000000..6b9d788dfef2c51111e9f2129a04fce7754c51ba --- /dev/null +++ b/src/main/java/org/yatopiamc/yatopia/server/network/NetworkType.java @@ -0,0 +1,110 @@ +package org.yatopiamc.yatopia.server.network; + +import io.netty.channel.ChannelFactory; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.epoll.Epoll; +import io.netty.channel.epoll.EpollEventLoopGroup; +import io.netty.channel.epoll.EpollServerSocketChannel; +import io.netty.channel.kqueue.KQueue; +import io.netty.channel.kqueue.KQueueEventLoopGroup; +import io.netty.channel.kqueue.KQueueServerSocketChannel; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.ServerSocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.incubator.channel.uring.IOUring; +import io.netty.incubator.channel.uring.IOUringEventLoopGroup; +import io.netty.incubator.channel.uring.IOUringServerSocketChannel; + +import java.util.concurrent.ThreadFactory; +import java.util.function.BiFunction; + +import net.minecraft.server.MinecraftServer; +import org.spigotmc.SpigotConfig; +import org.yatopiamc.yatopia.server.YatopiaConfig; + +/** + * Based off of Velocity's TransportType + */ +public enum NetworkType { + NIO("NIO", NioServerSocketChannel::new, (name, type) -> new NioEventLoopGroup(8, createThreadFactory(name, type))), + + EPOLL("Epoll", EpollServerSocketChannel::new, (name, type) -> new EpollEventLoopGroup(8, createThreadFactory(name, type))), + + IOURING("IOUring", IOUringServerSocketChannel::new, (name, type) -> new IOUringEventLoopGroup(8, createThreadFactory(name, type))), + + KQUEUE("KQueue", KQueueServerSocketChannel::new, (name, type) -> new KQueueEventLoopGroup(8, createThreadFactory(name, type))); + + public final String name; + public final ChannelFactory serverSocketChannelFactory; + public final BiFunction eventLoopGroupFactory; + + NetworkType(final String name, + final ChannelFactory serverSocketChannelFactory, + final BiFunction eventLoopGroupFactory) { + this.name = name; + this.serverSocketChannelFactory = serverSocketChannelFactory; + this.eventLoopGroupFactory = eventLoopGroupFactory; + } + + public String getName() { + return name; + } + + public ChannelFactory getServerSocketChannelFactory() { + return serverSocketChannelFactory; + } + + @Override + public String toString() { + return this.name; + } + + public EventLoopGroup createEventLoopGroup(final LoopGroupType type) { + return this.eventLoopGroupFactory.apply(this.name, type); + } + + private static ThreadFactory createThreadFactory(final String name, final LoopGroupType type) { + return new NettyThreadFactory(name, type.toString()); + } + + public static NetworkType bestType(MinecraftServer minecraftServer) { + if (!minecraftServer.isUsingNativeTransport()) { + return NIO; + } + // Actually, there is a decompression problem with zlib from bungeecord that makes + // IOUring not available on spigot server with bungeecord + // https://github.com/netty/netty-incubator-transport-io_uring/issues/40 + // Looks like iouring send very small compressed packet and trigger PacketDecompressor + if (!SpigotConfig.bungee && YatopiaConfig.ioUringBeta && MinecraftServer.getServer().ax() < 0) { + if (IOUring.isAvailable()) { + return IOURING; + } + } + + if (Epoll.isAvailable()) { + return EPOLL; + } + + if (KQueue.isAvailable()) { + return KQUEUE; + } + + return NIO; + } + + public enum LoopGroupType { + BOSS("Boss"), + WORKER("Worker"); + + private final String name; + + LoopGroupType(final String name) { + this.name = name; + } + + @Override + public String toString() { + return this.name; + } + } +}