1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.jboss.netty.channel;
17
18 import java.util.ArrayList;
19 import java.util.List;
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 public class AdaptiveReceiveBufferSizePredictor implements
38 ReceiveBufferSizePredictor {
39
40 static final int DEFAULT_MINIMUM = 64;
41 static final int DEFAULT_INITIAL = 1024;
42 static final int DEFAULT_MAXIMUM = 65536;
43
44 private static final int INDEX_INCREMENT = 4;
45 private static final int INDEX_DECREMENT = 1;
46
47 private static final int[] SIZE_TABLE;
48
49 static {
50 List<Integer> sizeTable = new ArrayList<Integer>();
51 for (int i = 1; i <= 8; i ++) {
52 sizeTable.add(i);
53 }
54
55 for (int i = 4; i < 32; i ++) {
56 long v = 1L << i;
57 long inc = v >>> 4;
58 v -= inc << 3;
59
60 for (int j = 0; j < 8; j ++) {
61 v += inc;
62 if (v > Integer.MAX_VALUE) {
63 sizeTable.add(Integer.MAX_VALUE);
64 } else {
65 sizeTable.add((int) v);
66 }
67 }
68 }
69
70 SIZE_TABLE = new int[sizeTable.size()];
71 for (int i = 0; i < SIZE_TABLE.length; i ++) {
72 SIZE_TABLE[i] = sizeTable.get(i);
73 }
74 }
75
76 private static int getSizeTableIndex(final int size) {
77 if (size <= 16) {
78 return size - 1;
79 }
80
81 int bits = 0;
82 int v = size;
83 do {
84 v >>>= 1;
85 bits ++;
86 } while (v != 0);
87
88 final int baseIdx = bits << 3;
89 final int startIdx = baseIdx - 18;
90 final int endIdx = baseIdx - 25;
91
92 for (int i = startIdx; i >= endIdx; i --) {
93 if (size >= SIZE_TABLE[i]) {
94 return i;
95 }
96 }
97
98 throw new Error("shouldn't reach here; please file a bug report.");
99 }
100
101 private final int minIndex;
102 private final int maxIndex;
103 private int index;
104 private int nextReceiveBufferSize;
105 private boolean decreaseNow;
106
107
108
109
110
111
112 public AdaptiveReceiveBufferSizePredictor() {
113 this(DEFAULT_MINIMUM, DEFAULT_INITIAL, DEFAULT_MAXIMUM);
114 }
115
116
117
118
119
120
121
122
123 public AdaptiveReceiveBufferSizePredictor(int minimum, int initial, int maximum) {
124 if (minimum <= 0) {
125 throw new IllegalArgumentException("minimum: " + minimum);
126 }
127 if (initial < minimum) {
128 throw new IllegalArgumentException("initial: " + initial);
129 }
130 if (maximum < initial) {
131 throw new IllegalArgumentException("maximum: " + maximum);
132 }
133
134 int minIndex = getSizeTableIndex(minimum);
135 if (SIZE_TABLE[minIndex] < minimum) {
136 this.minIndex = minIndex + 1;
137 } else {
138 this.minIndex = minIndex;
139 }
140
141 int maxIndex = getSizeTableIndex(maximum);
142 if (SIZE_TABLE[maxIndex] > maximum) {
143 this.maxIndex = maxIndex - 1;
144 } else {
145 this.maxIndex = maxIndex;
146 }
147
148 index = getSizeTableIndex(initial);
149 nextReceiveBufferSize = SIZE_TABLE[index];
150 }
151
152 public int nextReceiveBufferSize() {
153 return nextReceiveBufferSize;
154 }
155
156 public void previousReceiveBufferSize(int previousReceiveBufferSize) {
157 if (previousReceiveBufferSize <= SIZE_TABLE[Math.max(0, index - INDEX_DECREMENT - 1)]) {
158 if (decreaseNow) {
159 index = Math.max(index - INDEX_DECREMENT, minIndex);
160 nextReceiveBufferSize = SIZE_TABLE[index];
161 decreaseNow = false;
162 } else {
163 decreaseNow = true;
164 }
165 } else if (previousReceiveBufferSize >= nextReceiveBufferSize) {
166 index = Math.min(index + INDEX_INCREMENT, maxIndex);
167 nextReceiveBufferSize = SIZE_TABLE[index];
168 decreaseNow = false;
169 }
170 }
171 }