View Javadoc
1   /*
2    * Copyright 2013 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  
17  package io.netty.buffer;
18  
19  import io.netty.util.Recycler;
20  import io.netty.util.internal.PlatformDependent;
21  
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.io.OutputStream;
25  import java.nio.ByteBuffer;
26  import java.nio.channels.ClosedChannelException;
27  import java.nio.channels.FileChannel;
28  import java.nio.channels.GatheringByteChannel;
29  import java.nio.channels.ScatteringByteChannel;
30  
31  final class PooledUnsafeDirectByteBuf extends PooledByteBuf<ByteBuffer> {
32      private static final Recycler<PooledUnsafeDirectByteBuf> RECYCLER = new Recycler<PooledUnsafeDirectByteBuf>() {
33          @Override
34          protected PooledUnsafeDirectByteBuf newObject(Handle<PooledUnsafeDirectByteBuf> handle) {
35              return new PooledUnsafeDirectByteBuf(handle, 0);
36          }
37      };
38  
39      static PooledUnsafeDirectByteBuf newInstance(int maxCapacity) {
40          PooledUnsafeDirectByteBuf buf = RECYCLER.get();
41          buf.reuse(maxCapacity);
42          return buf;
43      }
44  
45      private long memoryAddress;
46  
47      private PooledUnsafeDirectByteBuf(Recycler.Handle<PooledUnsafeDirectByteBuf> recyclerHandle, int maxCapacity) {
48          super(recyclerHandle, maxCapacity);
49      }
50  
51      @Override
52      void init(PoolChunk<ByteBuffer> chunk, long handle, int offset, int length, int maxLength,
53                PoolThreadCache cache) {
54          super.init(chunk, handle, offset, length, maxLength, cache);
55          initMemoryAddress();
56      }
57  
58      @Override
59      void initUnpooled(PoolChunk<ByteBuffer> chunk, int length) {
60          super.initUnpooled(chunk, length);
61          initMemoryAddress();
62      }
63  
64      private void initMemoryAddress() {
65          memoryAddress = PlatformDependent.directBufferAddress(memory) + offset;
66      }
67  
68      @Override
69      protected ByteBuffer newInternalNioBuffer(ByteBuffer memory) {
70          return memory.duplicate();
71      }
72  
73      @Override
74      public boolean isDirect() {
75          return true;
76      }
77  
78      @Override
79      protected byte _getByte(int index) {
80          return UnsafeByteBufUtil.getByte(addr(index));
81      }
82  
83      @Override
84      protected short _getShort(int index) {
85          return UnsafeByteBufUtil.getShort(addr(index));
86      }
87  
88      @Override
89      protected short _getShortLE(int index) {
90          return UnsafeByteBufUtil.getShortLE(addr(index));
91      }
92  
93      @Override
94      protected int _getUnsignedMedium(int index) {
95          return UnsafeByteBufUtil.getUnsignedMedium(addr(index));
96      }
97  
98      @Override
99      protected int _getUnsignedMediumLE(int index) {
100         return UnsafeByteBufUtil.getUnsignedMediumLE(addr(index));
101     }
102 
103     @Override
104     protected int _getInt(int index) {
105         return UnsafeByteBufUtil.getInt(addr(index));
106     }
107 
108     @Override
109     protected int _getIntLE(int index) {
110         return UnsafeByteBufUtil.getIntLE(addr(index));
111     }
112 
113     @Override
114     protected long _getLong(int index) {
115         return UnsafeByteBufUtil.getLong(addr(index));
116     }
117 
118     @Override
119     protected long _getLongLE(int index) {
120         return UnsafeByteBufUtil.getLongLE(addr(index));
121     }
122 
123     @Override
124     public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
125         UnsafeByteBufUtil.getBytes(this, addr(index), index, dst, dstIndex, length);
126         return this;
127     }
128 
129     @Override
130     public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
131         UnsafeByteBufUtil.getBytes(this, addr(index), index, dst, dstIndex, length);
132         return this;
133     }
134 
135     @Override
136     public ByteBuf getBytes(int index, ByteBuffer dst) {
137         UnsafeByteBufUtil.getBytes(this, addr(index), index, dst);
138         return this;
139     }
140 
141     @Override
142     public ByteBuf readBytes(ByteBuffer dst) {
143         int length = dst.remaining();
144         checkReadableBytes(length);
145         getBytes(readerIndex, dst);
146         readerIndex += length;
147         return this;
148     }
149 
150     @Override
151     public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException {
152         UnsafeByteBufUtil.getBytes(this, addr(index), index, out, length);
153         return this;
154     }
155 
156     @Override
157     public int getBytes(int index, GatheringByteChannel out, int length) throws IOException {
158         return getBytes(index, out, length, false);
159     }
160 
161     private int getBytes(int index, GatheringByteChannel out, int length, boolean internal) throws IOException {
162         checkIndex(index, length);
163         if (length == 0) {
164             return 0;
165         }
166 
167         ByteBuffer tmpBuf;
168         if (internal) {
169             tmpBuf = internalNioBuffer();
170         } else {
171             tmpBuf = memory.duplicate();
172         }
173         index = idx(index);
174         tmpBuf.clear().position(index).limit(index + length);
175         return out.write(tmpBuf);
176     }
177 
178     @Override
179     public int getBytes(int index, FileChannel out, long position, int length) throws IOException {
180         return getBytes(index, out, position, length, false);
181     }
182 
183     private int getBytes(int index, FileChannel out, long position, int length, boolean internal) throws IOException {
184         checkIndex(index, length);
185         if (length == 0) {
186             return 0;
187         }
188 
189         ByteBuffer tmpBuf = internal ? internalNioBuffer() : memory.duplicate();
190         index = idx(index);
191         tmpBuf.clear().position(index).limit(index + length);
192         return out.write(tmpBuf, position);
193     }
194 
195     @Override
196     public int readBytes(GatheringByteChannel out, int length)
197             throws IOException {
198         checkReadableBytes(length);
199         int readBytes = getBytes(readerIndex, out, length, true);
200         readerIndex += readBytes;
201         return readBytes;
202     }
203 
204     @Override
205     public int readBytes(FileChannel out, long position, int length)
206             throws IOException {
207         checkReadableBytes(length);
208         int readBytes = getBytes(readerIndex, out, position, length, true);
209         readerIndex += readBytes;
210         return readBytes;
211     }
212 
213     @Override
214     protected void _setByte(int index, int value) {
215         UnsafeByteBufUtil.setByte(addr(index), (byte) value);
216     }
217 
218     @Override
219     protected void _setShort(int index, int value) {
220         UnsafeByteBufUtil.setShort(addr(index), value);
221     }
222 
223     @Override
224     protected void _setShortLE(int index, int value) {
225         UnsafeByteBufUtil.setShortLE(addr(index), value);
226     }
227 
228     @Override
229     protected void _setMedium(int index, int value) {
230         UnsafeByteBufUtil.setMedium(addr(index), value);
231     }
232 
233     @Override
234     protected void _setMediumLE(int index, int value) {
235         UnsafeByteBufUtil.setMediumLE(addr(index), value);
236     }
237 
238     @Override
239     protected void _setInt(int index, int value) {
240         UnsafeByteBufUtil.setInt(addr(index), value);
241     }
242 
243     @Override
244     protected void _setIntLE(int index, int value) {
245         UnsafeByteBufUtil.setIntLE(addr(index), value);
246     }
247 
248     @Override
249     protected void _setLong(int index, long value) {
250         UnsafeByteBufUtil.setLong(addr(index), value);
251     }
252 
253     @Override
254     protected void _setLongLE(int index, long value) {
255         UnsafeByteBufUtil.setLongLE(addr(index), value);
256     }
257 
258     @Override
259     public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
260         UnsafeByteBufUtil.setBytes(this, addr(index), index, src, srcIndex, length);
261         return this;
262     }
263 
264     @Override
265     public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
266         UnsafeByteBufUtil.setBytes(this, addr(index), index, src, srcIndex, length);
267         return this;
268     }
269 
270     @Override
271     public ByteBuf setBytes(int index, ByteBuffer src) {
272         UnsafeByteBufUtil.setBytes(this, addr(index), index, src);
273         return this;
274     }
275 
276     @Override
277     public int setBytes(int index, InputStream in, int length) throws IOException {
278         return UnsafeByteBufUtil.setBytes(this, addr(index), index, in, length);
279     }
280 
281     @Override
282     public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
283         checkIndex(index, length);
284         ByteBuffer tmpBuf = internalNioBuffer();
285         index = idx(index);
286         tmpBuf.clear().position(index).limit(index + length);
287         try {
288             return in.read(tmpBuf);
289         } catch (ClosedChannelException ignored) {
290             return -1;
291         }
292     }
293 
294     @Override
295     public int setBytes(int index, FileChannel in, long position, int length) throws IOException {
296         checkIndex(index, length);
297         ByteBuffer tmpBuf = internalNioBuffer();
298         index = idx(index);
299         tmpBuf.clear().position(index).limit(index + length);
300         try {
301             return in.read(tmpBuf, position);
302         } catch (ClosedChannelException ignored) {
303             return -1;
304         }
305     }
306 
307     @Override
308     public ByteBuf copy(int index, int length) {
309         return UnsafeByteBufUtil.copy(this, addr(index), index, length);
310     }
311 
312     @Override
313     public int nioBufferCount() {
314         return 1;
315     }
316 
317     @Override
318     public ByteBuffer[] nioBuffers(int index, int length) {
319         return new ByteBuffer[] { nioBuffer(index, length) };
320     }
321 
322     @Override
323     public ByteBuffer nioBuffer(int index, int length) {
324         checkIndex(index, length);
325         index = idx(index);
326         return ((ByteBuffer) memory.duplicate().position(index).limit(index + length)).slice();
327     }
328 
329     @Override
330     public ByteBuffer internalNioBuffer(int index, int length) {
331         checkIndex(index, length);
332         index = idx(index);
333         return (ByteBuffer) internalNioBuffer().clear().position(index).limit(index + length);
334     }
335 
336     @Override
337     public boolean hasArray() {
338         return false;
339     }
340 
341     @Override
342     public byte[] array() {
343         throw new UnsupportedOperationException("direct buffer");
344     }
345 
346     @Override
347     public int arrayOffset() {
348         throw new UnsupportedOperationException("direct buffer");
349     }
350 
351     @Override
352     public boolean hasMemoryAddress() {
353         return true;
354     }
355 
356     @Override
357     public long memoryAddress() {
358         ensureAccessible();
359         return memoryAddress;
360     }
361 
362     private long addr(int index) {
363         return memoryAddress + index;
364     }
365 
366     @Override
367     protected SwappedByteBuf newSwappedByteBuf() {
368         if (PlatformDependent.isUnaligned()) {
369             // Only use if unaligned access is supported otherwise there is no gain.
370             return new UnsafeDirectSwappedByteBuf(this);
371         }
372         return super.newSwappedByteBuf();
373     }
374 
375     @Override
376     public ByteBuf setZero(int index, int length) {
377         checkIndex(index, length);
378         UnsafeByteBufUtil.setZero(addr(index), length);
379         return this;
380     }
381 
382     @Override
383     public ByteBuf writeZero(int length) {
384         ensureWritable(length);
385         int wIndex = writerIndex;
386         UnsafeByteBufUtil.setZero(addr(wIndex), length);
387         writerIndex = wIndex + length;
388         return this;
389     }
390 }