1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.channel;
17
18 import java.util.ArrayList;
19 import java.util.List;
20
21 import static io.netty.util.internal.ObjectUtil.checkPositive;
22 import static java.lang.Math.max;
23 import static java.lang.Math.min;
24
25
26
27
28
29
30
31
32
33
34
35 public class AdaptiveRecvByteBufAllocator extends DefaultMaxMessagesRecvByteBufAllocator {
36
37 static final int DEFAULT_MINIMUM = 64;
38
39 static final int DEFAULT_INITIAL = 2048;
40 static final int DEFAULT_MAXIMUM = 65536;
41
42 private static final int INDEX_INCREMENT = 4;
43 private static final int INDEX_DECREMENT = 1;
44
45 private static final int[] SIZE_TABLE;
46
47 static {
48 List<Integer> sizeTable = new ArrayList<Integer>();
49 for (int i = 16; i < 512; i += 16) {
50 sizeTable.add(i);
51 }
52
53
54 for (int i = 512; i > 0; i <<= 1) {
55 sizeTable.add(i);
56 }
57
58 SIZE_TABLE = new int[sizeTable.size()];
59 for (int i = 0; i < SIZE_TABLE.length; i ++) {
60 SIZE_TABLE[i] = sizeTable.get(i);
61 }
62 }
63
64
65
66
67 @Deprecated
68 public static final AdaptiveRecvByteBufAllocator DEFAULT = new AdaptiveRecvByteBufAllocator();
69
70 private static int getSizeTableIndex(final int size) {
71 for (int low = 0, high = SIZE_TABLE.length - 1;;) {
72 if (high < low) {
73 return low;
74 }
75 if (high == low) {
76 return high;
77 }
78
79 int mid = low + high >>> 1;
80 int a = SIZE_TABLE[mid];
81 int b = SIZE_TABLE[mid + 1];
82 if (size > b) {
83 low = mid + 1;
84 } else if (size < a) {
85 high = mid - 1;
86 } else if (size == a) {
87 return mid;
88 } else {
89 return mid + 1;
90 }
91 }
92 }
93
94 private final class HandleImpl extends MaxMessageHandle {
95 private final int minIndex;
96 private final int maxIndex;
97 private final int minCapacity;
98 private final int maxCapacity;
99 private int index;
100 private int nextReceiveBufferSize;
101 private boolean decreaseNow;
102
103 HandleImpl(int minIndex, int maxIndex, int initialIndex, int minCapacity, int maxCapacity) {
104 this.minIndex = minIndex;
105 this.maxIndex = maxIndex;
106
107 index = initialIndex;
108 nextReceiveBufferSize = max(SIZE_TABLE[index], minCapacity);
109 this.minCapacity = minCapacity;
110 this.maxCapacity = maxCapacity;
111 }
112
113 @Override
114 public void lastBytesRead(int bytes) {
115
116
117
118
119 if (bytes == attemptedBytesRead()) {
120 record(bytes);
121 }
122 super.lastBytesRead(bytes);
123 }
124
125 @Override
126 public int guess() {
127 return nextReceiveBufferSize;
128 }
129
130 private void record(int actualReadBytes) {
131 if (actualReadBytes <= SIZE_TABLE[max(0, index - INDEX_DECREMENT)]) {
132 if (decreaseNow) {
133 index = max(index - INDEX_DECREMENT, minIndex);
134 nextReceiveBufferSize = max(SIZE_TABLE[index], minCapacity);
135 decreaseNow = false;
136 } else {
137 decreaseNow = true;
138 }
139 } else if (actualReadBytes >= nextReceiveBufferSize) {
140 index = min(index + INDEX_INCREMENT, maxIndex);
141 nextReceiveBufferSize = min(SIZE_TABLE[index], maxCapacity);
142 decreaseNow = false;
143 }
144 }
145
146 @Override
147 public void readComplete() {
148 record(totalBytesRead());
149 }
150 }
151
152 private final int minIndex;
153 private final int maxIndex;
154 private final int initialIndex;
155 private final int minCapacity;
156 private final int maxCapacity;
157
158
159
160
161
162
163 public AdaptiveRecvByteBufAllocator() {
164 this(DEFAULT_MINIMUM, DEFAULT_INITIAL, DEFAULT_MAXIMUM);
165 }
166
167
168
169
170
171
172
173
174 public AdaptiveRecvByteBufAllocator(int minimum, int initial, int maximum) {
175 checkPositive(minimum, "minimum");
176 if (initial < minimum) {
177 throw new IllegalArgumentException("initial: " + initial);
178 }
179 if (maximum < initial) {
180 throw new IllegalArgumentException("maximum: " + maximum);
181 }
182
183 int minIndex = getSizeTableIndex(minimum);
184 if (SIZE_TABLE[minIndex] < minimum) {
185 this.minIndex = minIndex + 1;
186 } else {
187 this.minIndex = minIndex;
188 }
189
190 int maxIndex = getSizeTableIndex(maximum);
191 if (SIZE_TABLE[maxIndex] > maximum) {
192 this.maxIndex = maxIndex - 1;
193 } else {
194 this.maxIndex = maxIndex;
195 }
196
197 int initialIndex = getSizeTableIndex(initial);
198 if (SIZE_TABLE[initialIndex] > initial) {
199 this.initialIndex = initialIndex - 1;
200 } else {
201 this.initialIndex = initialIndex;
202 }
203 this.minCapacity = minimum;
204 this.maxCapacity = maximum;
205 }
206
207 @SuppressWarnings("deprecation")
208 @Override
209 public Handle newHandle() {
210 return new HandleImpl(minIndex, maxIndex, initialIndex, minCapacity, maxCapacity);
211 }
212
213 @Override
214 public AdaptiveRecvByteBufAllocator respectMaybeMoreData(boolean respectMaybeMoreData) {
215 super.respectMaybeMoreData(respectMaybeMoreData);
216 return this;
217 }
218 }