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