Skip to content

Commit 9e4bb29

Browse files
authored
IoUring: Allow to create IoHandlerFactory that supports changing the (#15608)
Thread and so supports AutoScalingEventExecutorChooserFactory. Modifications: By default io_uring does not support AutoScalingEventExecutorChooserFactory as it uses IORING_SETUP_SINGLE_ISSUER for performance reasons. While this is a good default sometimes the user might want to tradeoff performance for flexibility / scalability. Modifications: Allow to disable the use of IORING_SETUP_SINGLE_ISSUER and so support AutoScalingEventExecutorChooserFactory even with io_uring Result: Follow up of #15603
1 parent 22d414b commit 9e4bb29

File tree

4 files changed

+52
-13
lines changed

4 files changed

+52
-13
lines changed

transport-classes-io_uring/src/main/java/io/netty/channel/uring/IoUringIoHandler.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public final class IoUringIoHandler implements IoHandler {
9393
IoUring.ensureAvailability();
9494
this.executor = requireNonNull(executor, "executor");
9595
requireNonNull(config, "config");
96-
int setupFlags = Native.setupFlags();
96+
int setupFlags = Native.setupFlags(config.singleIssuer());
9797

9898
//The default cq size is always twice the ringSize.
9999
// It only makes sense when the user actually specifies the cq ring size.
@@ -696,6 +696,16 @@ public static IoHandlerFactory newFactory(int ringSize) {
696696
public static IoHandlerFactory newFactory(IoUringIoHandlerConfig config) {
697697
IoUring.ensureAvailability();
698698
ObjectUtil.checkNotNull(config, "config");
699-
return eventLoop -> new IoUringIoHandler(eventLoop, config);
699+
return new IoHandlerFactory() {
700+
@Override
701+
public IoHandler newHandler(ThreadAwareExecutor eventLoop) {
702+
return new IoUringIoHandler(eventLoop, config);
703+
}
704+
705+
@Override
706+
public boolean isChangingThreadSupported() {
707+
return !config.singleIssuer();
708+
}
709+
};
700710
}
701711
}

transport-classes-io_uring/src/main/java/io/netty/channel/uring/IoUringIoHandlerConfig.java

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@
9292
* It will be used to register the buffer ring for the io_uring instance.
9393
* </td>
9494
* </tr>
95+
* <tr>
96+
* <td>{@link IoUringIoHandlerConfig#setSingleIssuer}</td>
97+
* <td>
98+
* Enable or disable the use of {@code IORING_SETUP_SINGLE_ISSUER}.
99+
* </td>
100+
* </tr>
95101
* </tbody>
96102
* </table>
97103
*/
@@ -100,12 +106,10 @@ public final class IoUringIoHandlerConfig {
100106

101107
private int ringSize = IoUring.DEFAULT_RING_SIZE;
102108
private int cqSize = IoUring.DEFAULT_CQ_SIZE;
103-
104109
private int maxBoundedWorker;
105-
106110
private int maxUnboundedWorker;
107-
108111
private Set<IoUringBufferRingConfig> bufferRingConfigs;
112+
private boolean singleIssuer = true;
109113

110114
/**
111115
* Return the ring size of the io_uring instance.
@@ -213,6 +217,22 @@ public IoUringIoHandlerConfig setBufferRingConfig(IoUringBufferRingConfig... rin
213217
return this;
214218
}
215219

220+
/**
221+
* Set if {@code IORING_SETUP_SINGLE_ISSUER} should be used when setup the ring. This is {@code true} by default
222+
* for performance reasons but also means that the {@link Thread} that is used to drive the
223+
* {@link io.netty.channel.IoHandler} can never change. If you want the flexibility to change the {@link Thread},
224+
* to for example make use of the {@link io.netty.util.concurrent.AutoScalingEventExecutorChooserFactory} it's
225+
* possible to not use {@code IORING_SETUP_SINGLE_ISSUER}. This will trade scalibility / flexibility
226+
* and performance.
227+
*
228+
* @param singleIssuer {@code true} if {@code IORING_SETUP_SINGLE_ISSUER} should be used, {@code false} otherwise
229+
* @return reference to this, so the API can be used fluently
230+
*/
231+
public IoUringIoHandlerConfig setSingleIssuer(boolean singleIssuer) {
232+
this.singleIssuer = singleIssuer;
233+
return this;
234+
}
235+
216236
/**
217237
* Get the list of buffer ring configurations.
218238
* @return the copy of buffer ring configurations.
@@ -232,4 +252,8 @@ boolean needSetupCqeSize() {
232252
Set<IoUringBufferRingConfig> getInternBufferRingConfigs() {
233253
return bufferRingConfigs;
234254
}
255+
256+
boolean singleIssuer() {
257+
return singleIssuer;
258+
}
235259
}

transport-classes-io_uring/src/main/java/io/netty/channel/uring/Native.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -355,18 +355,21 @@ static String opToStr(byte op) {
355355
IORING_OP_SEND
356356
};
357357

358-
static int setupFlags() {
358+
static int setupFlags(boolean useSingleIssuer) {
359359
int flags = Native.IORING_SETUP_R_DISABLED | Native.IORING_SETUP_CLAMP;
360360
if (IoUring.isSetupSubmitAllSupported()) {
361361
flags |= Native.IORING_SETUP_SUBMIT_ALL;
362362
}
363363

364-
// See https://github.com/axboe/liburing/wiki/io_uring-and-networking-in-2023#task-work
365-
if (IoUring.isSetupSingleIssuerSupported()) {
366-
flags |= Native.IORING_SETUP_SINGLE_ISSUER;
367-
}
368-
if (IoUring.isSetupDeferTaskrunSupported()) {
369-
flags |= Native.IORING_SETUP_DEFER_TASKRUN;
364+
if (useSingleIssuer) {
365+
// See https://github.com/axboe/liburing/wiki/io_uring-and-networking-in-2023#task-work
366+
if (IoUring.isSetupSingleIssuerSupported()) {
367+
flags |= Native.IORING_SETUP_SINGLE_ISSUER;
368+
}
369+
// IORING_SETUP_DEFER_TASKRUN also requires IORING_SETUP_SINGLE_ISSUER.
370+
if (IoUring.isSetupDeferTaskrunSupported()) {
371+
flags |= Native.IORING_SETUP_DEFER_TASKRUN;
372+
}
370373
}
371374
// liburing uses IORING_SETUP_NO_SQARRAY by default these days, we should do the same by default if possible.
372375
// See https://github.com/axboe/liburing/releases/tag/liburing-2.6

transport-native-io_uring/src/test/java/io/netty/channel/uring/IoUringEventLoopTest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.junit.jupiter.api.Test;
2828

2929
import java.util.concurrent.CountDownLatch;
30+
import java.util.concurrent.Executor;
3031
import java.util.concurrent.TimeUnit;
3132

3233
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -53,7 +54,8 @@ protected EventLoopGroup newEventLoopGroup() {
5354

5455
@Override
5556
protected EventLoopGroup newAutoScalingEventLoopGroup() {
56-
return null;
57+
return new MultiThreadIoEventLoopGroup(SCALING_MAX_THREADS, (Executor) null, AUTO_SCALING_CHOOSER_FACTORY,
58+
IoUringIoHandler.newFactory(new IoUringIoHandlerConfig().setSingleIssuer(false)));
5759
}
5860

5961
@Override

0 commit comments

Comments
 (0)