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.MathUtil;
19  import io.netty.util.internal.ObjectUtil;
20  
21  import java.util.Objects;
22  
23  /**
24   * Configuration class for an {@link IoUringBufferRing}.
25   * It will configure the buffer ring size, buffer group id and the chunk size.
26   */
27  public final class IoUringBufferRingConfig {
28      private final short bgId;
29      private final short bufferRingSize;
30      private final int batchSize;
31      private final int maxUnreleasedBuffers;
32      private final boolean incremental;
33      private final IoUringBufferRingAllocator allocator;
34  
35      /**
36       * Create a new configuration.
37       *
38       * @param bgId                  the buffer group id to use (must be non-negative).
39       * @param bufferRingSize        the size of the ring
40       * @param maxUnreleasedBuffers  the maximum buffers that were allocated out of this buffer ring and are
41       *                              unreleased yet. Once this threshold is hit the usage of the buffer ring will
42       *                              be temporary disabled.
43       * @param allocator             the {@link IoUringBufferRingAllocator} to use to allocate
44       *                              {@link io.netty.buffer.ByteBuf}s.
45       */
46      public IoUringBufferRingConfig(short bgId, short bufferRingSize, int maxUnreleasedBuffers,
47                                     IoUringBufferRingAllocator allocator) {
48          this(bgId, bufferRingSize, bufferRingSize / 2, maxUnreleasedBuffers,
49                  IoUring.isRegisterBufferRingIncSupported(), allocator);
50      }
51  
52      /**
53       * Create a new configuration.
54       *
55       * @param bgId                  the buffer group id to use (must be non-negative).
56       * @param bufferRingSize        the size of the ring
57       * @param batchSize             the size of the batch on how many buffers are added everytime we need to expand the
58       *                              buffer ring.
59       * @param maxUnreleasedBuffers  the maximum buffers that can be allocated out of this buffer ring and are
60       *                              unreleased yet. Once this threshold is hit the usage of the buffer ring will
61       *                              be temporarily disabled.
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       */
66      public IoUringBufferRingConfig(short bgId, short bufferRingSize, int batchSize, int maxUnreleasedBuffers,
67                                     boolean incremental, IoUringBufferRingAllocator allocator) {
68          this.bgId = (short) ObjectUtil.checkPositiveOrZero(bgId, "bgId");
69          this.bufferRingSize = checkBufferRingSize(bufferRingSize);
70          this.batchSize = MathUtil.findNextPositivePowerOfTwo(
71                  ObjectUtil.checkInRange(batchSize, 1, bufferRingSize, "batchSize"));
72          this.maxUnreleasedBuffers = ObjectUtil.checkInRange(
73                  maxUnreleasedBuffers, bufferRingSize, Integer.MAX_VALUE, "maxUnreleasedBuffers");
74          if (incremental && !IoUring.isRegisterBufferRingIncSupported()) {
75              throw new IllegalArgumentException("Incremental buffer ring is not supported");
76          }
77          this.incremental = incremental;
78          this.allocator = ObjectUtil.checkNotNull(allocator, "allocator");
79      }
80  
81      /**
82       * Returns the buffer group id to use.
83       *
84       * @return the buffer group id to use.
85       */
86      public short bufferGroupId() {
87          return bgId;
88      }
89  
90      /**
91       * Returns the size of the ring.
92       *
93       * @return the size of the ring.
94       */
95      public short bufferRingSize() {
96          return bufferRingSize;
97      }
98  
99      /**
100      * Returns the size of the batch on how many buffers are added everytime we need to expand the buffer ring.
101      *
102      * @return batch size.
103      */
104     public int batchSize() {
105         return batchSize;
106     }
107 
108     /**
109      * Returns the maximum buffers that can be allocated out of this buffer ring and are
110      * unreleased yet
111      *
112      * @return the max unreleased buffers.
113      */
114     public int maxUnreleasedBuffers() {
115         return maxUnreleasedBuffers;
116     }
117 
118     /**
119      * Returns the {@link IoUringBufferRingAllocator} to use to allocate {@link io.netty.buffer.ByteBuf}s.
120      *
121      * @return  the allocator.
122      */
123     public IoUringBufferRingAllocator allocator() {
124         return allocator;
125     }
126 
127     /**
128      * Returns true if <a href="https://github.com/axboe/liburing/wiki/
129      * What's-new-with-io_uring-in-6.11-and-6.12#incremental-provided-buffer-consumption">incremental mode</a>
130      * should be used for the buffer ring.
131      *
132      * @return {@code true} if incremental mode is used, {@code false} otherwise.
133      */
134     public boolean isIncremental() {
135         return incremental;
136     }
137 
138     private static short checkBufferRingSize(short bufferRingSize) {
139         if (bufferRingSize < 1) {
140             throw new IllegalArgumentException("bufferRingSize: " + bufferRingSize + " (expected: > 0)");
141         }
142 
143         boolean isPowerOfTwo = (bufferRingSize & (bufferRingSize - 1)) == 0;
144         if (!isPowerOfTwo) {
145             throw new IllegalArgumentException("bufferRingSize: " + bufferRingSize + " (expected: power of 2)");
146         }
147         return bufferRingSize;
148     }
149 
150     @Override
151     public boolean equals(Object o) {
152         if (o == null || getClass() != o.getClass()) {
153             return false;
154         }
155         IoUringBufferRingConfig that = (IoUringBufferRingConfig) o;
156         return bgId == that.bgId;
157     }
158 
159     @Override
160     public int hashCode() {
161         return Objects.hashCode(bgId);
162     }
163 }