1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
package com.yahoo.jdisc.http.server.jetty;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
import java.nio.ByteBuffer;
class ThreadLocalByteBufferPool implements ByteBufferPool {
static int bufferId(int size) {
return 32 - Integer.numberOfLeadingZeros(size);
}
private static class BufferList {
final ByteBuffer [] buffers = new ByteBuffer[16];
int latest = -1;
ByteBuffer acquire() {
if (latest == -1) return null;
ByteBuffer buf = buffers[latest];
buffers[latest] = null;
latest--;
return buf;
}
ByteBuffer release(ByteBuffer buf) {
if (latest >= (buffers.length - 1)) return buf;
buffers[++latest] = buf;
BufferUtil.clearToFill(buf);
return null;
}
}
private static class Cache {
private int cachedBytes = 0;
private final BufferList [] direct;
private final BufferList [] heap;
Cache(int numBufferClasses) {
direct = new BufferList[numBufferClasses];
heap = new BufferList[numBufferClasses];
for (int i=0; i < numBufferClasses; i++) {
direct[i] = new BufferList();
heap[i] = new BufferList();
}
}
ByteBuffer acquire(int bufferId, boolean direct) {
ByteBuffer buf = direct ? this.direct[bufferId].acquire() : this.heap[bufferId].acquire();
if (buf != null)
cachedBytes -= buf.capacity();
return buf;
}
ByteBuffer release(int bufferId, ByteBuffer buf) {
ByteBuffer overflow = buf.isDirect() ? direct[bufferId].release(buf) : heap[bufferId].release(buf);
if (overflow == null)
cachedBytes += buf.capacity();
return overflow;
}
}
private static class ThreadLocalCache extends ThreadLocal<Cache> {
private final int numBufferClasses;
ThreadLocalCache(int numBufferClasses) {
this.numBufferClasses = numBufferClasses;
}
@Override
protected Cache initialValue() {
return new Cache(numBufferClasses);
}
}
final private ByteBufferPool globalPool;
final private int maxCachedPerThread;
final private int lowestBufferId;
final private int largestBufferSize;
final private ThreadLocalCache cache;
ThreadLocalByteBufferPool(ByteBufferPool globalPool) {
this(globalPool, 0x100000, 1024, 0x40000);
}
ThreadLocalByteBufferPool(ByteBufferPool globalPool, int maxCachedPerThread, int smallestBufferSize, int largestBufferSize) {
this.globalPool = globalPool;
this.maxCachedPerThread = maxCachedPerThread;
this.lowestBufferId = bufferId(smallestBufferSize);
this.largestBufferSize = largestBufferSize;
cache = new ThreadLocalCache(bufferId(largestBufferSize));
}
@Override
public ByteBuffer acquire(int size, boolean direct) {
if (size <= largestBufferSize) {
ByteBuffer buf = cache.get().acquire(Integer.min(lowestBufferId, bufferId(size)), direct);
if (buf != null) return buf;
}
return globalPool.acquire(size, direct);
}
@Override
public void release(ByteBuffer buffer) {
if (buffer.capacity() <= largestBufferSize) {
Cache local = cache.get();
if (local.cachedBytes < maxCachedPerThread) {
buffer = local.release(Integer.max(lowestBufferId, bufferId(buffer.capacity())), buffer);
}
}
if (buffer != null) {
globalPool.release(buffer);
}
}
}
|