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.ByteBufAllocator;
19  import io.netty.util.internal.AdaptiveCalculator;
20  
21  /**
22   * {@link IoUringBufferRingAllocator} implementation which uses an adaptive strategy to allocate buffers, which
23   * will decrease / increase the buffer size depending on if the allocated buffers were completely used or not before.
24   */
25  public final class IoUringAdaptiveBufferRingAllocator extends AbstractIoUringBufferRingAllocator {
26  
27      public static final int DEFAULT_MINIMUM = 1024;
28      public static final int DEFAULT_INITIAL = 4096;
29      public static final int DEFAULT_MAXIMUM = 65536;
30  
31      private final AdaptiveCalculator calculator;
32  
33      public IoUringAdaptiveBufferRingAllocator() {
34          this(ByteBufAllocator.DEFAULT);
35      }
36  
37      /**
38       * Creates new instance.
39       *
40       * @param allocator the {@link ByteBufAllocator} to use.
41       */
42      public IoUringAdaptiveBufferRingAllocator(ByteBufAllocator allocator) {
43          this(allocator, DEFAULT_MINIMUM, DEFAULT_INITIAL, DEFAULT_MAXIMUM);
44      }
45  
46      /**
47       * Creates new instance.
48       *
49       * @param allocator the {@link ByteBufAllocator} to use for the allocations
50       * @param minimum   the inclusive lower bound of the expected buffer size
51       * @param initial   the initial buffer size when no feed back was received
52       * @param maximum   the inclusive upper bound of the expected buffer size
53       */
54      public IoUringAdaptiveBufferRingAllocator(ByteBufAllocator allocator, int minimum, int initial, int maximum) {
55          this(allocator, minimum, initial, maximum, false);
56      }
57  
58      /**
59       * Creates new instance.
60       *
61       * @param allocator         the {@link ByteBufAllocator} to use for the allocations
62       * @param minimum           the inclusive lower bound of the expected buffer size
63       * @param initial           the initial buffer size when no feed back was received
64       * @param maximum           the inclusive upper bound of the expected buffer size
65       * @param largeAllocation   {@code true} if we should do a large allocation for the whole buffer ring
66       *                          and then slice out the buffers or {@code false} if we should do one allocation
67       *                          per buffer.
68       */
69      public IoUringAdaptiveBufferRingAllocator(
70              ByteBufAllocator allocator, int minimum, int initial, int maximum, boolean largeAllocation) {
71          super(allocator, largeAllocation);
72          this.calculator = new AdaptiveCalculator(minimum, initial, maximum);
73      }
74  
75      @Override
76      protected int nextBufferSize() {
77          return calculator.nextSize();
78      }
79  
80      @Override
81      public void lastBytesRead(int attempted, int actual) {
82          // If we read as much as we asked for we should check if we need to ramp up the size of our next guess.
83          // This helps adjust more quickly when large amounts of data is pending and can avoid going back to
84          // the selector to check for more data. Going back to the selector can add significant latency for large
85          // data transfers.
86          if (attempted == actual) {
87              calculator.record(actual);
88          }
89      }
90  }