View Javadoc
1   /*
2    * Copyright 2012 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;
17  
18  import io.netty.util.internal.AdaptiveCalculator;
19  
20  import static io.netty.util.internal.ObjectUtil.checkPositive;
21  
22  /**
23   * The {@link RecvByteBufAllocator} that automatically increases and
24   * decreases the predicted buffer size on feed back.
25   * <p>
26   * It gradually increases the expected number of readable bytes if the previous
27   * read fully filled the allocated buffer.  It gradually decreases the expected
28   * number of readable bytes if the read operation was not able to fill a certain
29   * amount of the allocated buffer two times consecutively.  Otherwise, it keeps
30   * returning the same prediction.
31   */
32  public class AdaptiveRecvByteBufAllocator extends DefaultMaxMessagesRecvByteBufAllocator {
33  
34      public static final int DEFAULT_MINIMUM = 64;
35      // Use an initial value that is bigger than the common MTU of 1500
36      public static final int DEFAULT_INITIAL = 2048;
37      public static final int DEFAULT_MAXIMUM = 65536;
38  
39      /**
40       * @deprecated There is state for {@link #maxMessagesPerRead()} which is typically based upon channel type.
41       */
42      @Deprecated
43      public static final AdaptiveRecvByteBufAllocator DEFAULT = new AdaptiveRecvByteBufAllocator();
44  
45      private final class HandleImpl extends MaxMessageHandle {
46          private final AdaptiveCalculator calculator;
47  
48          HandleImpl(int minimum, int initial, int maximum) {
49              calculator = new AdaptiveCalculator(minimum, initial, maximum);
50          }
51  
52          @Override
53          public void lastBytesRead(int bytes) {
54              // If we read as much as we asked for we should check if we need to ramp up the size of our next guess.
55              // This helps adjust more quickly when large amounts of data is pending and can avoid going back to
56              // the selector to check for more data. Going back to the selector can add significant latency for large
57              // data transfers.
58              if (bytes == attemptedBytesRead()) {
59                  calculator.record(bytes);
60              }
61              super.lastBytesRead(bytes);
62          }
63  
64          @Override
65          public int guess() {
66              return calculator.nextSize();
67          }
68  
69          @Override
70          public void readComplete() {
71              calculator.record(totalBytesRead());
72          }
73      }
74  
75      private final int minimum;
76      private final int initial;
77      private final int maximum;
78  
79      /**
80       * Creates a new predictor with the default parameters.  With the default
81       * parameters, the expected buffer size starts from {@code 1024}, does not
82       * go down below {@code 64}, and does not go up above {@code 65536}.
83       */
84      public AdaptiveRecvByteBufAllocator() {
85          this(DEFAULT_MINIMUM, DEFAULT_INITIAL, DEFAULT_MAXIMUM);
86      }
87  
88      /**
89       * Creates a new predictor with the specified parameters.
90       *
91       * @param minimum  the inclusive lower bound of the expected buffer size
92       * @param initial  the initial buffer size when no feed back was received
93       * @param maximum  the inclusive upper bound of the expected buffer size
94       */
95      public AdaptiveRecvByteBufAllocator(int minimum, int initial, int maximum) {
96          checkPositive(minimum, "minimum");
97          if (initial < minimum) {
98              throw new IllegalArgumentException("initial: " + initial);
99          }
100         if (maximum < initial) {
101             throw new IllegalArgumentException("maximum: " + maximum);
102         }
103 
104         this.minimum = minimum;
105         this.initial = initial;
106         this.maximum = maximum;
107     }
108 
109     @SuppressWarnings("deprecation")
110     @Override
111     public Handle newHandle() {
112         return new HandleImpl(minimum, initial, maximum);
113     }
114 
115     @Override
116     public AdaptiveRecvByteBufAllocator respectMaybeMoreData(boolean respectMaybeMoreData) {
117         super.respectMaybeMoreData(respectMaybeMoreData);
118         return this;
119     }
120 }