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.buffer.ByteBuf;
19  import io.netty.util.internal.MathUtil;
20  import io.netty.util.internal.ObjectUtil;
21  
22  import java.util.Objects;
23  
24  /**
25   * Configuration class for an {@link IoUringBufferRing}.
26   * It will configure the buffer ring size, buffer group id and the chunk size.
27   */
28  public final class IoUringBufferRingConfig {
29      private final short bgId;
30      private final short bufferRingSize;
31      private final int batchSize;
32      private final int maxUnreleasedBuffers;
33      private final boolean incremental;
34      private final IoUringBufferRingAllocator allocator;
35      private final boolean batchAllocation;
36  
37      /**
38       * Create a new configuration.
39       *
40       * @param bgId                  the buffer group id to use (must be non-negative).
41       * @param bufferRingSize        the size of the ring
42       * @param maxUnreleasedBuffers  this parameter is ignored by the buffer ring.
43       * @param allocator             the {@link IoUringBufferRingAllocator} to use to allocate
44       *                              {@link io.netty.buffer.ByteBuf}s.
45       * @deprecated                  use {@link Builder}.
46       */
47      @Deprecated
48      public IoUringBufferRingConfig(short bgId, short bufferRingSize, int maxUnreleasedBuffers,
49                                     IoUringBufferRingAllocator allocator) {
50          this(bgId, bufferRingSize, bufferRingSize / 2, maxUnreleasedBuffers,
51                  IoUring.isRegisterBufferRingIncSupported(), allocator);
52      }
53  
54      /**
55       * Create a new configuration.
56       *
57       * @param bgId                  the buffer group id to use (must be non-negative).
58       * @param bufferRingSize        the size of the ring
59       * @param batchSize             the size of the batch on how many buffers are added everytime we need to expand the
60       *                              buffer ring.
61       * @param maxUnreleasedBuffers  this parameter is ignored by the buffer ring.
62       * @param incremental           {@code true} if the buffer ring is using incremental buffer consumption.
63       * @param allocator             the {@link IoUringBufferRingAllocator} to use to allocate
64       *                              {@link io.netty.buffer.ByteBuf}s.
65       * @deprecated                  use {@link Builder}.
66       */
67      @Deprecated
68      public IoUringBufferRingConfig(short bgId, short bufferRingSize, int batchSize, int maxUnreleasedBuffers,
69                                     boolean incremental, IoUringBufferRingAllocator allocator) {
70          this(bgId, bufferRingSize, batchSize, maxUnreleasedBuffers, incremental, allocator, false);
71      }
72  
73      private IoUringBufferRingConfig(short bgId, short bufferRingSize, int batchSize, int maxUnreleasedBuffers,
74                                     boolean incremental, IoUringBufferRingAllocator allocator, boolean batchAllocation) {
75          this.bgId = (short) ObjectUtil.checkPositiveOrZero(bgId, "bgId");
76          this.bufferRingSize = checkBufferRingSize(bufferRingSize);
77          this.batchSize = MathUtil.findNextPositivePowerOfTwo(
78                  ObjectUtil.checkInRange(batchSize, 1, bufferRingSize, "batchSize"));
79          this.maxUnreleasedBuffers = ObjectUtil.checkInRange(
80                  maxUnreleasedBuffers, bufferRingSize, Integer.MAX_VALUE, "maxUnreleasedBuffers");
81          if (incremental && !IoUring.isRegisterBufferRingIncSupported()) {
82              throw new IllegalArgumentException("Incremental buffer ring is not supported");
83          }
84          this.incremental = incremental;
85          this.allocator = ObjectUtil.checkNotNull(allocator, "allocator");
86          this.batchAllocation = batchAllocation;
87      }
88  
89      /**
90       * Returns the buffer group id to use.
91       *
92       * @return the buffer group id to use.
93       */
94      public short bufferGroupId() {
95          return bgId;
96      }
97  
98      /**
99       * Returns the size of the ring.
100      *
101      * @return the size of the ring.
102      */
103     public short bufferRingSize() {
104         return bufferRingSize;
105     }
106 
107     /**
108      * Returns the size of the batch on how many buffers are added everytime we need to expand the buffer ring.
109      *
110      * @return batch size.
111      */
112     public int batchSize() {
113         return batchSize;
114     }
115 
116     /**
117      * Returns the maximum buffers that can be allocated out of this buffer ring and are
118      * unreleased yet
119      *
120      * @return the max unreleased buffers.
121      * @deprecated will be removed as it as no effect.
122      */
123     @Deprecated
124     public int maxUnreleasedBuffers() {
125         return maxUnreleasedBuffers;
126     }
127 
128     /**
129      * Returns the {@link IoUringBufferRingAllocator} to use to allocate {@link io.netty.buffer.ByteBuf}s.
130      *
131      * @return  the allocator.
132      */
133     public IoUringBufferRingAllocator allocator() {
134         return allocator;
135     }
136 
137     /**
138      * Returns {@code true} if the ring should always be filled via a batch allocation or
139      * {@code false} if we will try to allocate a new {@link ByteBuf} as we used a buffer from the ring.
140      * @return {@code true} if the ring should always be filled via a batch allocation.
141      */
142     public boolean isBatchAllocation() {
143         return batchAllocation;
144     }
145 
146     /**
147      * Returns true if <a href="https://github.com/axboe/liburing/wiki/
148      * What's-new-with-io_uring-in-6.11-and-6.12#incremental-provided-buffer-consumption">incremental mode</a>
149      * should be used for the buffer ring.
150      *
151      * @return {@code true} if incremental mode is used, {@code false} otherwise.
152      */
153     public boolean isIncremental() {
154         return incremental;
155     }
156 
157     private static short checkBufferRingSize(short bufferRingSize) {
158         if (bufferRingSize < 1) {
159             throw new IllegalArgumentException("bufferRingSize: " + bufferRingSize + " (expected: > 0)");
160         }
161 
162         boolean isPowerOfTwo = (bufferRingSize & (bufferRingSize - 1)) == 0;
163         if (!isPowerOfTwo) {
164             throw new IllegalArgumentException("bufferRingSize: " + bufferRingSize + " (expected: power of 2)");
165         }
166         return bufferRingSize;
167     }
168 
169     @Override
170     public boolean equals(Object o) {
171         if (o == null || getClass() != o.getClass()) {
172             return false;
173         }
174         IoUringBufferRingConfig that = (IoUringBufferRingConfig) o;
175         return bgId == that.bgId;
176     }
177 
178     @Override
179     public int hashCode() {
180         return Objects.hashCode(bgId);
181     }
182 
183     public static Builder builder() {
184         return new Builder();
185     }
186 
187     public static final class Builder {
188         private short bgId = -1;
189         private short bufferRingSize = -1;
190         private int batchSize = -1;
191         private boolean incremental = IoUring.isRegisterBufferRingIncSupported();
192         private IoUringBufferRingAllocator allocator;
193         private boolean batchAllocation;
194 
195         /**
196          * Set the buffer group id to use.
197          *
198          * @param bgId  The buffer group id to use.
199          * @return      This builder.
200          */
201         public Builder bufferGroupId(short bgId) {
202             this.bgId = bgId;
203             return this;
204         }
205 
206         /**
207          * Set the size of the ring.
208          *
209          * @param bufferRingSize    The size of the ring.
210          * @return                  This builder.
211          */
212         public Builder bufferRingSize(short bufferRingSize) {
213             this.bufferRingSize = bufferRingSize;
214             return this;
215         }
216 
217         /**
218          * Set the size of the batch on how many buffers are added everytime we need to expand the buffer ring.
219          *
220          * @param batchSize The batch size.
221          * @return          This builder.
222          */
223         public Builder batchSize(int batchSize) {
224             this.batchSize = batchSize;
225             return this;
226         }
227 
228         /**
229          * Set the {@link IoUringBufferRingAllocator} to use to allocate {@link ByteBuf}s.
230          *
231          * @param allocator         The allocator.
232          */
233         public Builder allocator(IoUringBufferRingAllocator allocator) {
234             this.allocator = allocator;
235             return this;
236         }
237 
238         /**
239          * Set allocation strategy that is used to allocate {@link ByteBuf}s.
240          *
241          * @param batchAllocation   {@code true} if the ring should always be filled via a batch allocation or
242          *                          {@code false} if we will try to allocate a new {@link ByteBuf} as soon
243          *                          as we used a buffer from the ring.
244          * @return                  This builder.
245          */
246         public Builder batchAllocation(boolean batchAllocation) {
247             this.batchAllocation = batchAllocation;
248             return this;
249         }
250 
251         /**
252          * Set if <a href="https://github.com/axboe/liburing/wiki/
253          * What's-new-with-io_uring-in-6.11-and-6.12#incremental-provided-buffer-consumption">incremental mode</a>
254          * should be used for the buffer ring.
255          *
256          * @param incremental   {@code true} if incremental mode is used, {@code false} otherwise.
257          * @return              This builder.
258          */
259         public Builder incremental(boolean incremental) {
260             this.incremental = incremental;
261             return this;
262         }
263 
264         /**
265          * Create a new {@link IoUringBufferRingConfig}.
266          *
267          * @return a new config.
268          */
269         public IoUringBufferRingConfig build() {
270             return new IoUringBufferRingConfig(
271                     bgId, bufferRingSize, batchSize, Integer.MAX_VALUE, incremental, allocator, batchAllocation);
272         }
273     }
274 }