From 715746a168bb52450055c279a1c07d6e403fb6af Mon Sep 17 00:00:00 2001 From: Jire Date: Wed, 27 Nov 2024 19:37:19 -0500 Subject: [PATCH] feat: upgrade to Netty `4.2.0.Beta1` --- gradle/libs.versions.toml | 5 +- .../osrs-221/osrs-221-api/build.gradle.kts | 4 +- .../api/bootstrap/BootstrapFactory.kt | 61 +++++++++---------- .../osrs-222/osrs-222-api/build.gradle.kts | 4 +- .../api/bootstrap/BootstrapFactory.kt | 61 +++++++++---------- .../osrs-223/osrs-223-api/build.gradle.kts | 4 +- .../api/bootstrap/BootstrapFactory.kt | 61 +++++++++---------- .../osrs-224/osrs-224-api/build.gradle.kts | 4 +- .../api/bootstrap/BootstrapFactory.kt | 61 +++++++++---------- .../osrs-225/osrs-225-api/build.gradle.kts | 4 +- .../api/bootstrap/BootstrapBuilder.kt | 60 +++++++++--------- .../osrs-226/osrs-226-api/build.gradle.kts | 4 +- .../api/bootstrap/BootstrapBuilder.kt | 60 +++++++++--------- .../osrs-227/osrs-227-api/build.gradle.kts | 4 +- .../api/bootstrap/BootstrapBuilder.kt | 60 +++++++++--------- 15 files changed, 221 insertions(+), 236 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 103c94a59..b194d5580 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,6 @@ [versions] kotlin = "1.9.23" -netty = "4.1.109.Final" -netty-iouring = "0.0.25.Final" +netty = "4.2.0.Beta1" junit = "5.10.2" jmh = "0.4.10" inlinelogger = "1.0.6" @@ -21,7 +20,7 @@ netty-handler = { module = "io.netty:netty-handler" } netty-native-epoll = { module = "io.netty:netty-transport-native-epoll" } netty-native-kqueue = { module = "io.netty:netty-transport-native-kqueue" } netty-native-macos-dns-resolver = { module = "io.netty:netty-resolver-dns-native-macos" } -netty-incubator-iouring = { module = "io.netty.incubator:netty-incubator-transport-native-io_uring", version.ref = "netty-iouring" } +netty-iouring = { module = "io.netty:netty-transport-native-io_uring", version.ref = "netty" } junit-bom = { module = "org.junit:junit-bom", version.ref = "junit" } junit-api = { module = "org.junit.jupiter:junit-jupiter-api" } junit-engine = { module = "org.junit.jupiter:junit-jupiter-engine" } diff --git a/protocol/osrs-221/osrs-221-api/build.gradle.kts b/protocol/osrs-221/osrs-221-api/build.gradle.kts index 45cb8b1f2..0fd13e6e3 100644 --- a/protocol/osrs-221/osrs-221-api/build.gradle.kts +++ b/protocol/osrs-221/osrs-221-api/build.gradle.kts @@ -5,7 +5,7 @@ dependencies { implementation(rootProject.libs.netty.handler) implementation(rootProject.libs.netty.native.epoll) implementation(rootProject.libs.netty.native.kqueue) - implementation(rootProject.libs.netty.incubator.iouring) + implementation(rootProject.libs.netty.iouring) implementation(rootProject.libs.netty.native.macos.dns.resolver) val epollClassifiers = listOf("linux-aarch_64", "linux-x86_64", "linux-riscv64") val kqueueClassifiers = listOf("osx-x86_64") @@ -17,7 +17,7 @@ dependencies { implementation(variantOf(rootProject.libs.netty.native.kqueue) { classifier(classifier) }) } for (classifier in iouringClassifiers) { - implementation(variantOf(rootProject.libs.netty.incubator.iouring) { classifier(classifier) }) + implementation(variantOf(rootProject.libs.netty.iouring) { classifier(classifier) }) } implementation(rootProject.libs.inline.logger) api(projects.protocol) diff --git a/protocol/osrs-221/osrs-221-api/src/main/kotlin/net/rsprot/protocol/api/bootstrap/BootstrapFactory.kt b/protocol/osrs-221/osrs-221-api/src/main/kotlin/net/rsprot/protocol/api/bootstrap/BootstrapFactory.kt index 2d085f81b..b611c71d1 100644 --- a/protocol/osrs-221/osrs-221-api/src/main/kotlin/net/rsprot/protocol/api/bootstrap/BootstrapFactory.kt +++ b/protocol/osrs-221/osrs-221-api/src/main/kotlin/net/rsprot/protocol/api/bootstrap/BootstrapFactory.kt @@ -5,20 +5,20 @@ import io.netty.bootstrap.ServerBootstrap import io.netty.buffer.ByteBufAllocator import io.netty.channel.ChannelOption import io.netty.channel.EventLoopGroup +import io.netty.channel.IoHandlerFactory +import io.netty.channel.MultiThreadIoEventLoopGroup import io.netty.channel.WriteBufferWaterMark import io.netty.channel.epoll.Epoll -import io.netty.channel.epoll.EpollChannelOption -import io.netty.channel.epoll.EpollEventLoopGroup -import io.netty.channel.epoll.EpollMode +import io.netty.channel.epoll.EpollIoHandler import io.netty.channel.epoll.EpollServerSocketChannel import io.netty.channel.kqueue.KQueue -import io.netty.channel.kqueue.KQueueEventLoopGroup +import io.netty.channel.kqueue.KQueueIoHandler import io.netty.channel.kqueue.KQueueServerSocketChannel -import io.netty.channel.nio.NioEventLoopGroup +import io.netty.channel.nio.NioIoHandler 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 io.netty.channel.uring.IoUring +import io.netty.channel.uring.IoUringIoHandler +import io.netty.channel.uring.IoUringServerSocketChannel import net.rsprot.protocol.api.logging.networkLog /** @@ -28,28 +28,29 @@ public class BootstrapFactory( private val alloc: ByteBufAllocator, ) { /** - * Creates a parent loop group with a single thread behind it, based on the best - * available event loop group. + * Creates an IO handler factory based on the best available event loop group. */ - public fun createParentLoopGroup(): EventLoopGroup = + public fun createIoHandlerFactory(): IoHandlerFactory = when { - IOUring.isAvailable() -> IOUringEventLoopGroup(1) - Epoll.isAvailable() -> EpollEventLoopGroup(1) - KQueue.isAvailable() -> KQueueEventLoopGroup(1) - else -> NioEventLoopGroup(1) + IoUring.isAvailable() -> IoUringIoHandler.newFactory() + Epoll.isAvailable() -> EpollIoHandler.newFactory() + KQueue.isAvailable() -> KQueueIoHandler.newFactory() + else -> NioIoHandler.newFactory() } + /** + * Creates a parent loop group with a single thread behind it, based on the best + * available event loop group. + */ + public fun createParentLoopGroup(nThreads: Int = 1): EventLoopGroup = + MultiThreadIoEventLoopGroup(nThreads, createIoHandlerFactory()) + /** * Creates a child loop group with a number of threads based on availableProcessors * 2, * which is done at Netty level. */ - public fun createChildLoopGroup(): EventLoopGroup = - when { - IOUring.isAvailable() -> IOUringEventLoopGroup() - Epoll.isAvailable() -> EpollEventLoopGroup() - KQueue.isAvailable() -> KQueueEventLoopGroup() - else -> NioEventLoopGroup() - } + public fun createChildLoopGroup(nThreads: Int = 0): EventLoopGroup = + MultiThreadIoEventLoopGroup(nThreads, createIoHandlerFactory()) /** * Creates a server bootstrap using the parent and child event loop groups with @@ -60,12 +61,11 @@ public class BootstrapFactory( childGroup: EventLoopGroup, ): ServerBootstrap { val channel = - when (parentGroup) { - is IOUringEventLoopGroup -> IOUringServerSocketChannel::class.java - is EpollEventLoopGroup -> EpollServerSocketChannel::class.java - is KQueueEventLoopGroup -> KQueueServerSocketChannel::class.java - is NioEventLoopGroup -> NioServerSocketChannel::class.java - else -> throw IllegalArgumentException("Unknown EventLoopGroup type") + when { + IoUring.isAvailable() -> IoUringServerSocketChannel::class.java + Epoll.isAvailable() -> EpollServerSocketChannel::class.java + KQueue.isAvailable() -> KQueueServerSocketChannel::class.java + else -> NioServerSocketChannel::class.java } networkLog(logger) { "Bootstrap event loop group: ${parentGroup.javaClass.simpleName}" @@ -81,11 +81,6 @@ public class BootstrapFactory( .childOption(ChannelOption.SO_SNDBUF, 65536) .childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, 30_000) .childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, WriteBufferWaterMark(524_288, 2_097_152)) - .also { - if (parentGroup is EpollEventLoopGroup) { - it.childOption(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED) - } - } } private companion object { diff --git a/protocol/osrs-222/osrs-222-api/build.gradle.kts b/protocol/osrs-222/osrs-222-api/build.gradle.kts index ec4f7ca99..1c9ee2e98 100644 --- a/protocol/osrs-222/osrs-222-api/build.gradle.kts +++ b/protocol/osrs-222/osrs-222-api/build.gradle.kts @@ -5,7 +5,7 @@ dependencies { implementation(rootProject.libs.netty.handler) implementation(rootProject.libs.netty.native.epoll) implementation(rootProject.libs.netty.native.kqueue) - implementation(rootProject.libs.netty.incubator.iouring) + implementation(rootProject.libs.netty.iouring) implementation(rootProject.libs.netty.native.macos.dns.resolver) val epollClassifiers = listOf("linux-aarch_64", "linux-x86_64", "linux-riscv64") val kqueueClassifiers = listOf("osx-x86_64") @@ -17,7 +17,7 @@ dependencies { implementation(variantOf(rootProject.libs.netty.native.kqueue) { classifier(classifier) }) } for (classifier in iouringClassifiers) { - implementation(variantOf(rootProject.libs.netty.incubator.iouring) { classifier(classifier) }) + implementation(variantOf(rootProject.libs.netty.iouring) { classifier(classifier) }) } implementation(rootProject.libs.inline.logger) api(projects.protocol) diff --git a/protocol/osrs-222/osrs-222-api/src/main/kotlin/net/rsprot/protocol/api/bootstrap/BootstrapFactory.kt b/protocol/osrs-222/osrs-222-api/src/main/kotlin/net/rsprot/protocol/api/bootstrap/BootstrapFactory.kt index 2d085f81b..b611c71d1 100644 --- a/protocol/osrs-222/osrs-222-api/src/main/kotlin/net/rsprot/protocol/api/bootstrap/BootstrapFactory.kt +++ b/protocol/osrs-222/osrs-222-api/src/main/kotlin/net/rsprot/protocol/api/bootstrap/BootstrapFactory.kt @@ -5,20 +5,20 @@ import io.netty.bootstrap.ServerBootstrap import io.netty.buffer.ByteBufAllocator import io.netty.channel.ChannelOption import io.netty.channel.EventLoopGroup +import io.netty.channel.IoHandlerFactory +import io.netty.channel.MultiThreadIoEventLoopGroup import io.netty.channel.WriteBufferWaterMark import io.netty.channel.epoll.Epoll -import io.netty.channel.epoll.EpollChannelOption -import io.netty.channel.epoll.EpollEventLoopGroup -import io.netty.channel.epoll.EpollMode +import io.netty.channel.epoll.EpollIoHandler import io.netty.channel.epoll.EpollServerSocketChannel import io.netty.channel.kqueue.KQueue -import io.netty.channel.kqueue.KQueueEventLoopGroup +import io.netty.channel.kqueue.KQueueIoHandler import io.netty.channel.kqueue.KQueueServerSocketChannel -import io.netty.channel.nio.NioEventLoopGroup +import io.netty.channel.nio.NioIoHandler 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 io.netty.channel.uring.IoUring +import io.netty.channel.uring.IoUringIoHandler +import io.netty.channel.uring.IoUringServerSocketChannel import net.rsprot.protocol.api.logging.networkLog /** @@ -28,28 +28,29 @@ public class BootstrapFactory( private val alloc: ByteBufAllocator, ) { /** - * Creates a parent loop group with a single thread behind it, based on the best - * available event loop group. + * Creates an IO handler factory based on the best available event loop group. */ - public fun createParentLoopGroup(): EventLoopGroup = + public fun createIoHandlerFactory(): IoHandlerFactory = when { - IOUring.isAvailable() -> IOUringEventLoopGroup(1) - Epoll.isAvailable() -> EpollEventLoopGroup(1) - KQueue.isAvailable() -> KQueueEventLoopGroup(1) - else -> NioEventLoopGroup(1) + IoUring.isAvailable() -> IoUringIoHandler.newFactory() + Epoll.isAvailable() -> EpollIoHandler.newFactory() + KQueue.isAvailable() -> KQueueIoHandler.newFactory() + else -> NioIoHandler.newFactory() } + /** + * Creates a parent loop group with a single thread behind it, based on the best + * available event loop group. + */ + public fun createParentLoopGroup(nThreads: Int = 1): EventLoopGroup = + MultiThreadIoEventLoopGroup(nThreads, createIoHandlerFactory()) + /** * Creates a child loop group with a number of threads based on availableProcessors * 2, * which is done at Netty level. */ - public fun createChildLoopGroup(): EventLoopGroup = - when { - IOUring.isAvailable() -> IOUringEventLoopGroup() - Epoll.isAvailable() -> EpollEventLoopGroup() - KQueue.isAvailable() -> KQueueEventLoopGroup() - else -> NioEventLoopGroup() - } + public fun createChildLoopGroup(nThreads: Int = 0): EventLoopGroup = + MultiThreadIoEventLoopGroup(nThreads, createIoHandlerFactory()) /** * Creates a server bootstrap using the parent and child event loop groups with @@ -60,12 +61,11 @@ public class BootstrapFactory( childGroup: EventLoopGroup, ): ServerBootstrap { val channel = - when (parentGroup) { - is IOUringEventLoopGroup -> IOUringServerSocketChannel::class.java - is EpollEventLoopGroup -> EpollServerSocketChannel::class.java - is KQueueEventLoopGroup -> KQueueServerSocketChannel::class.java - is NioEventLoopGroup -> NioServerSocketChannel::class.java - else -> throw IllegalArgumentException("Unknown EventLoopGroup type") + when { + IoUring.isAvailable() -> IoUringServerSocketChannel::class.java + Epoll.isAvailable() -> EpollServerSocketChannel::class.java + KQueue.isAvailable() -> KQueueServerSocketChannel::class.java + else -> NioServerSocketChannel::class.java } networkLog(logger) { "Bootstrap event loop group: ${parentGroup.javaClass.simpleName}" @@ -81,11 +81,6 @@ public class BootstrapFactory( .childOption(ChannelOption.SO_SNDBUF, 65536) .childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, 30_000) .childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, WriteBufferWaterMark(524_288, 2_097_152)) - .also { - if (parentGroup is EpollEventLoopGroup) { - it.childOption(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED) - } - } } private companion object { diff --git a/protocol/osrs-223/osrs-223-api/build.gradle.kts b/protocol/osrs-223/osrs-223-api/build.gradle.kts index 3dad2caac..67d63cef1 100644 --- a/protocol/osrs-223/osrs-223-api/build.gradle.kts +++ b/protocol/osrs-223/osrs-223-api/build.gradle.kts @@ -5,7 +5,7 @@ dependencies { implementation(rootProject.libs.netty.handler) implementation(rootProject.libs.netty.native.epoll) implementation(rootProject.libs.netty.native.kqueue) - implementation(rootProject.libs.netty.incubator.iouring) + implementation(rootProject.libs.netty.iouring) implementation(rootProject.libs.netty.native.macos.dns.resolver) val epollClassifiers = listOf("linux-aarch_64", "linux-x86_64", "linux-riscv64") val kqueueClassifiers = listOf("osx-x86_64") @@ -17,7 +17,7 @@ dependencies { implementation(variantOf(rootProject.libs.netty.native.kqueue) { classifier(classifier) }) } for (classifier in iouringClassifiers) { - implementation(variantOf(rootProject.libs.netty.incubator.iouring) { classifier(classifier) }) + implementation(variantOf(rootProject.libs.netty.iouring) { classifier(classifier) }) } implementation(rootProject.libs.inline.logger) api(projects.protocol) diff --git a/protocol/osrs-223/osrs-223-api/src/main/kotlin/net/rsprot/protocol/api/bootstrap/BootstrapFactory.kt b/protocol/osrs-223/osrs-223-api/src/main/kotlin/net/rsprot/protocol/api/bootstrap/BootstrapFactory.kt index 2d085f81b..b611c71d1 100644 --- a/protocol/osrs-223/osrs-223-api/src/main/kotlin/net/rsprot/protocol/api/bootstrap/BootstrapFactory.kt +++ b/protocol/osrs-223/osrs-223-api/src/main/kotlin/net/rsprot/protocol/api/bootstrap/BootstrapFactory.kt @@ -5,20 +5,20 @@ import io.netty.bootstrap.ServerBootstrap import io.netty.buffer.ByteBufAllocator import io.netty.channel.ChannelOption import io.netty.channel.EventLoopGroup +import io.netty.channel.IoHandlerFactory +import io.netty.channel.MultiThreadIoEventLoopGroup import io.netty.channel.WriteBufferWaterMark import io.netty.channel.epoll.Epoll -import io.netty.channel.epoll.EpollChannelOption -import io.netty.channel.epoll.EpollEventLoopGroup -import io.netty.channel.epoll.EpollMode +import io.netty.channel.epoll.EpollIoHandler import io.netty.channel.epoll.EpollServerSocketChannel import io.netty.channel.kqueue.KQueue -import io.netty.channel.kqueue.KQueueEventLoopGroup +import io.netty.channel.kqueue.KQueueIoHandler import io.netty.channel.kqueue.KQueueServerSocketChannel -import io.netty.channel.nio.NioEventLoopGroup +import io.netty.channel.nio.NioIoHandler 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 io.netty.channel.uring.IoUring +import io.netty.channel.uring.IoUringIoHandler +import io.netty.channel.uring.IoUringServerSocketChannel import net.rsprot.protocol.api.logging.networkLog /** @@ -28,28 +28,29 @@ public class BootstrapFactory( private val alloc: ByteBufAllocator, ) { /** - * Creates a parent loop group with a single thread behind it, based on the best - * available event loop group. + * Creates an IO handler factory based on the best available event loop group. */ - public fun createParentLoopGroup(): EventLoopGroup = + public fun createIoHandlerFactory(): IoHandlerFactory = when { - IOUring.isAvailable() -> IOUringEventLoopGroup(1) - Epoll.isAvailable() -> EpollEventLoopGroup(1) - KQueue.isAvailable() -> KQueueEventLoopGroup(1) - else -> NioEventLoopGroup(1) + IoUring.isAvailable() -> IoUringIoHandler.newFactory() + Epoll.isAvailable() -> EpollIoHandler.newFactory() + KQueue.isAvailable() -> KQueueIoHandler.newFactory() + else -> NioIoHandler.newFactory() } + /** + * Creates a parent loop group with a single thread behind it, based on the best + * available event loop group. + */ + public fun createParentLoopGroup(nThreads: Int = 1): EventLoopGroup = + MultiThreadIoEventLoopGroup(nThreads, createIoHandlerFactory()) + /** * Creates a child loop group with a number of threads based on availableProcessors * 2, * which is done at Netty level. */ - public fun createChildLoopGroup(): EventLoopGroup = - when { - IOUring.isAvailable() -> IOUringEventLoopGroup() - Epoll.isAvailable() -> EpollEventLoopGroup() - KQueue.isAvailable() -> KQueueEventLoopGroup() - else -> NioEventLoopGroup() - } + public fun createChildLoopGroup(nThreads: Int = 0): EventLoopGroup = + MultiThreadIoEventLoopGroup(nThreads, createIoHandlerFactory()) /** * Creates a server bootstrap using the parent and child event loop groups with @@ -60,12 +61,11 @@ public class BootstrapFactory( childGroup: EventLoopGroup, ): ServerBootstrap { val channel = - when (parentGroup) { - is IOUringEventLoopGroup -> IOUringServerSocketChannel::class.java - is EpollEventLoopGroup -> EpollServerSocketChannel::class.java - is KQueueEventLoopGroup -> KQueueServerSocketChannel::class.java - is NioEventLoopGroup -> NioServerSocketChannel::class.java - else -> throw IllegalArgumentException("Unknown EventLoopGroup type") + when { + IoUring.isAvailable() -> IoUringServerSocketChannel::class.java + Epoll.isAvailable() -> EpollServerSocketChannel::class.java + KQueue.isAvailable() -> KQueueServerSocketChannel::class.java + else -> NioServerSocketChannel::class.java } networkLog(logger) { "Bootstrap event loop group: ${parentGroup.javaClass.simpleName}" @@ -81,11 +81,6 @@ public class BootstrapFactory( .childOption(ChannelOption.SO_SNDBUF, 65536) .childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, 30_000) .childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, WriteBufferWaterMark(524_288, 2_097_152)) - .also { - if (parentGroup is EpollEventLoopGroup) { - it.childOption(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED) - } - } } private companion object { diff --git a/protocol/osrs-224/osrs-224-api/build.gradle.kts b/protocol/osrs-224/osrs-224-api/build.gradle.kts index cd8b4a349..e2c17af1f 100644 --- a/protocol/osrs-224/osrs-224-api/build.gradle.kts +++ b/protocol/osrs-224/osrs-224-api/build.gradle.kts @@ -5,7 +5,7 @@ dependencies { implementation(rootProject.libs.netty.handler) implementation(rootProject.libs.netty.native.epoll) implementation(rootProject.libs.netty.native.kqueue) - implementation(rootProject.libs.netty.incubator.iouring) + implementation(rootProject.libs.netty.iouring) implementation(rootProject.libs.netty.native.macos.dns.resolver) val epollClassifiers = listOf("linux-aarch_64", "linux-x86_64", "linux-riscv64") val kqueueClassifiers = listOf("osx-x86_64") @@ -17,7 +17,7 @@ dependencies { implementation(variantOf(rootProject.libs.netty.native.kqueue) { classifier(classifier) }) } for (classifier in iouringClassifiers) { - implementation(variantOf(rootProject.libs.netty.incubator.iouring) { classifier(classifier) }) + implementation(variantOf(rootProject.libs.netty.iouring) { classifier(classifier) }) } implementation(rootProject.libs.inline.logger) api(projects.protocol) diff --git a/protocol/osrs-224/osrs-224-api/src/main/kotlin/net/rsprot/protocol/api/bootstrap/BootstrapFactory.kt b/protocol/osrs-224/osrs-224-api/src/main/kotlin/net/rsprot/protocol/api/bootstrap/BootstrapFactory.kt index 2d085f81b..b611c71d1 100644 --- a/protocol/osrs-224/osrs-224-api/src/main/kotlin/net/rsprot/protocol/api/bootstrap/BootstrapFactory.kt +++ b/protocol/osrs-224/osrs-224-api/src/main/kotlin/net/rsprot/protocol/api/bootstrap/BootstrapFactory.kt @@ -5,20 +5,20 @@ import io.netty.bootstrap.ServerBootstrap import io.netty.buffer.ByteBufAllocator import io.netty.channel.ChannelOption import io.netty.channel.EventLoopGroup +import io.netty.channel.IoHandlerFactory +import io.netty.channel.MultiThreadIoEventLoopGroup import io.netty.channel.WriteBufferWaterMark import io.netty.channel.epoll.Epoll -import io.netty.channel.epoll.EpollChannelOption -import io.netty.channel.epoll.EpollEventLoopGroup -import io.netty.channel.epoll.EpollMode +import io.netty.channel.epoll.EpollIoHandler import io.netty.channel.epoll.EpollServerSocketChannel import io.netty.channel.kqueue.KQueue -import io.netty.channel.kqueue.KQueueEventLoopGroup +import io.netty.channel.kqueue.KQueueIoHandler import io.netty.channel.kqueue.KQueueServerSocketChannel -import io.netty.channel.nio.NioEventLoopGroup +import io.netty.channel.nio.NioIoHandler 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 io.netty.channel.uring.IoUring +import io.netty.channel.uring.IoUringIoHandler +import io.netty.channel.uring.IoUringServerSocketChannel import net.rsprot.protocol.api.logging.networkLog /** @@ -28,28 +28,29 @@ public class BootstrapFactory( private val alloc: ByteBufAllocator, ) { /** - * Creates a parent loop group with a single thread behind it, based on the best - * available event loop group. + * Creates an IO handler factory based on the best available event loop group. */ - public fun createParentLoopGroup(): EventLoopGroup = + public fun createIoHandlerFactory(): IoHandlerFactory = when { - IOUring.isAvailable() -> IOUringEventLoopGroup(1) - Epoll.isAvailable() -> EpollEventLoopGroup(1) - KQueue.isAvailable() -> KQueueEventLoopGroup(1) - else -> NioEventLoopGroup(1) + IoUring.isAvailable() -> IoUringIoHandler.newFactory() + Epoll.isAvailable() -> EpollIoHandler.newFactory() + KQueue.isAvailable() -> KQueueIoHandler.newFactory() + else -> NioIoHandler.newFactory() } + /** + * Creates a parent loop group with a single thread behind it, based on the best + * available event loop group. + */ + public fun createParentLoopGroup(nThreads: Int = 1): EventLoopGroup = + MultiThreadIoEventLoopGroup(nThreads, createIoHandlerFactory()) + /** * Creates a child loop group with a number of threads based on availableProcessors * 2, * which is done at Netty level. */ - public fun createChildLoopGroup(): EventLoopGroup = - when { - IOUring.isAvailable() -> IOUringEventLoopGroup() - Epoll.isAvailable() -> EpollEventLoopGroup() - KQueue.isAvailable() -> KQueueEventLoopGroup() - else -> NioEventLoopGroup() - } + public fun createChildLoopGroup(nThreads: Int = 0): EventLoopGroup = + MultiThreadIoEventLoopGroup(nThreads, createIoHandlerFactory()) /** * Creates a server bootstrap using the parent and child event loop groups with @@ -60,12 +61,11 @@ public class BootstrapFactory( childGroup: EventLoopGroup, ): ServerBootstrap { val channel = - when (parentGroup) { - is IOUringEventLoopGroup -> IOUringServerSocketChannel::class.java - is EpollEventLoopGroup -> EpollServerSocketChannel::class.java - is KQueueEventLoopGroup -> KQueueServerSocketChannel::class.java - is NioEventLoopGroup -> NioServerSocketChannel::class.java - else -> throw IllegalArgumentException("Unknown EventLoopGroup type") + when { + IoUring.isAvailable() -> IoUringServerSocketChannel::class.java + Epoll.isAvailable() -> EpollServerSocketChannel::class.java + KQueue.isAvailable() -> KQueueServerSocketChannel::class.java + else -> NioServerSocketChannel::class.java } networkLog(logger) { "Bootstrap event loop group: ${parentGroup.javaClass.simpleName}" @@ -81,11 +81,6 @@ public class BootstrapFactory( .childOption(ChannelOption.SO_SNDBUF, 65536) .childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, 30_000) .childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, WriteBufferWaterMark(524_288, 2_097_152)) - .also { - if (parentGroup is EpollEventLoopGroup) { - it.childOption(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED) - } - } } private companion object { diff --git a/protocol/osrs-225/osrs-225-api/build.gradle.kts b/protocol/osrs-225/osrs-225-api/build.gradle.kts index 32355592a..b88007f77 100644 --- a/protocol/osrs-225/osrs-225-api/build.gradle.kts +++ b/protocol/osrs-225/osrs-225-api/build.gradle.kts @@ -5,7 +5,7 @@ dependencies { implementation(rootProject.libs.netty.handler) implementation(rootProject.libs.netty.native.epoll) implementation(rootProject.libs.netty.native.kqueue) - implementation(rootProject.libs.netty.incubator.iouring) + implementation(rootProject.libs.netty.iouring) implementation(rootProject.libs.netty.native.macos.dns.resolver) val epollClassifiers = listOf("linux-aarch_64", "linux-x86_64", "linux-riscv64") val kqueueClassifiers = listOf("osx-x86_64") @@ -17,7 +17,7 @@ dependencies { implementation(variantOf(rootProject.libs.netty.native.kqueue) { classifier(classifier) }) } for (classifier in iouringClassifiers) { - implementation(variantOf(rootProject.libs.netty.incubator.iouring) { classifier(classifier) }) + implementation(variantOf(rootProject.libs.netty.iouring) { classifier(classifier) }) } implementation(rootProject.libs.inline.logger) api(projects.protocol) diff --git a/protocol/osrs-225/osrs-225-api/src/main/kotlin/net/rsprot/protocol/api/bootstrap/BootstrapBuilder.kt b/protocol/osrs-225/osrs-225-api/src/main/kotlin/net/rsprot/protocol/api/bootstrap/BootstrapBuilder.kt index 9ab836091..191a1b342 100644 --- a/protocol/osrs-225/osrs-225-api/src/main/kotlin/net/rsprot/protocol/api/bootstrap/BootstrapBuilder.kt +++ b/protocol/osrs-225/osrs-225-api/src/main/kotlin/net/rsprot/protocol/api/bootstrap/BootstrapBuilder.kt @@ -5,21 +5,24 @@ import io.netty.bootstrap.ServerBootstrap import io.netty.buffer.ByteBufAllocator import io.netty.channel.ChannelOption import io.netty.channel.EventLoopGroup +import io.netty.channel.MultiThreadIoEventLoopGroup import io.netty.channel.ServerChannel import io.netty.channel.WriteBufferWaterMark import io.netty.channel.epoll.Epoll -import io.netty.channel.epoll.EpollChannelOption -import io.netty.channel.epoll.EpollEventLoopGroup -import io.netty.channel.epoll.EpollMode +import io.netty.channel.epoll.EpollIoHandler import io.netty.channel.epoll.EpollServerSocketChannel import io.netty.channel.kqueue.KQueue -import io.netty.channel.kqueue.KQueueEventLoopGroup +import io.netty.channel.kqueue.KQueueIoHandler import io.netty.channel.kqueue.KQueueServerSocketChannel -import io.netty.channel.nio.NioEventLoopGroup +import io.netty.channel.nio.NioIoHandler 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 io.netty.channel.uring.IoUring +import io.netty.channel.uring.IoUringIoHandler +import io.netty.channel.uring.IoUringServerSocketChannel +import net.rsprot.protocol.api.bootstrap.BootstrapBuilder.EventLoopGroupType.EPOLL +import net.rsprot.protocol.api.bootstrap.BootstrapBuilder.EventLoopGroupType.IOURING +import net.rsprot.protocol.api.bootstrap.BootstrapBuilder.EventLoopGroupType.KQUEUE +import net.rsprot.protocol.api.bootstrap.BootstrapBuilder.EventLoopGroupType.NIO import net.rsprot.protocol.api.handlers.OutgoingMessageSizeEstimator import java.text.NumberFormat import kotlin.math.max @@ -229,32 +232,36 @@ public class BootstrapBuilder { try { when (type) { EventLoopGroupType.IOURING -> { - if (!IOUring.isAvailable()) { + if (!IoUring.isAvailable()) { continue } - val boss = IOUringEventLoopGroup(bossThreadCount) - val child = IOUringEventLoopGroup(childThreadCount) + val factory = IoUringIoHandler.newFactory() + val boss = MultiThreadIoEventLoopGroup(bossThreadCount, factory) + val child = MultiThreadIoEventLoopGroup(childThreadCount, factory) return boss to child } EventLoopGroupType.EPOLL -> { if (!Epoll.isAvailable()) { continue } - val boss = EpollEventLoopGroup(bossThreadCount) - val child = EpollEventLoopGroup(childThreadCount) + val factory = EpollIoHandler.newFactory() + val boss = MultiThreadIoEventLoopGroup(bossThreadCount, factory) + val child = MultiThreadIoEventLoopGroup(childThreadCount, factory) return boss to child } EventLoopGroupType.KQUEUE -> { if (!KQueue.isAvailable()) { continue } - val boss = KQueueEventLoopGroup(bossThreadCount) - val child = KQueueEventLoopGroup(childThreadCount) + val factory = KQueueIoHandler.newFactory() + val boss = MultiThreadIoEventLoopGroup(bossThreadCount, factory) + val child = MultiThreadIoEventLoopGroup(childThreadCount, factory) return boss to child } EventLoopGroupType.NIO -> { - val boss = NioEventLoopGroup(bossThreadCount) - val child = NioEventLoopGroup(childThreadCount) + val factory = NioIoHandler.newFactory() + val boss = MultiThreadIoEventLoopGroup(bossThreadCount, factory) + val child = MultiThreadIoEventLoopGroup(childThreadCount, factory) return boss to child } } @@ -270,13 +277,12 @@ public class BootstrapBuilder { throw IllegalStateException("No event loop groups are available in ${groupTypes.contentDeepToString()}") } - private fun determineSocketChannel(loopGroup: EventLoopGroup): Class = - when (loopGroup) { - is IOUringEventLoopGroup -> IOUringServerSocketChannel::class.java - is EpollEventLoopGroup -> EpollServerSocketChannel::class.java - is KQueueEventLoopGroup -> KQueueServerSocketChannel::class.java - is NioEventLoopGroup -> NioServerSocketChannel::class.java - else -> throw IllegalArgumentException("Unknown EventLoopGroup type: $loopGroup") + private fun determineSocketChannel(): Class = + when { + IoUring.isAvailable() -> IoUringServerSocketChannel::class.java + Epoll.isAvailable() -> EpollServerSocketChannel::class.java + KQueue.isAvailable() -> KQueueServerSocketChannel::class.java + else -> NioServerSocketChannel::class.java } /** @@ -293,7 +299,7 @@ public class BootstrapBuilder { childThreadCount, groupTypes, ) - val channel = determineSocketChannel(bossGroup) + val channel = determineSocketChannel() log { "Using event loop group: ${bossGroup.javaClass.simpleName} " + "(bossThreads: $bossThreadCount, childThreads: $childThreadCount)" @@ -330,10 +336,6 @@ public class BootstrapBuilder { bootstrap.childOption(ChannelOption.TCP_NODELAY, tcpNoDelay) log { "Nagle's algorithm (TCP no delay): ${if (tcpNoDelay) "disabled" else "enabled"}" } bootstrap.childOption(ChannelOption.MESSAGE_SIZE_ESTIMATOR, estimator) - if (bossGroup is EpollEventLoopGroup) { - bootstrap.childOption(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED) - log { "Using level-triggered Epoll mode." } - } return bootstrap } diff --git a/protocol/osrs-226/osrs-226-api/build.gradle.kts b/protocol/osrs-226/osrs-226-api/build.gradle.kts index 2115b9546..dd186849c 100644 --- a/protocol/osrs-226/osrs-226-api/build.gradle.kts +++ b/protocol/osrs-226/osrs-226-api/build.gradle.kts @@ -5,7 +5,7 @@ dependencies { implementation(rootProject.libs.netty.handler) implementation(rootProject.libs.netty.native.epoll) implementation(rootProject.libs.netty.native.kqueue) - implementation(rootProject.libs.netty.incubator.iouring) + implementation(rootProject.libs.netty.iouring) implementation(rootProject.libs.netty.native.macos.dns.resolver) val epollClassifiers = listOf("linux-aarch_64", "linux-x86_64", "linux-riscv64") val kqueueClassifiers = listOf("osx-x86_64") @@ -17,7 +17,7 @@ dependencies { implementation(variantOf(rootProject.libs.netty.native.kqueue) { classifier(classifier) }) } for (classifier in iouringClassifiers) { - implementation(variantOf(rootProject.libs.netty.incubator.iouring) { classifier(classifier) }) + implementation(variantOf(rootProject.libs.netty.iouring) { classifier(classifier) }) } implementation(rootProject.libs.inline.logger) api(projects.protocol) diff --git a/protocol/osrs-226/osrs-226-api/src/main/kotlin/net/rsprot/protocol/api/bootstrap/BootstrapBuilder.kt b/protocol/osrs-226/osrs-226-api/src/main/kotlin/net/rsprot/protocol/api/bootstrap/BootstrapBuilder.kt index 9ab836091..191a1b342 100644 --- a/protocol/osrs-226/osrs-226-api/src/main/kotlin/net/rsprot/protocol/api/bootstrap/BootstrapBuilder.kt +++ b/protocol/osrs-226/osrs-226-api/src/main/kotlin/net/rsprot/protocol/api/bootstrap/BootstrapBuilder.kt @@ -5,21 +5,24 @@ import io.netty.bootstrap.ServerBootstrap import io.netty.buffer.ByteBufAllocator import io.netty.channel.ChannelOption import io.netty.channel.EventLoopGroup +import io.netty.channel.MultiThreadIoEventLoopGroup import io.netty.channel.ServerChannel import io.netty.channel.WriteBufferWaterMark import io.netty.channel.epoll.Epoll -import io.netty.channel.epoll.EpollChannelOption -import io.netty.channel.epoll.EpollEventLoopGroup -import io.netty.channel.epoll.EpollMode +import io.netty.channel.epoll.EpollIoHandler import io.netty.channel.epoll.EpollServerSocketChannel import io.netty.channel.kqueue.KQueue -import io.netty.channel.kqueue.KQueueEventLoopGroup +import io.netty.channel.kqueue.KQueueIoHandler import io.netty.channel.kqueue.KQueueServerSocketChannel -import io.netty.channel.nio.NioEventLoopGroup +import io.netty.channel.nio.NioIoHandler 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 io.netty.channel.uring.IoUring +import io.netty.channel.uring.IoUringIoHandler +import io.netty.channel.uring.IoUringServerSocketChannel +import net.rsprot.protocol.api.bootstrap.BootstrapBuilder.EventLoopGroupType.EPOLL +import net.rsprot.protocol.api.bootstrap.BootstrapBuilder.EventLoopGroupType.IOURING +import net.rsprot.protocol.api.bootstrap.BootstrapBuilder.EventLoopGroupType.KQUEUE +import net.rsprot.protocol.api.bootstrap.BootstrapBuilder.EventLoopGroupType.NIO import net.rsprot.protocol.api.handlers.OutgoingMessageSizeEstimator import java.text.NumberFormat import kotlin.math.max @@ -229,32 +232,36 @@ public class BootstrapBuilder { try { when (type) { EventLoopGroupType.IOURING -> { - if (!IOUring.isAvailable()) { + if (!IoUring.isAvailable()) { continue } - val boss = IOUringEventLoopGroup(bossThreadCount) - val child = IOUringEventLoopGroup(childThreadCount) + val factory = IoUringIoHandler.newFactory() + val boss = MultiThreadIoEventLoopGroup(bossThreadCount, factory) + val child = MultiThreadIoEventLoopGroup(childThreadCount, factory) return boss to child } EventLoopGroupType.EPOLL -> { if (!Epoll.isAvailable()) { continue } - val boss = EpollEventLoopGroup(bossThreadCount) - val child = EpollEventLoopGroup(childThreadCount) + val factory = EpollIoHandler.newFactory() + val boss = MultiThreadIoEventLoopGroup(bossThreadCount, factory) + val child = MultiThreadIoEventLoopGroup(childThreadCount, factory) return boss to child } EventLoopGroupType.KQUEUE -> { if (!KQueue.isAvailable()) { continue } - val boss = KQueueEventLoopGroup(bossThreadCount) - val child = KQueueEventLoopGroup(childThreadCount) + val factory = KQueueIoHandler.newFactory() + val boss = MultiThreadIoEventLoopGroup(bossThreadCount, factory) + val child = MultiThreadIoEventLoopGroup(childThreadCount, factory) return boss to child } EventLoopGroupType.NIO -> { - val boss = NioEventLoopGroup(bossThreadCount) - val child = NioEventLoopGroup(childThreadCount) + val factory = NioIoHandler.newFactory() + val boss = MultiThreadIoEventLoopGroup(bossThreadCount, factory) + val child = MultiThreadIoEventLoopGroup(childThreadCount, factory) return boss to child } } @@ -270,13 +277,12 @@ public class BootstrapBuilder { throw IllegalStateException("No event loop groups are available in ${groupTypes.contentDeepToString()}") } - private fun determineSocketChannel(loopGroup: EventLoopGroup): Class = - when (loopGroup) { - is IOUringEventLoopGroup -> IOUringServerSocketChannel::class.java - is EpollEventLoopGroup -> EpollServerSocketChannel::class.java - is KQueueEventLoopGroup -> KQueueServerSocketChannel::class.java - is NioEventLoopGroup -> NioServerSocketChannel::class.java - else -> throw IllegalArgumentException("Unknown EventLoopGroup type: $loopGroup") + private fun determineSocketChannel(): Class = + when { + IoUring.isAvailable() -> IoUringServerSocketChannel::class.java + Epoll.isAvailable() -> EpollServerSocketChannel::class.java + KQueue.isAvailable() -> KQueueServerSocketChannel::class.java + else -> NioServerSocketChannel::class.java } /** @@ -293,7 +299,7 @@ public class BootstrapBuilder { childThreadCount, groupTypes, ) - val channel = determineSocketChannel(bossGroup) + val channel = determineSocketChannel() log { "Using event loop group: ${bossGroup.javaClass.simpleName} " + "(bossThreads: $bossThreadCount, childThreads: $childThreadCount)" @@ -330,10 +336,6 @@ public class BootstrapBuilder { bootstrap.childOption(ChannelOption.TCP_NODELAY, tcpNoDelay) log { "Nagle's algorithm (TCP no delay): ${if (tcpNoDelay) "disabled" else "enabled"}" } bootstrap.childOption(ChannelOption.MESSAGE_SIZE_ESTIMATOR, estimator) - if (bossGroup is EpollEventLoopGroup) { - bootstrap.childOption(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED) - log { "Using level-triggered Epoll mode." } - } return bootstrap } diff --git a/protocol/osrs-227/osrs-227-api/build.gradle.kts b/protocol/osrs-227/osrs-227-api/build.gradle.kts index e3252c8a3..28b5ef320 100644 --- a/protocol/osrs-227/osrs-227-api/build.gradle.kts +++ b/protocol/osrs-227/osrs-227-api/build.gradle.kts @@ -5,7 +5,7 @@ dependencies { implementation(rootProject.libs.netty.handler) implementation(rootProject.libs.netty.native.epoll) implementation(rootProject.libs.netty.native.kqueue) - implementation(rootProject.libs.netty.incubator.iouring) + implementation(rootProject.libs.netty.iouring) implementation(rootProject.libs.netty.native.macos.dns.resolver) val epollClassifiers = listOf("linux-aarch_64", "linux-x86_64", "linux-riscv64") val kqueueClassifiers = listOf("osx-x86_64") @@ -17,7 +17,7 @@ dependencies { implementation(variantOf(rootProject.libs.netty.native.kqueue) { classifier(classifier) }) } for (classifier in iouringClassifiers) { - implementation(variantOf(rootProject.libs.netty.incubator.iouring) { classifier(classifier) }) + implementation(variantOf(rootProject.libs.netty.iouring) { classifier(classifier) }) } implementation(rootProject.libs.inline.logger) api(projects.protocol) diff --git a/protocol/osrs-227/osrs-227-api/src/main/kotlin/net/rsprot/protocol/api/bootstrap/BootstrapBuilder.kt b/protocol/osrs-227/osrs-227-api/src/main/kotlin/net/rsprot/protocol/api/bootstrap/BootstrapBuilder.kt index 9ab836091..191a1b342 100644 --- a/protocol/osrs-227/osrs-227-api/src/main/kotlin/net/rsprot/protocol/api/bootstrap/BootstrapBuilder.kt +++ b/protocol/osrs-227/osrs-227-api/src/main/kotlin/net/rsprot/protocol/api/bootstrap/BootstrapBuilder.kt @@ -5,21 +5,24 @@ import io.netty.bootstrap.ServerBootstrap import io.netty.buffer.ByteBufAllocator import io.netty.channel.ChannelOption import io.netty.channel.EventLoopGroup +import io.netty.channel.MultiThreadIoEventLoopGroup import io.netty.channel.ServerChannel import io.netty.channel.WriteBufferWaterMark import io.netty.channel.epoll.Epoll -import io.netty.channel.epoll.EpollChannelOption -import io.netty.channel.epoll.EpollEventLoopGroup -import io.netty.channel.epoll.EpollMode +import io.netty.channel.epoll.EpollIoHandler import io.netty.channel.epoll.EpollServerSocketChannel import io.netty.channel.kqueue.KQueue -import io.netty.channel.kqueue.KQueueEventLoopGroup +import io.netty.channel.kqueue.KQueueIoHandler import io.netty.channel.kqueue.KQueueServerSocketChannel -import io.netty.channel.nio.NioEventLoopGroup +import io.netty.channel.nio.NioIoHandler 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 io.netty.channel.uring.IoUring +import io.netty.channel.uring.IoUringIoHandler +import io.netty.channel.uring.IoUringServerSocketChannel +import net.rsprot.protocol.api.bootstrap.BootstrapBuilder.EventLoopGroupType.EPOLL +import net.rsprot.protocol.api.bootstrap.BootstrapBuilder.EventLoopGroupType.IOURING +import net.rsprot.protocol.api.bootstrap.BootstrapBuilder.EventLoopGroupType.KQUEUE +import net.rsprot.protocol.api.bootstrap.BootstrapBuilder.EventLoopGroupType.NIO import net.rsprot.protocol.api.handlers.OutgoingMessageSizeEstimator import java.text.NumberFormat import kotlin.math.max @@ -229,32 +232,36 @@ public class BootstrapBuilder { try { when (type) { EventLoopGroupType.IOURING -> { - if (!IOUring.isAvailable()) { + if (!IoUring.isAvailable()) { continue } - val boss = IOUringEventLoopGroup(bossThreadCount) - val child = IOUringEventLoopGroup(childThreadCount) + val factory = IoUringIoHandler.newFactory() + val boss = MultiThreadIoEventLoopGroup(bossThreadCount, factory) + val child = MultiThreadIoEventLoopGroup(childThreadCount, factory) return boss to child } EventLoopGroupType.EPOLL -> { if (!Epoll.isAvailable()) { continue } - val boss = EpollEventLoopGroup(bossThreadCount) - val child = EpollEventLoopGroup(childThreadCount) + val factory = EpollIoHandler.newFactory() + val boss = MultiThreadIoEventLoopGroup(bossThreadCount, factory) + val child = MultiThreadIoEventLoopGroup(childThreadCount, factory) return boss to child } EventLoopGroupType.KQUEUE -> { if (!KQueue.isAvailable()) { continue } - val boss = KQueueEventLoopGroup(bossThreadCount) - val child = KQueueEventLoopGroup(childThreadCount) + val factory = KQueueIoHandler.newFactory() + val boss = MultiThreadIoEventLoopGroup(bossThreadCount, factory) + val child = MultiThreadIoEventLoopGroup(childThreadCount, factory) return boss to child } EventLoopGroupType.NIO -> { - val boss = NioEventLoopGroup(bossThreadCount) - val child = NioEventLoopGroup(childThreadCount) + val factory = NioIoHandler.newFactory() + val boss = MultiThreadIoEventLoopGroup(bossThreadCount, factory) + val child = MultiThreadIoEventLoopGroup(childThreadCount, factory) return boss to child } } @@ -270,13 +277,12 @@ public class BootstrapBuilder { throw IllegalStateException("No event loop groups are available in ${groupTypes.contentDeepToString()}") } - private fun determineSocketChannel(loopGroup: EventLoopGroup): Class = - when (loopGroup) { - is IOUringEventLoopGroup -> IOUringServerSocketChannel::class.java - is EpollEventLoopGroup -> EpollServerSocketChannel::class.java - is KQueueEventLoopGroup -> KQueueServerSocketChannel::class.java - is NioEventLoopGroup -> NioServerSocketChannel::class.java - else -> throw IllegalArgumentException("Unknown EventLoopGroup type: $loopGroup") + private fun determineSocketChannel(): Class = + when { + IoUring.isAvailable() -> IoUringServerSocketChannel::class.java + Epoll.isAvailable() -> EpollServerSocketChannel::class.java + KQueue.isAvailable() -> KQueueServerSocketChannel::class.java + else -> NioServerSocketChannel::class.java } /** @@ -293,7 +299,7 @@ public class BootstrapBuilder { childThreadCount, groupTypes, ) - val channel = determineSocketChannel(bossGroup) + val channel = determineSocketChannel() log { "Using event loop group: ${bossGroup.javaClass.simpleName} " + "(bossThreads: $bossThreadCount, childThreads: $childThreadCount)" @@ -330,10 +336,6 @@ public class BootstrapBuilder { bootstrap.childOption(ChannelOption.TCP_NODELAY, tcpNoDelay) log { "Nagle's algorithm (TCP no delay): ${if (tcpNoDelay) "disabled" else "enabled"}" } bootstrap.childOption(ChannelOption.MESSAGE_SIZE_ESTIMATOR, estimator) - if (bossGroup is EpollEventLoopGroup) { - bootstrap.childOption(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED) - log { "Using level-triggered Epoll mode." } - } return bootstrap }