View Javadoc
1   /*
2    * Copyright 2025 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.channel.uring;
17  
18  import io.netty.util.internal.ObjectUtil;
19  
20  import java.util.ArrayList;
21  import java.util.HashSet;
22  import java.util.List;
23  import java.util.Objects;
24  import java.util.Set;
25  
26  /**
27   * Configuration class for an {@link IoUringIoHandler},
28   * managing the settings for a {@link RingBuffer} and its io_uring file descriptor.
29   *
30   * <h3>Option Map</h3>
31   * These options are used exclusively during the initialization of the {@link IoUringIoHandler}
32   * to configure the associated io_uring instance.
33   *
34   * <p>
35   * The {@link IoUringIoHandlerConfig} class provides the following configurable options:
36   * </p>
37   *
38   * <table border="1" cellspacing="0" cellpadding="6">
39   *   <caption>Available Configuration Options</caption>
40   *   <thead>
41   *     <tr>
42   *       <th>Setter Method</th>
43   *       <th>Description</th>
44   *     </tr>
45   *   </thead>
46   *   <tbody>
47   *     <tr>
48   *       <td>{@link IoUringIoHandlerConfig#setRingSize}</td>
49   *       <td>Sets the size of the submission queue for the io_uring instance.</td>
50   *     </tr>
51   *     <tr>
52   *       <td>{@link IoUringIoHandlerConfig#setMaxBoundedWorker}</td>
53   *       <td>Defines the maximum number of bounded io_uring worker threads.</td>
54   *     </tr>
55   *     <tr>
56   *       <td>{@link IoUringIoHandlerConfig#setMaxUnboundedWorker}</td>
57   *       <td>Defines the maximum number of unbounded io_uring worker threads.</td>
58   *     </tr>
59   *     <tr>
60   *       <td>{@link IoUringIoHandlerConfig#setBufferRingConfig}</td>
61   *       <td>
62   *         Adds a buffer ring configuration to the list of buffer ring configurations.
63   *         It will be used to register the buffer ring for the io_uring instance.
64   *       </td>
65   *     </tr>
66   *   </tbody>
67   * </table>
68   */
69  
70  public final class IoUringIoHandlerConfig {
71      private static final int DISABLE_SETUP_CQ_SIZE = -1;
72  
73      private int ringSize = Native.DEFAULT_RING_SIZE;
74      private int cqSize = DISABLE_SETUP_CQ_SIZE;
75  
76      private int maxBoundedWorker;
77  
78      private int maxUnboundedWorker;
79  
80      private Set<IoUringBufferRingConfig> bufferRingConfigs;
81  
82      /**
83       * Return the ring size of the io_uring instance.
84       * @return the ring size of the io_uring instance.
85       */
86      public int getRingSize() {
87          return ringSize;
88      }
89  
90      /**
91       * Return the size of the io_uring cqe.
92       * @return the cq size of the io_uring.
93       */
94      public int getCqSize() {
95          return cqSize;
96      }
97  
98      /**
99       * Return the maximum number of bounded iowq worker threads.
100      * @return the maximum number of bounded iowq worker threads.
101      */
102     public int getMaxBoundedWorker() {
103         return maxBoundedWorker;
104     }
105 
106     /**
107      * Return the maximum number of unbounded iowq worker threads.
108      * @return the maximum number of unbounded iowq worker threads.
109      */
110     public int getMaxUnboundedWorker() {
111         return maxUnboundedWorker;
112     }
113 
114     /**
115      * Set the ring size of the io_uring instance.
116      * @param ringSize the ring size of the io_uring instance.
117      * @return reference to this, so the API can be used fluently
118      */
119     public IoUringIoHandlerConfig setRingSize(int ringSize) {
120         this.ringSize = ObjectUtil.checkPositive(ringSize, "ringSize");
121         return this;
122     }
123 
124     /**
125      * Set the size of the io_uring cqe.
126      * @param cqSize the size of the io_uring cqe.
127      * @throws IllegalArgumentException if cqSize is less than ringSize, or not a power of 2
128      * @return reference to this, so the API can be used fluently
129      */
130     public IoUringIoHandlerConfig setCqSize(int cqSize) {
131         ObjectUtil.checkPositive(cqSize, "cqSize");
132         this.cqSize = checkCqSize(cqSize);
133         return this;
134     }
135 
136     int checkCqSize(int cqSize) {
137         if (cqSize < ringSize) {
138             throw new IllegalArgumentException("cqSize must be greater than or equal to ringSize");
139         }
140 
141         boolean isPowerOfTwo = Integer.bitCount(cqSize) == 1;
142         if (!isPowerOfTwo) {
143             throw new IllegalArgumentException("cqSize: " + cqSize + " (expected: power of 2)");
144         }
145         return cqSize;
146     }
147 
148     /**
149      * Set the maximum number of bounded iowq worker threads.
150      * @param maxBoundedWorker the maximum number of bounded iowq worker threads,
151      *                         or 0 for the Linux kernel default
152      * @return reference to this, so the API can be used fluently
153      */
154     public IoUringIoHandlerConfig setMaxBoundedWorker(int maxBoundedWorker) {
155         this.maxBoundedWorker = ObjectUtil.checkPositiveOrZero(maxBoundedWorker, "maxBoundedWorker");
156         return this;
157     }
158 
159     /**
160      * Set the maximum number of unbounded iowq worker threads.
161      * @param maxUnboundedWorker the maximum number of unbounded iowq worker threads,
162      *                           of 0 for the Linux kernel default
163      * @return reference to this, so the API can be used fluently
164      */
165     public IoUringIoHandlerConfig setMaxUnboundedWorker(int maxUnboundedWorker) {
166         this.maxUnboundedWorker = ObjectUtil.checkPositiveOrZero(maxUnboundedWorker, "maxUnboundedWorker");
167         return this;
168     }
169 
170     /**
171      * Add a buffer ring configuration to the list of buffer ring configurations.
172      * Each {@link IoUringBufferRingConfig} must have a different {@link IoUringBufferRingConfig#bufferGroupId()}.
173      *
174      * @param ringConfig        the buffer ring configuration to append.
175      * @return reference to this, so the API can be used fluently
176      */
177     public IoUringIoHandlerConfig setBufferRingConfig(IoUringBufferRingConfig... ringConfig) {
178         Set<IoUringBufferRingConfig> configSet = new HashSet<>(ringConfig.length);
179         for (IoUringBufferRingConfig bufferRingConfig : ringConfig) {
180             if (!configSet.add(bufferRingConfig)) {
181                 throw new IllegalArgumentException("Duplicated buffer group id: " + bufferRingConfig.bufferGroupId());
182             }
183         }
184         bufferRingConfigs = configSet;
185         return this;
186     }
187 
188     /**
189      * Get the list of buffer ring configurations.
190      * @return the copy of buffer ring configurations.
191      */
192     public List<IoUringBufferRingConfig> getBufferRingConfigs() {
193         return new ArrayList<>(bufferRingConfigs);
194     }
195 
196     boolean needRegisterIowqMaxWorker() {
197         return maxBoundedWorker > 0 || maxUnboundedWorker > 0;
198     }
199 
200     boolean needSetupCqeSize() {
201         return cqSize != DISABLE_SETUP_CQ_SIZE;
202     }
203 
204     Set<IoUringBufferRingConfig> getInternBufferRingConfigs() {
205         return bufferRingConfigs;
206     }
207 }