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 }