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