1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.netty.util.internal;
18
19 import io.netty.util.concurrent.FastThreadLocal;
20 import io.netty.util.concurrent.FastThreadLocalThread;
21 import io.netty.util.internal.logging.InternalLogger;
22 import io.netty.util.internal.logging.InternalLoggerFactory;
23
24 import java.nio.charset.Charset;
25 import java.nio.charset.CharsetDecoder;
26 import java.nio.charset.CharsetEncoder;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.IdentityHashMap;
30 import java.util.Map;
31 import java.util.WeakHashMap;
32
33
34
35
36
37
38 public final class InternalThreadLocalMap extends UnpaddedInternalThreadLocalMap {
39
40 private static final InternalLogger logger = InternalLoggerFactory.getInstance(InternalThreadLocalMap.class);
41
42 private static final int DEFAULT_ARRAY_LIST_INITIAL_CAPACITY = 8;
43 private static final int STRING_BUILDER_INITIAL_SIZE;
44 private static final int STRING_BUILDER_MAX_SIZE;
45
46 public static final Object UNSET = new Object();
47
48 static {
49 STRING_BUILDER_INITIAL_SIZE =
50 SystemPropertyUtil.getInt("io.netty.threadLocalMap.stringBuilder.initialSize", 1024);
51 logger.debug("-Dio.netty.threadLocalMap.stringBuilder.initialSize: {}", STRING_BUILDER_INITIAL_SIZE);
52
53 STRING_BUILDER_MAX_SIZE = SystemPropertyUtil.getInt("io.netty.threadLocalMap.stringBuilder.maxSize", 1024 * 4);
54 logger.debug("-Dio.netty.threadLocalMap.stringBuilder.maxSize: {}", STRING_BUILDER_MAX_SIZE);
55 }
56
57 public static InternalThreadLocalMap getIfSet() {
58 Thread thread = Thread.currentThread();
59 if (thread instanceof FastThreadLocalThread) {
60 return ((FastThreadLocalThread) thread).threadLocalMap();
61 }
62 return slowThreadLocalMap.get();
63 }
64
65 public static InternalThreadLocalMap get() {
66 Thread thread = Thread.currentThread();
67 if (thread instanceof FastThreadLocalThread) {
68 return fastGet((FastThreadLocalThread) thread);
69 } else {
70 return slowGet();
71 }
72 }
73
74 private static InternalThreadLocalMap fastGet(FastThreadLocalThread thread) {
75 InternalThreadLocalMap threadLocalMap = thread.threadLocalMap();
76 if (threadLocalMap == null) {
77 thread.setThreadLocalMap(threadLocalMap = new InternalThreadLocalMap());
78 }
79 return threadLocalMap;
80 }
81
82 private static InternalThreadLocalMap slowGet() {
83 ThreadLocal<InternalThreadLocalMap> slowThreadLocalMap = UnpaddedInternalThreadLocalMap.slowThreadLocalMap;
84 InternalThreadLocalMap ret = slowThreadLocalMap.get();
85 if (ret == null) {
86 ret = new InternalThreadLocalMap();
87 slowThreadLocalMap.set(ret);
88 }
89 return ret;
90 }
91
92 public static void remove() {
93 Thread thread = Thread.currentThread();
94 if (thread instanceof FastThreadLocalThread) {
95 ((FastThreadLocalThread) thread).setThreadLocalMap(null);
96 } else {
97 slowThreadLocalMap.remove();
98 }
99 }
100
101 public static void destroy() {
102 slowThreadLocalMap.remove();
103 }
104
105 public static int nextVariableIndex() {
106 int index = nextIndex.getAndIncrement();
107 if (index < 0) {
108 nextIndex.decrementAndGet();
109 throw new IllegalStateException("too many thread-local indexed variables");
110 }
111 return index;
112 }
113
114 public static int lastVariableIndex() {
115 return nextIndex.get() - 1;
116 }
117
118
119
120 public long rp1, rp2, rp3, rp4, rp5, rp6, rp7, rp8, rp9;
121
122 private InternalThreadLocalMap() {
123 super(newIndexedVariableTable());
124 }
125
126 private static Object[] newIndexedVariableTable() {
127 Object[] array = new Object[32];
128 Arrays.fill(array, UNSET);
129 return array;
130 }
131
132 public int size() {
133 int count = 0;
134
135 if (futureListenerStackDepth != 0) {
136 count ++;
137 }
138 if (localChannelReaderStackDepth != 0) {
139 count ++;
140 }
141 if (handlerSharableCache != null) {
142 count ++;
143 }
144 if (counterHashCode != null) {
145 count ++;
146 }
147 if (random != null) {
148 count ++;
149 }
150 if (typeParameterMatcherGetCache != null) {
151 count ++;
152 }
153 if (typeParameterMatcherFindCache != null) {
154 count ++;
155 }
156 if (stringBuilder != null) {
157 count ++;
158 }
159 if (charsetEncoderCache != null) {
160 count ++;
161 }
162 if (charsetDecoderCache != null) {
163 count ++;
164 }
165 if (arrayList != null) {
166 count ++;
167 }
168
169 for (Object o: indexedVariables) {
170 if (o != UNSET) {
171 count ++;
172 }
173 }
174
175
176
177 return count - 1;
178 }
179
180 public StringBuilder stringBuilder() {
181 StringBuilder sb = stringBuilder;
182 if (sb == null) {
183 return stringBuilder = new StringBuilder(STRING_BUILDER_INITIAL_SIZE);
184 }
185 if (sb.capacity() > STRING_BUILDER_MAX_SIZE) {
186 sb.setLength(STRING_BUILDER_INITIAL_SIZE);
187 sb.trimToSize();
188 }
189 sb.setLength(0);
190 return sb;
191 }
192
193 public Map<Charset, CharsetEncoder> charsetEncoderCache() {
194 Map<Charset, CharsetEncoder> cache = charsetEncoderCache;
195 if (cache == null) {
196 charsetEncoderCache = cache = new IdentityHashMap<Charset, CharsetEncoder>();
197 }
198 return cache;
199 }
200
201 public Map<Charset, CharsetDecoder> charsetDecoderCache() {
202 Map<Charset, CharsetDecoder> cache = charsetDecoderCache;
203 if (cache == null) {
204 charsetDecoderCache = cache = new IdentityHashMap<Charset, CharsetDecoder>();
205 }
206 return cache;
207 }
208
209 public <E> ArrayList<E> arrayList() {
210 return arrayList(DEFAULT_ARRAY_LIST_INITIAL_CAPACITY);
211 }
212
213 @SuppressWarnings("unchecked")
214 public <E> ArrayList<E> arrayList(int minCapacity) {
215 ArrayList<E> list = (ArrayList<E>) arrayList;
216 if (list == null) {
217 arrayList = new ArrayList<Object>(minCapacity);
218 return (ArrayList<E>) arrayList;
219 }
220 list.clear();
221 list.ensureCapacity(minCapacity);
222 return list;
223 }
224
225 public int futureListenerStackDepth() {
226 return futureListenerStackDepth;
227 }
228
229 public void setFutureListenerStackDepth(int futureListenerStackDepth) {
230 this.futureListenerStackDepth = futureListenerStackDepth;
231 }
232
233 public ThreadLocalRandom random() {
234 ThreadLocalRandom r = random;
235 if (r == null) {
236 random = r = new ThreadLocalRandom();
237 }
238 return r;
239 }
240
241 public Map<Class<?>, TypeParameterMatcher> typeParameterMatcherGetCache() {
242 Map<Class<?>, TypeParameterMatcher> cache = typeParameterMatcherGetCache;
243 if (cache == null) {
244 typeParameterMatcherGetCache = cache = new IdentityHashMap<Class<?>, TypeParameterMatcher>();
245 }
246 return cache;
247 }
248
249 public Map<Class<?>, Map<String, TypeParameterMatcher>> typeParameterMatcherFindCache() {
250 Map<Class<?>, Map<String, TypeParameterMatcher>> cache = typeParameterMatcherFindCache;
251 if (cache == null) {
252 typeParameterMatcherFindCache = cache = new IdentityHashMap<Class<?>, Map<String, TypeParameterMatcher>>();
253 }
254 return cache;
255 }
256
257 public IntegerHolder counterHashCode() {
258 return counterHashCode;
259 }
260
261 public void setCounterHashCode(IntegerHolder counterHashCode) {
262 this.counterHashCode = counterHashCode;
263 }
264
265 public Map<Class<?>, Boolean> handlerSharableCache() {
266 Map<Class<?>, Boolean> cache = handlerSharableCache;
267 if (cache == null) {
268
269 handlerSharableCache = cache = new WeakHashMap<Class<?>, Boolean>(4);
270 }
271 return cache;
272 }
273
274 public int localChannelReaderStackDepth() {
275 return localChannelReaderStackDepth;
276 }
277
278 public void setLocalChannelReaderStackDepth(int localChannelReaderStackDepth) {
279 this.localChannelReaderStackDepth = localChannelReaderStackDepth;
280 }
281
282 public Object indexedVariable(int index) {
283 Object[] lookup = indexedVariables;
284 return index < lookup.length? lookup[index] : UNSET;
285 }
286
287
288
289
290 public boolean setIndexedVariable(int index, Object value) {
291 Object[] lookup = indexedVariables;
292 if (index < lookup.length) {
293 Object oldValue = lookup[index];
294 lookup[index] = value;
295 return oldValue == UNSET;
296 } else {
297 expandIndexedVariableTableAndSet(index, value);
298 return true;
299 }
300 }
301
302 private void expandIndexedVariableTableAndSet(int index, Object value) {
303 Object[] oldArray = indexedVariables;
304 final int oldCapacity = oldArray.length;
305 int newCapacity = index;
306 newCapacity |= newCapacity >>> 1;
307 newCapacity |= newCapacity >>> 2;
308 newCapacity |= newCapacity >>> 4;
309 newCapacity |= newCapacity >>> 8;
310 newCapacity |= newCapacity >>> 16;
311 newCapacity ++;
312
313 Object[] newArray = Arrays.copyOf(oldArray, newCapacity);
314 Arrays.fill(newArray, oldCapacity, newArray.length, UNSET);
315 newArray[index] = value;
316 indexedVariables = newArray;
317 }
318
319 public Object removeIndexedVariable(int index) {
320 Object[] lookup = indexedVariables;
321 if (index < lookup.length) {
322 Object v = lookup[index];
323 lookup[index] = UNSET;
324 return v;
325 } else {
326 return UNSET;
327 }
328 }
329
330 public boolean isIndexedVariableSet(int index) {
331 Object[] lookup = indexedVariables;
332 return index < lookup.length && lookup[index] != UNSET;
333 }
334 }