This is an automated email from the ASF dual-hosted git repository.
wenbingshen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/bookkeeper.git
The following commit(s) were added to refs/heads/master by this push:
new a61a6305db Support bookie server config tcp keep-alive (#4762)
a61a6305db is described below
commit a61a6305db0ba5b4fe84dac83a0435a94d37c23b
Author: xiaolong ran <[email protected]>
AuthorDate: Tue Apr 28 19:47:49 2026 +0800
Support bookie server config tcp keep-alive (#4762)
* Support bookie server config tcp keep-alive
Signed-off-by: xiaolongran <[email protected]>
* fix comments
Signed-off-by: xiaolongran <[email protected]>
* fix comments
Signed-off-by: xiaolongran <[email protected]>
---------
Signed-off-by: xiaolongran <[email protected]>
---
.../bookkeeper/conf/ServerConfiguration.java | 66 ++++++++
.../apache/bookkeeper/proto/BookieNettyServer.java | 45 +++--
.../bookkeeper/proto/PerChannelBookieClient.java | 11 ++
.../proto/TestBookieNettyServerTcpKeepalive.java | 187 +++++++++++++++++++++
.../TestPerChannelBookieClientTcpKeepalive.java | 89 +++++++++-
5 files changed, 378 insertions(+), 20 deletions(-)
diff --git
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/ServerConfiguration.java
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/ServerConfiguration.java
index 4f95443e31..a6ce37874d 100644
---
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/ServerConfiguration.java
+++
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/ServerConfiguration.java
@@ -178,6 +178,9 @@ public class ServerConfiguration extends
AbstractConfiguration<ServerConfigurati
// NIO and Netty Parameters
protected static final String SERVER_TCP_NODELAY = "serverTcpNoDelay";
protected static final String SERVER_SOCK_KEEPALIVE =
"serverSockKeepalive";
+ protected static final String SERVER_TCP_KEEPIDLE = "serverTcpKeepIdle";
+ protected static final String SERVER_TCP_KEEPINTVL = "serverTcpKeepIntvl";
+ protected static final String SERVER_TCP_KEEPCNT = "serverTcpKeepCnt";
protected static final String SERVER_SOCK_LINGER = "serverTcpLinger";
protected static final String SERVER_WRITEBUFFER_LOW_WATER_MARK =
"serverWriteBufferLowWaterMark";
protected static final String SERVER_WRITEBUFFER_HIGH_WATER_MARK =
"serverWriteBufferHighWaterMark";
@@ -1627,6 +1630,69 @@ public class ServerConfiguration extends
AbstractConfiguration<ServerConfigurati
return this;
}
+ /**
+ * Set TCP_KEEPIDLE value for SO_KEEPALIVE.
+ *
+ * @param keepIdle
+ * TCP_KEEPIDLE value in seconds
+ * @return server configuration
+ */
+ public ServerConfiguration setServerTcpKeepIdle(int keepIdle) {
+ setProperty(SERVER_TCP_KEEPIDLE, keepIdle);
+ return this;
+ }
+
+ /**
+ * Get TCP_KEEPIDLE value for SO_KEEPALIVE.
+ *
+ * @return TCP_KEEPIDLE value in seconds, default -1
+ */
+ public int getServerTcpKeepIdle() {
+ return getInt(SERVER_TCP_KEEPIDLE, -1);
+ }
+
+ /**
+ * Set TCP_KEEPINTVL value for SO_KEEPALIVE.
+ *
+ * @param keepIntvl
+ * TCP_KEEPINTVL value in seconds
+ * @return server configuration
+ */
+ public ServerConfiguration setServerTcpKeepIntvl(int keepIntvl) {
+ setProperty(SERVER_TCP_KEEPINTVL, keepIntvl);
+ return this;
+ }
+
+ /**
+ * Get TCP_KEEPINTVL value for SO_KEEPALIVE.
+ *
+ * @return TCP_KEEPINTVL value in seconds, default -1
+ */
+ public int getServerTcpKeepIntvl() {
+ return getInt(SERVER_TCP_KEEPINTVL, -1);
+ }
+
+ /**
+ * Set TCP_KEEPCNT value for SO_KEEPALIVE.
+ *
+ * @param keepCnt
+ * TCP_KEEPCNT value
+ * @return server configuration
+ */
+ public ServerConfiguration setServerTcpKeepCnt(int keepCnt) {
+ setProperty(SERVER_TCP_KEEPCNT, keepCnt);
+ return this;
+ }
+
+ /**
+ * Get TCP_KEEPCNT value for SO_KEEPALIVE.
+ *
+ * @return TCP_KEEPCNT value, default -1
+ */
+ public int getServerTcpKeepCnt() {
+ return getInt(SERVER_TCP_KEEPCNT, -1);
+ }
+
/**
* Get zookeeper client backoff retry start time in millis.
*
diff --git
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BookieNettyServer.java
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BookieNettyServer.java
index 0bd8e9a179..56218286a1 100644
---
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BookieNettyServer.java
+++
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BookieNettyServer.java
@@ -38,6 +38,7 @@ import io.netty.channel.DefaultEventLoopGroup;
import io.netty.channel.EventLoop;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.WriteBufferWaterMark;
+import io.netty.channel.epoll.EpollChannelOption;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.group.ChannelGroup;
@@ -48,6 +49,7 @@ import io.netty.channel.local.LocalChannel;
import io.netty.channel.local.LocalServerChannel;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.channel.uring.IoUringChannelOption;
import io.netty.channel.uring.IoUringServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.flush.FlushConsolidationHandler;
@@ -316,6 +318,7 @@ class BookieNettyServer {
bootstrap.childOption(ChannelOption.ALLOCATOR, allocator);
bootstrap.group(acceptorGroup, eventLoopGroup);
bootstrap.childOption(ChannelOption.TCP_NODELAY,
conf.getServerTcpNoDelay());
+ bootstrap.childOption(ChannelOption.SO_KEEPALIVE,
conf.getServerSockKeepalive());
bootstrap.childOption(ChannelOption.SO_LINGER,
conf.getServerSockLinger());
bootstrap.childOption(ChannelOption.RCVBUF_ALLOCATOR,
new
AdaptiveRecvByteBufAllocator(conf.getRecvByteBufAllocatorSizeMin(),
@@ -323,6 +326,32 @@ class BookieNettyServer {
bootstrap.childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, new
WriteBufferWaterMark(
conf.getServerWriteBufferLowWaterMark(),
conf.getServerWriteBufferHighWaterMark()));
+ // Set TCP keepalive parameters if configured. Use childOption()
so that these
+ // options are applied to each accepted SocketChannel (not the
listening
+ // ServerSocketChannel), which is the Netty-idiomatic approach and
avoids
+ // relying on OS-level socket option inheritance behavior.
+ if (EventLoopUtil.isIoUringGroup(eventLoopGroup)) {
+ if (conf.getServerTcpKeepIdle() > 0) {
+ bootstrap.childOption(IoUringChannelOption.TCP_KEEPIDLE,
conf.getServerTcpKeepIdle());
+ }
+ if (conf.getServerTcpKeepIntvl() > 0) {
+ bootstrap.childOption(IoUringChannelOption.TCP_KEEPINTVL,
conf.getServerTcpKeepIntvl());
+ }
+ if (conf.getServerTcpKeepCnt() > 0) {
+ bootstrap.childOption(IoUringChannelOption.TCP_KEEPCNT,
conf.getServerTcpKeepCnt());
+ }
+ } else if (eventLoopGroup instanceof EpollEventLoopGroup) {
+ if (conf.getServerTcpKeepIdle() > 0) {
+ bootstrap.childOption(EpollChannelOption.TCP_KEEPIDLE,
conf.getServerTcpKeepIdle());
+ }
+ if (conf.getServerTcpKeepIntvl() > 0) {
+ bootstrap.childOption(EpollChannelOption.TCP_KEEPINTVL,
conf.getServerTcpKeepIntvl());
+ }
+ if (conf.getServerTcpKeepCnt() > 0) {
+ bootstrap.childOption(EpollChannelOption.TCP_KEEPCNT,
conf.getServerTcpKeepCnt());
+ }
+ }
+
if (EventLoopUtil.isIoUringGroup(eventLoopGroup)) {
bootstrap.channel(IoUringServerSocketChannel.class);
} else if (eventLoopGroup instanceof EpollEventLoopGroup) {
@@ -382,24 +411,16 @@ class BookieNettyServer {
ServerBootstrap jvmBootstrap = new ServerBootstrap();
jvmBootstrap.childOption(ChannelOption.ALLOCATOR, new
PooledByteBufAllocator(true));
jvmBootstrap.group(jvmEventLoopGroup, jvmEventLoopGroup);
- jvmBootstrap.childOption(ChannelOption.TCP_NODELAY,
conf.getServerTcpNoDelay());
- jvmBootstrap.childOption(ChannelOption.SO_KEEPALIVE,
conf.getServerSockKeepalive());
- jvmBootstrap.childOption(ChannelOption.SO_LINGER,
conf.getServerSockLinger());
jvmBootstrap.childOption(ChannelOption.RCVBUF_ALLOCATOR,
new
AdaptiveRecvByteBufAllocator(conf.getRecvByteBufAllocatorSizeMin(),
conf.getRecvByteBufAllocatorSizeInitial(),
conf.getRecvByteBufAllocatorSizeMax()));
jvmBootstrap.option(ChannelOption.WRITE_BUFFER_WATER_MARK, new
WriteBufferWaterMark(
conf.getServerWriteBufferLowWaterMark(),
conf.getServerWriteBufferHighWaterMark()));
- if (jvmEventLoopGroup instanceof DefaultEventLoopGroup) {
- jvmBootstrap.channel(LocalServerChannel.class);
- } else if (EventLoopUtil.isIoUringGroup(jvmEventLoopGroup)) {
- jvmBootstrap.channel(IoUringServerSocketChannel.class);
- } else if (jvmEventLoopGroup instanceof EpollEventLoopGroup) {
- jvmBootstrap.channel(EpollServerSocketChannel.class);
- } else {
- jvmBootstrap.channel(NioServerSocketChannel.class);
- }
+ // Local transport (BOOKKEEPER-896) is an in-VM transport that
does not involve
+ // the network stack, so network-related socket options such as
TCP_NODELAY,
+ // SO_KEEPALIVE, SO_LINGER and TCP_KEEP* are not applicable and
must not be set here.
+ jvmBootstrap.channel(LocalServerChannel.class);
jvmBootstrap.childHandler(new ChannelInitializer<LocalChannel>() {
@Override
diff --git
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/PerChannelBookieClient.java
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/PerChannelBookieClient.java
index 25abe5e703..69cb06bd5b 100644
---
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/PerChannelBookieClient.java
+++
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/PerChannelBookieClient.java
@@ -572,6 +572,17 @@ public class PerChannelBookieClient extends
ChannelInboundHandlerAdapter {
if (conf.getTcpKeepCnt() > 0) {
bootstrap.option(EpollChannelOption.TCP_KEEPCNT,
conf.getTcpKeepCnt());
}
+ } else if (EventLoopUtil.isIoUringGroup(eventLoopGroup)) {
+ // Set TCP keepalive parameters for IoUring if configured
+ if (conf.getTcpKeepIdle() > 0) {
+ bootstrap.option(IoUringChannelOption.TCP_KEEPIDLE,
conf.getTcpKeepIdle());
+ }
+ if (conf.getTcpKeepIntvl() > 0) {
+ bootstrap.option(IoUringChannelOption.TCP_KEEPINTVL,
conf.getTcpKeepIntvl());
+ }
+ if (conf.getTcpKeepCnt() > 0) {
+ bootstrap.option(IoUringChannelOption.TCP_KEEPCNT,
conf.getTcpKeepCnt());
+ }
}
// if buffer sizes are 0, let OS auto-tune it
if (conf.getClientSendBufferSize() > 0) {
diff --git
a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/TestBookieNettyServerTcpKeepalive.java
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/TestBookieNettyServerTcpKeepalive.java
new file mode 100644
index 0000000000..9497e5c96f
--- /dev/null
+++
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/TestBookieNettyServerTcpKeepalive.java
@@ -0,0 +1,187 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.bookkeeper.proto;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import io.netty.channel.DefaultEventLoopGroup;
+import io.netty.channel.epoll.Epoll;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.uring.IoUring;
+import java.util.concurrent.TimeUnit;
+import org.apache.bookkeeper.conf.ServerConfiguration;
+import org.apache.bookkeeper.util.EventLoopUtil;
+import org.junit.Test;
+
+/**
+ * Unit tests for TCP keepalive configuration in BookieNettyServer.
+ * This test focuses on server-side TCP keepalive configuration logic
+ * without requiring actual network connections.
+ */
+public class TestBookieNettyServerTcpKeepalive {
+
+ /**
+ * Test ServerConfiguration TCP keepalive getter methods.
+ */
+ @Test
+ public void testServerConfigurationGetters() {
+ ServerConfiguration conf = new ServerConfiguration();
+
+ // Test default values (should be -1 as per implementation)
+ assertEquals("Default server TCP keep idle should be -1", -1,
conf.getServerTcpKeepIdle());
+ assertEquals("Default server TCP keep interval should be -1", -1,
conf.getServerTcpKeepIntvl());
+ assertEquals("Default server TCP keep count should be -1", -1,
conf.getServerTcpKeepCnt());
+
+ // Test setter and getter methods
+ conf.setServerTcpKeepIdle(60);
+ conf.setServerTcpKeepIntvl(30);
+ conf.setServerTcpKeepCnt(5);
+
+ assertEquals("Server TCP keep idle should be 60", 60,
conf.getServerTcpKeepIdle());
+ assertEquals("Server TCP keep interval should be 30", 30,
conf.getServerTcpKeepIntvl());
+ assertEquals("Server TCP keep count should be 5", 5,
conf.getServerTcpKeepCnt());
+
+ // Test that -1 means use system default (as per implementation
comments)
+ conf.setServerTcpKeepIdle(-1);
+ conf.setServerTcpKeepIntvl(-1);
+ conf.setServerTcpKeepCnt(-1);
+
+ assertEquals("Server TCP keep idle should be -1 for system default",
-1, conf.getServerTcpKeepIdle());
+ assertEquals("Server TCP keep interval should be -1 for system
default", -1, conf.getServerTcpKeepIntvl());
+ assertEquals("Server TCP keep count should be -1 for system default",
-1, conf.getServerTcpKeepCnt());
+ }
+
+ /**
+ * Test TCP keepalive configuration conditional logic for server side.
+ */
+ @Test
+ public void testServerTcpKeepaliveConditionalLogic() {
+ ServerConfiguration conf = new ServerConfiguration();
+
+ // Test with positive values
+ conf.setServerTcpKeepIdle(60);
+ conf.setServerTcpKeepIntvl(30);
+ conf.setServerTcpKeepCnt(5);
+
+ assertTrue("Server TCP keep idle should be > 0",
conf.getServerTcpKeepIdle() > 0);
+ assertTrue("Server TCP keep interval should be > 0",
conf.getServerTcpKeepIntvl() > 0);
+ assertTrue("Server TCP keep count should be > 0",
conf.getServerTcpKeepCnt() > 0);
+
+ // Test with zero values
+ conf.setServerTcpKeepIdle(0);
+ conf.setServerTcpKeepIntvl(0);
+ conf.setServerTcpKeepCnt(0);
+
+ assertFalse("Server TCP keep idle should not be configured for zero",
conf.getServerTcpKeepIdle() > 0);
+ assertFalse("Server TCP keep interval should not be configured for
zero", conf.getServerTcpKeepIntvl() > 0);
+ assertFalse("Server TCP keep count should not be configured for zero",
conf.getServerTcpKeepCnt() > 0);
+
+ // Test with negative values (system default)
+ conf.setServerTcpKeepIdle(-1);
+ conf.setServerTcpKeepIntvl(-1);
+ conf.setServerTcpKeepCnt(-1);
+
+ assertFalse("Server TCP keep idle should not be configured for
negative", conf.getServerTcpKeepIdle() > 0);
+ assertFalse("Server TCP keep interval should not be configured for
negative", conf.getServerTcpKeepIntvl() > 0);
+ assertFalse("Server TCP keep count should not be configured for
negative", conf.getServerTcpKeepCnt() > 0);
+
+ // Test partial configuration
+ conf.setServerTcpKeepIdle(60);
+ conf.setServerTcpKeepIntvl(0);
+ conf.setServerTcpKeepCnt(5);
+
+ assertTrue("Server TCP keep idle should be configured",
conf.getServerTcpKeepIdle() > 0);
+ assertFalse("Server TCP keep interval should not be configured",
conf.getServerTcpKeepIntvl() > 0);
+ assertTrue("Server TCP keep count should be configured",
conf.getServerTcpKeepCnt() > 0);
+ }
+
+ /**
+ * Test EventLoopGroup type detection logic.
+ */
+ @Test
+ public void testEventLoopGroupTypeDetection() {
+ // Test NIO event loop group detection
+ NioEventLoopGroup nioGroup = new NioEventLoopGroup(1);
+ assertFalse("NIO event loop group should not be detected as Epoll",
+ nioGroup.getClass().getName().contains("Epoll"));
+ assertFalse("NIO event loop group should not be detected as IoUring",
+ EventLoopUtil.isIoUringGroup(nioGroup));
+ nioGroup.shutdownGracefully(0, 0, TimeUnit.MILLISECONDS);
+
+ // Test DefaultEventLoopGroup detection
+ DefaultEventLoopGroup defaultGroup = new DefaultEventLoopGroup(1);
+ assertFalse("Default event loop group should not be detected as Epoll",
+ defaultGroup.getClass().getName().contains("Epoll"));
+ assertFalse("Default event loop group should not be detected as
IoUring",
+ EventLoopUtil.isIoUringGroup(defaultGroup));
+ defaultGroup.shutdownGracefully(0, 0, TimeUnit.MILLISECONDS);
+
+ // Test Epoll support detection: use Epoll.isAvailable() to verify
that the native
+ // library can actually be loaded, not just that the class is on the
classpath.
+ boolean isEpollSupported = Epoll.isAvailable();
+
+ // Test IoUring support detection via runtime availability check.
+ boolean isIoUringSupported = IoUring.isAvailable();
+
+ System.out.println("Epoll support detected: " + isEpollSupported);
+ System.out.println("IoUring support detected: " + isIoUringSupported);
+ System.out.println("Operating system: " +
System.getProperty("os.name"));
+
+ // The important thing is that the detection logic works correctly
+ // The actual result depends on the platform
+ assertTrue("EventLoopUtil should be available", EventLoopUtil.class !=
null);
+ }
+
+ /**
+ * Test TCP keepalive parameter validation logic.
+ */
+ @Test
+ public void testTcpKeepaliveParameterValidation() {
+ ServerConfiguration conf = new ServerConfiguration();
+
+ // Test valid parameter ranges
+ conf.setServerTcpKeepIdle(1);
+ conf.setServerTcpKeepIntvl(1);
+ conf.setServerTcpKeepCnt(1);
+
+ assertTrue("Minimum TCP keep idle should be valid",
conf.getServerTcpKeepIdle() > 0);
+ assertTrue("Minimum TCP keep interval should be valid",
conf.getServerTcpKeepIntvl() > 0);
+ assertTrue("Minimum TCP keep count should be valid",
conf.getServerTcpKeepCnt() > 0);
+
+ // Test typical production values
+ conf.setServerTcpKeepIdle(300);
+ conf.setServerTcpKeepIntvl(60);
+ conf.setServerTcpKeepCnt(3);
+
+ assertEquals("Production TCP keep idle should be 300", 300,
conf.getServerTcpKeepIdle());
+ assertEquals("Production TCP keep interval should be 60", 60,
conf.getServerTcpKeepIntvl());
+ assertEquals("Production TCP keep count should be 3", 3,
conf.getServerTcpKeepCnt());
+
+ // Test boundary values
+ conf.setServerTcpKeepIdle(Integer.MAX_VALUE);
+ conf.setServerTcpKeepIntvl(Integer.MAX_VALUE);
+ conf.setServerTcpKeepCnt(Integer.MAX_VALUE);
+
+ assertTrue("Maximum TCP keep idle should be valid",
conf.getServerTcpKeepIdle() > 0);
+ assertTrue("Maximum TCP keep interval should be valid",
conf.getServerTcpKeepIntvl() > 0);
+ assertTrue("Maximum TCP keep count should be valid",
conf.getServerTcpKeepCnt() > 0);
+ }
+}
\ No newline at end of file
diff --git
a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/TestPerChannelBookieClientTcpKeepalive.java
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/TestPerChannelBookieClientTcpKeepalive.java
index 6ecf2d71d9..b35f2005b7 100644
---
a/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/TestPerChannelBookieClientTcpKeepalive.java
+++
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/proto/TestPerChannelBookieClientTcpKeepalive.java
@@ -22,9 +22,14 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import io.netty.channel.DefaultEventLoopGroup;
+import io.netty.channel.epoll.Epoll;
+import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.uring.IoUring;
import java.util.concurrent.TimeUnit;
import org.apache.bookkeeper.conf.ClientConfiguration;
+import org.apache.bookkeeper.util.EventLoopUtil;
import org.junit.Test;
/**
@@ -117,14 +122,9 @@ public class TestPerChannelBookieClientTcpKeepalive {
*/
@Test
public void testEpollSupportDetection() {
- // Test Epoll support detection
- boolean isEpollSupported = false;
- try {
- Class.forName("io.netty.channel.epoll.EpollEventLoopGroup");
- isEpollSupported = true;
- } catch (ClassNotFoundException e) {
- // Epoll not supported on this platform
- }
+ // Test Epoll support detection: use Epoll.isAvailable() to verify
that the native
+ // library can actually be loaded, not just that the class is on the
classpath.
+ boolean isEpollSupported = Epoll.isAvailable();
// Test NIO event loop group detection
NioEventLoopGroup nioGroup = new NioEventLoopGroup(1);
@@ -138,4 +138,77 @@ public class TestPerChannelBookieClientTcpKeepalive {
System.out.println("Epoll support detected: " + isEpollSupported);
System.out.println("Operating system: " +
System.getProperty("os.name"));
}
+
+ /**
+ * Test IoUring support detection logic.
+ */
+ @Test
+ public void testIoUringSupportDetection() {
+ // Use runtime availability checks to avoid UnsatisfiedLinkError on
non-Linux platforms.
+ boolean isIoUringSupported = IoUring.isAvailable();
+ boolean isEpollSupported = Epoll.isAvailable();
+
+ // Test NIO event loop group detection
+ NioEventLoopGroup nioGroup = new NioEventLoopGroup(1);
+ assertFalse("NIO event loop group should not be detected as IoUring",
+ EventLoopUtil.isIoUringGroup(nioGroup));
+
+ // Test DefaultEventLoopGroup detection
+ DefaultEventLoopGroup defaultGroup = new DefaultEventLoopGroup(1);
+ assertFalse("Default event loop group should not be detected as
IoUring",
+ EventLoopUtil.isIoUringGroup(defaultGroup));
+
+ // Only instantiate EpollEventLoopGroup when the native library is
available,
+ // otherwise the constructor will fail on non-Linux platforms.
+ if (isEpollSupported) {
+ EpollEventLoopGroup epollGroup = new EpollEventLoopGroup(1);
+ assertFalse("Epoll event loop group should not be detected as
IoUring",
+ EventLoopUtil.isIoUringGroup(epollGroup));
+ epollGroup.shutdownGracefully(0, 0, TimeUnit.MILLISECONDS);
+ }
+
+ nioGroup.shutdownGracefully(0, 0, TimeUnit.MILLISECONDS);
+ defaultGroup.shutdownGracefully(0, 0, TimeUnit.MILLISECONDS);
+
+ // The important thing is that the detection logic works correctly
+ // The actual result depends on the platform
+ System.out.println("IoUring support detected: " + isIoUringSupported);
+ System.out.println("Epoll support detected: " + isEpollSupported);
+ System.out.println("Operating system: " +
System.getProperty("os.name"));
+ }
+
+ /**
+ * Test TCP keepalive parameter validation logic.
+ */
+ @Test
+ public void testTcpKeepaliveParameterValidation() {
+ ClientConfiguration conf = new ClientConfiguration();
+
+ // Test valid parameter ranges
+ conf.setTcpKeepIdle(1);
+ conf.setTcpKeepIntvl(1);
+ conf.setTcpKeepCnt(1);
+
+ assertTrue("Minimum TCP keep idle should be valid",
conf.getTcpKeepIdle() > 0);
+ assertTrue("Minimum TCP keep interval should be valid",
conf.getTcpKeepIntvl() > 0);
+ assertTrue("Minimum TCP keep count should be valid",
conf.getTcpKeepCnt() > 0);
+
+ // Test typical production values
+ conf.setTcpKeepIdle(300);
+ conf.setTcpKeepIntvl(60);
+ conf.setTcpKeepCnt(3);
+
+ assertEquals("Production TCP keep idle should be 300", 300,
conf.getTcpKeepIdle());
+ assertEquals("Production TCP keep interval should be 60", 60,
conf.getTcpKeepIntvl());
+ assertEquals("Production TCP keep count should be 3", 3,
conf.getTcpKeepCnt());
+
+ // Test boundary values
+ conf.setTcpKeepIdle(Integer.MAX_VALUE);
+ conf.setTcpKeepIntvl(Integer.MAX_VALUE);
+ conf.setTcpKeepCnt(Integer.MAX_VALUE);
+
+ assertTrue("Maximum TCP keep idle should be valid",
conf.getTcpKeepIdle() > 0);
+ assertTrue("Maximum TCP keep interval should be valid",
conf.getTcpKeepIntvl() > 0);
+ assertTrue("Maximum TCP keep count should be valid",
conf.getTcpKeepCnt() > 0);
+ }
}