1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.netty.buffer;
18
19 import io.netty.util.Recycler.EnhancedHandle;
20 import io.netty.util.internal.ObjectPool.Handle;
21
22 import java.io.IOException;
23 import java.nio.ByteBuffer;
24 import java.nio.ByteOrder;
25 import java.nio.channels.ClosedChannelException;
26 import java.nio.channels.FileChannel;
27 import java.nio.channels.GatheringByteChannel;
28 import java.nio.channels.ScatteringByteChannel;
29
30 abstract class PooledByteBuf<T> extends AbstractReferenceCountedByteBuf {
31
32 private final EnhancedHandle<PooledByteBuf<T>> recyclerHandle;
33
34 protected PoolChunk<T> chunk;
35 protected long handle;
36 protected T memory;
37 protected int offset;
38 protected int length;
39 int maxLength;
40 PoolThreadCache cache;
41 ByteBuffer tmpNioBuf;
42 private ByteBufAllocator allocator;
43
44 @SuppressWarnings("unchecked")
45 protected PooledByteBuf(Handle<? extends PooledByteBuf<T>> recyclerHandle, int maxCapacity) {
46 super(maxCapacity);
47 this.recyclerHandle = (EnhancedHandle<PooledByteBuf<T>>) recyclerHandle;
48 }
49
50 void init(PoolChunk<T> chunk, ByteBuffer nioBuffer,
51 long handle, int offset, int length, int maxLength, PoolThreadCache cache, boolean threadLocal) {
52 init0(chunk, nioBuffer, handle, offset, length, maxLength, cache, true, threadLocal);
53 }
54
55 void initUnpooled(PoolChunk<T> chunk, int length) {
56 init0(chunk, null, 0, 0, length, length, null, false,
57 false );
58 }
59
60 private void init0(PoolChunk<T> chunk, ByteBuffer nioBuffer, long handle, int offset, int length, int maxLength,
61 PoolThreadCache cache, boolean pooled, boolean threadLocal) {
62 assert handle >= 0;
63 assert chunk != null;
64 assert !PoolChunk.isSubpage(handle) ||
65 chunk.arena.sizeClass.size2SizeIdx(maxLength) <= chunk.arena.sizeClass.smallMaxSizeIdx:
66 "Allocated small sub-page handle for a buffer size that isn't \"small.\"";
67
68 chunk.incrementPinnedMemory(maxLength);
69 this.chunk = chunk;
70 memory = chunk.memory;
71 tmpNioBuf = nioBuffer;
72 allocator = chunk.arena.parent;
73 this.cache = cache;
74 this.handle = handle;
75 this.offset = offset;
76 this.length = length;
77 this.maxLength = maxLength;
78 PooledByteBufAllocator.onAllocateBuffer(this, pooled, threadLocal);
79 }
80
81
82
83
84 final void reuse(int maxCapacity) {
85 maxCapacity(maxCapacity);
86 resetRefCnt();
87 setIndex0(0, 0);
88 discardMarks();
89 }
90
91 @Override
92 public final int capacity() {
93 return length;
94 }
95
96 @Override
97 public int maxFastWritableBytes() {
98 return Math.min(maxLength, maxCapacity()) - writerIndex;
99 }
100
101 @Override
102 public final ByteBuf capacity(int newCapacity) {
103 if (newCapacity == length) {
104 ensureAccessible();
105 return this;
106 }
107 checkNewCapacity(newCapacity);
108 if (!chunk.unpooled) {
109
110 if (newCapacity > length) {
111 if (newCapacity <= maxLength) {
112 length = newCapacity;
113 return this;
114 }
115 } else if (newCapacity > maxLength >>> 1 &&
116 (maxLength > 512 || newCapacity > maxLength - 16)) {
117
118 length = newCapacity;
119 trimIndicesToCapacity(newCapacity);
120 return this;
121 }
122 }
123
124
125 PooledByteBufAllocator.onReallocateBuffer(this, newCapacity);
126 chunk.arena.reallocate(this, newCapacity);
127 return this;
128 }
129
130 @Override
131 public final ByteBufAllocator alloc() {
132 return allocator;
133 }
134
135 @Override
136 public final ByteOrder order() {
137 return ByteOrder.BIG_ENDIAN;
138 }
139
140 @Override
141 public final ByteBuf unwrap() {
142 return null;
143 }
144
145 @Override
146 public final ByteBuf retainedDuplicate() {
147 return PooledDuplicatedByteBuf.newInstance(this, this, readerIndex(), writerIndex());
148 }
149
150 @Override
151 public final ByteBuf retainedSlice() {
152 final int index = readerIndex();
153 return retainedSlice(index, writerIndex() - index);
154 }
155
156 @Override
157 public final ByteBuf retainedSlice(int index, int length) {
158 return PooledSlicedByteBuf.newInstance(this, this, index, length);
159 }
160
161 protected final ByteBuffer internalNioBuffer() {
162 ByteBuffer tmpNioBuf = this.tmpNioBuf;
163 if (tmpNioBuf == null) {
164 this.tmpNioBuf = tmpNioBuf = newInternalNioBuffer(memory);
165 } else {
166 tmpNioBuf.clear();
167 }
168 return tmpNioBuf;
169 }
170
171 protected abstract ByteBuffer newInternalNioBuffer(T memory);
172
173 @Override
174 protected final void deallocate() {
175 if (handle >= 0) {
176 PooledByteBufAllocator.onDeallocateBuffer(this);
177 final long handle = this.handle;
178 this.handle = -1;
179 memory = null;
180 chunk.arena.free(chunk, tmpNioBuf, handle, maxLength, cache);
181 tmpNioBuf = null;
182 chunk = null;
183 cache = null;
184 this.recyclerHandle.unguardedRecycle(this);
185 }
186 }
187
188 protected final int idx(int index) {
189 return offset + index;
190 }
191
192 final ByteBuffer _internalNioBuffer(int index, int length, boolean duplicate) {
193 index = idx(index);
194 ByteBuffer buffer = duplicate ? newInternalNioBuffer(memory) : internalNioBuffer();
195 buffer.limit(index + length).position(index);
196 return buffer;
197 }
198
199 ByteBuffer duplicateInternalNioBuffer(int index, int length) {
200 checkIndex(index, length);
201 return _internalNioBuffer(index, length, true);
202 }
203
204 @Override
205 public final ByteBuffer internalNioBuffer(int index, int length) {
206 checkIndex(index, length);
207 return _internalNioBuffer(index, length, false);
208 }
209
210 @Override
211 public final int nioBufferCount() {
212 return 1;
213 }
214
215 @Override
216 public final ByteBuffer nioBuffer(int index, int length) {
217 return duplicateInternalNioBuffer(index, length).slice();
218 }
219
220 @Override
221 public final ByteBuffer[] nioBuffers(int index, int length) {
222 return new ByteBuffer[] { nioBuffer(index, length) };
223 }
224
225 @Override
226 public final boolean isContiguous() {
227 return true;
228 }
229
230 @Override
231 public final int getBytes(int index, GatheringByteChannel out, int length) throws IOException {
232 return out.write(duplicateInternalNioBuffer(index, length));
233 }
234
235 @Override
236 public final int readBytes(GatheringByteChannel out, int length) throws IOException {
237 checkReadableBytes(length);
238 int readBytes = out.write(_internalNioBuffer(readerIndex, length, false));
239 readerIndex += readBytes;
240 return readBytes;
241 }
242
243 @Override
244 public final int getBytes(int index, FileChannel out, long position, int length) throws IOException {
245 return out.write(duplicateInternalNioBuffer(index, length), position);
246 }
247
248 @Override
249 public final int readBytes(FileChannel out, long position, int length) throws IOException {
250 checkReadableBytes(length);
251 int readBytes = out.write(_internalNioBuffer(readerIndex, length, false), position);
252 readerIndex += readBytes;
253 return readBytes;
254 }
255
256 @Override
257 public final int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
258 try {
259 return in.read(internalNioBuffer(index, length));
260 } catch (ClosedChannelException ignored) {
261 return -1;
262 }
263 }
264
265 @Override
266 public final int setBytes(int index, FileChannel in, long position, int length) throws IOException {
267 try {
268 return in.read(internalNioBuffer(index, length), position);
269 } catch (ClosedChannelException ignored) {
270 return -1;
271 }
272 }
273 }