Compare commits

...

1 Commits

Author SHA1 Message Date
66ab357d91 added epoll native transport for server 2025-02-05 21:01:49 +08:00
11 changed files with 62 additions and 9 deletions

View File

@@ -27,6 +27,7 @@ public class Configuration {
Cache cache; Cache cache;
Authentication authentication; Authentication authentication;
Tls tls; Tls tls;
boolean useNativeTransport;
@Value @Value
public static class EventExecutor { public static class EventExecutor {
@@ -151,7 +152,8 @@ public class Configuration {
Map<String, Group> groups, Map<String, Group> groups,
Cache cache, Cache cache,
Authentication authentication, Authentication authentication,
Tls tls Tls tls,
boolean useNativeTransport
) { ) {
return new Configuration( return new Configuration(
host, host,
@@ -164,7 +166,8 @@ public class Configuration {
groups, groups,
cache, cache,
authentication, authentication,
tls tls,
useNativeTransport
); );
} }
} }

View File

@@ -32,6 +32,13 @@ configurations {
canBeResolved = true canBeResolved = true
visible = true visible = true
} }
nativeLibraries {
transitive = false
canBeConsumed = false
canBeResolved = true
visible = false
}
} }
envelopeJar { envelopeJar {
@@ -53,6 +60,8 @@ dependencies {
// runtimeOnly catalog.slf4j.jdk14 // runtimeOnly catalog.slf4j.jdk14
runtimeOnly catalog.logback.classic runtimeOnly catalog.logback.classic
// runtimeOnly catalog.slf4j.simple // runtimeOnly catalog.slf4j.simple
nativeLibraries group: 'io.netty', name: 'netty-transport-native-epoll', version: catalog.versions.netty.get(), classifier: 'linux-x86_64'
} }
Provider<EnvelopeJarTask> envelopeJarTaskProvider = tasks.named('envelopeJar', EnvelopeJarTask.class) { Provider<EnvelopeJarTask> envelopeJarTaskProvider = tasks.named('envelopeJar', EnvelopeJarTask.class) {
@@ -67,6 +76,9 @@ Provider<EnvelopeJarTask> envelopeJarTaskProvider = tasks.named('envelopeJar', E
// systemProperties['org.slf4j.simpleLogger.log.com.google.code.yanf4j'] = 'warn' // systemProperties['org.slf4j.simpleLogger.log.com.google.code.yanf4j'] = 'warn'
// systemProperties['org.slf4j.simpleLogger.log.net.rubyeye.xmemcached'] = 'warn' // systemProperties['org.slf4j.simpleLogger.log.net.rubyeye.xmemcached'] = 'warn'
// systemProperties['org.slf4j.simpleLogger.dateTimeFormat'] = 'yyyy-MM-dd\'T\'HH:mm:ss.SSSZ' // systemProperties['org.slf4j.simpleLogger.dateTimeFormat'] = 'yyyy-MM-dd\'T\'HH:mm:ss.SSSZ'
from {
configurations.nativeLibraries.collect { it.isDirectory() ? it : zipTree(it) }
}
} }
tasks.named(NativeImagePlugin.CONFIGURE_NATIVE_IMAGE_TASK_NAME, NativeImageConfigurationTask) { tasks.named(NativeImagePlugin.CONFIGURE_NATIVE_IMAGE_TASK_NAME, NativeImageConfigurationTask) {

View File

@@ -18,6 +18,7 @@ module net.woggioni.gbcs.server {
requires net.woggioni.jwo; requires net.woggioni.jwo;
requires net.woggioni.gbcs.common; requires net.woggioni.gbcs.common;
requires net.woggioni.gbcs.api; requires net.woggioni.gbcs.api;
requires io.netty.transport.classes.epoll;
exports net.woggioni.gbcs.server; exports net.woggioni.gbcs.server;

View File

@@ -10,6 +10,9 @@ import io.netty.channel.ChannelInboundHandlerAdapter
import io.netty.channel.ChannelInitializer import io.netty.channel.ChannelInitializer
import io.netty.channel.ChannelOption import io.netty.channel.ChannelOption
import io.netty.channel.ChannelPromise import io.netty.channel.ChannelPromise
import io.netty.channel.MultithreadEventLoopGroup
import io.netty.channel.epoll.EpollEventLoopGroup
import io.netty.channel.epoll.EpollServerSocketChannel
import io.netty.channel.nio.NioEventLoopGroup import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.nio.NioServerSocketChannel import io.netty.channel.socket.nio.NioServerSocketChannel
import io.netty.handler.codec.compression.CompressionOptions import io.netty.handler.codec.compression.CompressionOptions
@@ -49,6 +52,7 @@ import net.woggioni.gbcs.server.exception.ExceptionHandler
import net.woggioni.gbcs.server.handler.ServerHandler import net.woggioni.gbcs.server.handler.ServerHandler
import net.woggioni.gbcs.server.throttling.ThrottlingHandler import net.woggioni.gbcs.server.throttling.ThrottlingHandler
import net.woggioni.jwo.JWO import net.woggioni.jwo.JWO
import net.woggioni.jwo.OS
import net.woggioni.jwo.Tuple2 import net.woggioni.jwo.Tuple2
import java.io.OutputStream import java.io.OutputStream
import java.net.InetSocketAddress import java.net.InetSocketAddress
@@ -399,10 +403,23 @@ class GradleBuildCacheServer(private val cfg: Configuration) {
} }
fun run(): ServerHandle { fun run(): ServerHandle {
// Create the multithreaded event loops for the server val bossGroup : MultithreadEventLoopGroup
val bossGroup = NioEventLoopGroup(1) val workerGroup : MultithreadEventLoopGroup
val serverSocketChannel = NioServerSocketChannel::class.java val serverSocketChannel : Class<*>
val workerGroup = NioEventLoopGroup(0) if(cfg.isUseNativeTransport) {
if(OS.isLinux) {
bossGroup = EpollEventLoopGroup(1)
serverSocketChannel = EpollServerSocketChannel::class.java
workerGroup = EpollEventLoopGroup(0)
} else {
throw java.lang.IllegalArgumentException("Native transport is not supported on ${OS.current.name}")
}
} else {
bossGroup = NioEventLoopGroup(1)
serverSocketChannel = NioServerSocketChannel::class.java
workerGroup = NioEventLoopGroup(0)
}
val eventExecutorGroup = run { val eventExecutorGroup = run {
val threadFactory = if (cfg.eventExecutor.isUseVirtualThreads) { val threadFactory = if (cfg.eventExecutor.isUseVirtualThreads) {
Thread.ofVirtual().factory() Thread.ofVirtual().factory()

View File

@@ -44,6 +44,7 @@ object Parser {
val serverPath = root.renderAttribute("path") val serverPath = root.renderAttribute("path")
var incomingConnectionsBacklogSize = 1024 var incomingConnectionsBacklogSize = 1024
var authentication: Authentication? = null var authentication: Authentication? = null
var useNativeTransport = false
for (child in root.asIterable()) { for (child in root.asIterable()) {
val tagName = child.localName val tagName = child.localName
when (tagName) { when (tagName) {
@@ -136,7 +137,7 @@ object Parser {
} }
"event-executor" -> { "event-executor" -> {
val useVirtualThread = root.renderAttribute("use-virtual-threads") val useVirtualThread = child.renderAttribute("use-virtual-threads")
?.let(String::toBoolean) ?: true ?.let(String::toBoolean) ?: true
eventExecutor = Configuration.EventExecutor(useVirtualThread) eventExecutor = Configuration.EventExecutor(useVirtualThread)
} }
@@ -180,6 +181,10 @@ object Parser {
} }
tls = Tls(keyStore, trustStore) tls = Tls(keyStore, trustStore)
} }
"transport" -> {
useNativeTransport = child.renderAttribute("use-native-transport")
?.let(String::toBoolean) ?: false
}
} }
} }
return Configuration.of( return Configuration.of(
@@ -194,6 +199,7 @@ object Parser {
cache!!, cache!!,
authentication, authentication,
tls, tls,
useNativeTransport
) )
} }

View File

@@ -44,8 +44,12 @@ object Serializer {
attr("max-request-size", connection.maxRequestSize.toString()) attr("max-request-size", connection.maxRequestSize.toString())
} }
} }
node("transport") {
attr("use-native-transport", conf.isUseNativeTransport.toString())
}
node("event-executor") { node("event-executor") {
attr("use-virtual-threads", conf.eventExecutor.isUseVirtualThreads.toString()) attr("use-virtual-threads", conf.eventExecutor.isUseVirtualThreads.toString())
attr("use-virtual-threads", conf.eventExecutor.isUseVirtualThreads.toString())
} }
val cache = conf.cache val cache = conf.cache
val serializer : CacheProvider<Configuration.Cache> = val serializer : CacheProvider<Configuration.Cache> =

View File

@@ -9,6 +9,7 @@
<xs:sequence minOccurs="0"> <xs:sequence minOccurs="0">
<xs:element name="bind" type="gbcs:bindType" maxOccurs="1"/> <xs:element name="bind" type="gbcs:bindType" maxOccurs="1"/>
<xs:element name="connection" type="gbcs:connectionType" minOccurs="0" maxOccurs="1"/> <xs:element name="connection" type="gbcs:connectionType" minOccurs="0" maxOccurs="1"/>
<xs:element name="transport" type="gbcs:transportType" minOccurs="0" maxOccurs="1"/>
<xs:element name="event-executor" type="gbcs:eventExecutorType" minOccurs="0" maxOccurs="1"/> <xs:element name="event-executor" type="gbcs:eventExecutorType" minOccurs="0" maxOccurs="1"/>
<xs:element name="cache" type="gbcs:cacheType" maxOccurs="1"/> <xs:element name="cache" type="gbcs:cacheType" maxOccurs="1"/>
<xs:element name="authorization" type="gbcs:authorizationType" minOccurs="0"> <xs:element name="authorization" type="gbcs:authorizationType" minOccurs="0">
@@ -42,6 +43,10 @@
<xs:attribute name="max-request-size" type="xs:unsignedInt" use="optional" default="67108864"/> <xs:attribute name="max-request-size" type="xs:unsignedInt" use="optional" default="67108864"/>
</xs:complexType> </xs:complexType>
<xs:complexType name="transportType">
<xs:attribute name="use-native-transport" type="xs:boolean" use="optional" default="false"/>
</xs:complexType>
<xs:complexType name="eventExecutorType"> <xs:complexType name="eventExecutorType">
<xs:attribute name="use-virtual-threads" type="xs:boolean" use="optional" default="true"/> <xs:attribute name="use-virtual-threads" type="xs:boolean" use="optional" default="true"/>
</xs:complexType> </xs:complexType>

View File

@@ -55,6 +55,7 @@ abstract class AbstractBasicAuthServerTest : AbstractServerTest() {
), ),
Configuration.BasicAuthentication(), Configuration.BasicAuthentication(),
null, null,
false,
) )
Xml.write(Serializer.serialize(cfg), System.out) Xml.write(Serializer.serialize(cfg), System.out)
} }

View File

@@ -171,7 +171,8 @@ abstract class AbstractTlsServerTest : AbstractServerTest() {
Configuration.Tls( Configuration.Tls(
Configuration.KeyStore(this.serverKeyStoreFile, null, SERVER_CERTIFICATE_ENTRY, PASSWORD), Configuration.KeyStore(this.serverKeyStoreFile, null, SERVER_CERTIFICATE_ENTRY, PASSWORD),
Configuration.TrustStore(this.trustStoreFile, null, false, false), Configuration.TrustStore(this.trustStoreFile, null, false, false),
) ),
false
) )
Xml.write(Serializer.serialize(cfg), System.out) Xml.write(Serializer.serialize(cfg), System.out)
} }

View File

@@ -51,10 +51,12 @@ class NoAuthServerTest : AbstractServerTest() {
maxAge = Duration.ofSeconds(3600 * 24), maxAge = Duration.ofSeconds(3600 * 24),
compressionEnabled = true, compressionEnabled = true,
digestAlgorithm = "MD5", digestAlgorithm = "MD5",
compressionLevel = Deflater.DEFAULT_COMPRESSION compressionLevel = Deflater.DEFAULT_COMPRESSION,
maxSize = 0x1000000
), ),
null, null,
null, null,
false,
) )
Xml.write(Serializer.serialize(cfg), System.out) Xml.write(Serializer.serialize(cfg), System.out)
} }

View File

@@ -10,6 +10,7 @@
write-idle-timeout="PT11M" write-idle-timeout="PT11M"
idle-timeout="PT30M" idle-timeout="PT30M"
max-request-size="101325"/> max-request-size="101325"/>
<transport use-native-transport="true"/>
<event-executor use-virtual-threads="false"/> <event-executor use-virtual-threads="false"/>
<cache xs:type="gbcs:fileSystemCacheType" path="/tmp/gbcs" max-age="P7D"/> <cache xs:type="gbcs:fileSystemCacheType" path="/tmp/gbcs" max-age="P7D"/>
<authentication> <authentication>