From eec979c6644dc56c6ccc9875bb75415561278203 Mon Sep 17 00:00:00 2001 From: Bixilon Date: Sun, 9 Jan 2022 23:23:14 +0100 Subject: [PATCH] netty: use epoll when available, improvements --- .../profile/profiles/other/OtherProfile.kt | 5 +++ .../network/connection/play/PlayConnection.kt | 2 +- .../connection/status/StatusConnection.kt | 2 +- .../network/client/NamedThreadFactory.kt | 27 +++++++++++++++ .../network/network/client/NettyClient.kt | 34 ++++++++++++++----- 5 files changed, 59 insertions(+), 11 deletions(-) create mode 100644 src/main/java/de/bixilon/minosoft/protocol/network/network/client/NamedThreadFactory.kt diff --git a/src/main/java/de/bixilon/minosoft/config/profile/profiles/other/OtherProfile.kt b/src/main/java/de/bixilon/minosoft/config/profile/profiles/other/OtherProfile.kt index 09056b702..62a2c4969 100644 --- a/src/main/java/de/bixilon/minosoft/config/profile/profiles/other/OtherProfile.kt +++ b/src/main/java/de/bixilon/minosoft/config/profile/profiles/other/OtherProfile.kt @@ -35,6 +35,11 @@ class OtherProfile( override val version: Int = latestVersion override var description by delegate(description ?: "") + /** + * Use native network transport if available + */ + var epoll by delegate(true) + /** * MacOS only: Ignores the warning if the jvm argument diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/connection/play/PlayConnection.kt b/src/main/java/de/bixilon/minosoft/protocol/network/connection/play/PlayConnection.kt index fea39fe26..8928710ec 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/network/connection/play/PlayConnection.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/network/connection/play/PlayConnection.kt @@ -224,7 +224,7 @@ class PlayConnection( renderLatch.awaitWithChange() } Log.log(LogMessageType.NETWORK_STATUS, level = LogLevels.INFO) { "Connecting to server: $address" } - network.connect(address) + network.connect(address, profiles.other.epoll) state = PlayConnectionStates.ESTABLISHING } catch (exception: Throwable) { Log.log(LogMessageType.VERSION_LOADING, level = LogLevels.FATAL) { exception } diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/connection/status/StatusConnection.kt b/src/main/java/de/bixilon/minosoft/protocol/network/connection/status/StatusConnection.kt index 3938ef24c..b61aa9232 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/network/connection/status/StatusConnection.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/network/connection/status/StatusConnection.kt @@ -143,7 +143,7 @@ class StatusConnection( Log.log(LogMessageType.NETWORK_RESOLVING) { "Trying to ping $tryAddress (from $address)" } state = StatusConnectionStates.ESTABLISHING - network.connect(tryAddress) + network.connect(tryAddress, false) } } diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/network/client/NamedThreadFactory.kt b/src/main/java/de/bixilon/minosoft/protocol/network/network/client/NamedThreadFactory.kt new file mode 100644 index 000000000..2230ef77f --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/protocol/network/network/client/NamedThreadFactory.kt @@ -0,0 +1,27 @@ +/* + * Minosoft + * Copyright (C) 2020-2022 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.protocol.network.network.client + +import java.util.concurrent.ThreadFactory +import java.util.concurrent.atomic.AtomicInteger + +class NamedThreadFactory( + val format: String, +) : ThreadFactory { + var count = AtomicInteger(0) + + override fun newThread(runnable: Runnable): Thread { + return Thread(runnable, format.format(count.incrementAndGet())) + } +} diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/network/client/NettyClient.kt b/src/main/java/de/bixilon/minosoft/protocol/network/network/client/NettyClient.kt index ae73d390a..a799a9f94 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/network/network/client/NettyClient.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/network/network/client/NettyClient.kt @@ -14,7 +14,6 @@ package de.bixilon.minosoft.protocol.network.network.client import de.bixilon.kutil.cast.CastUtil.nullCast -import de.bixilon.kutil.concurrent.pool.DefaultThreadPool import de.bixilon.kutil.watcher.DataWatcher.Companion.watched import de.bixilon.minosoft.config.profile.profiles.other.OtherProfileManager import de.bixilon.minosoft.protocol.network.connection.Connection @@ -32,6 +31,10 @@ import io.netty.bootstrap.Bootstrap import io.netty.channel.Channel import io.netty.channel.ChannelFuture import io.netty.channel.ChannelOption +import io.netty.channel.EventLoopGroup +import io.netty.channel.epoll.Epoll +import io.netty.channel.epoll.EpollEventLoopGroup +import io.netty.channel.epoll.EpollSocketChannel import io.netty.channel.nio.NioEventLoopGroup import io.netty.channel.socket.nio.NioSocketChannel import javax.crypto.Cipher @@ -69,12 +72,19 @@ class NettyClient( private set private var channel: Channel? = null - fun connect(address: ServerAddress) { - val workerGroup = NioEventLoopGroup(DefaultThreadPool.threadCount - 1, DefaultThreadPool) - // val workerGroup = NioEventLoopGroup() + fun connect(address: ServerAddress, epoll: Boolean) { + val threadPool: EventLoopGroup + val channelClass: Class + if (Epoll.isAvailable() && epoll) { + threadPool = EPOLL_THREAD_POOL + channelClass = EpollSocketChannel::class.java + } else { + threadPool = NIO_THREAD_POOL + channelClass = NioSocketChannel::class.java + } val bootstrap = Bootstrap() - .group(workerGroup) - .channel(NioSocketChannel::class.java) + .group(threadPool) + .channel(channelClass) .handler(NetworkPipeline(this)) val future: ChannelFuture = bootstrap.connect(address.hostname, address.port).sync() @@ -85,9 +95,11 @@ class NettyClient( } val channel = future.channel() this.channel = channel - channel.config().setOption(ChannelOption.TCP_NODELAY, true) + try { + channel.config().setOption(ChannelOption.TCP_NODELAY, true) + } catch (_: Throwable) { + } connected = true - println("Connected!") } } @@ -103,7 +115,6 @@ class NettyClient( fun disconnect() { channel?.close() - // ToDo: workerGroup.shutdownGracefully() connected = false } @@ -119,4 +130,9 @@ class NettyClient( packet.log((connection.nullCast()?.profiles?.other ?: OtherProfileManager.selected).log.reducedProtocolLog) channel.writeAndFlush(packet) } + + companion object { + private val NIO_THREAD_POOL by lazy { NioEventLoopGroup(NamedThreadFactory("Nio#%d")) } + private val EPOLL_THREAD_POOL by lazy { EpollEventLoopGroup(NamedThreadFactory("Epoll#%d")) } + } }