View Javadoc
1   /*
2    * Copyright 2012 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    *   https://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  package io.netty.buffer;
17  
18  import io.netty.util.internal.ObjectUtil;
19  import io.netty.util.internal.PlatformDependent;
20  
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.io.OutputStream;
24  import java.nio.ByteBuffer;
25  import java.nio.ByteOrder;
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  import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
32  
33  /**
34   * A NIO {@link ByteBuffer} based buffer. It is recommended to use
35   * {@link UnpooledByteBufAllocator#directBuffer(int, int)}, {@link Unpooled#directBuffer(int)} and
36   * {@link Unpooled#wrappedBuffer(ByteBuffer)} instead of calling the constructor explicitly.
37   */
38  public class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf {
39  
40      private final ByteBufAllocator alloc;
41  
42      ByteBuffer buffer; // accessed by UnpooledUnsafeNoCleanerDirectByteBuf.reallocateDirect()
43      private ByteBuffer tmpNioBuf;
44      private int capacity;
45      private boolean doNotFree;
46      private final boolean allowSectionedInternalNioBufferAccess;
47  
48      /**
49       * Creates a new direct buffer.
50       *
51       * @param initialCapacity the initial capacity of the underlying direct buffer
52       * @param maxCapacity     the maximum capacity of the underlying direct buffer
53       */
54      public UnpooledDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
55          this(alloc, initialCapacity, maxCapacity, true);
56      }
57  
58      /**
59       * Creates a new direct buffer.
60       *
61       * @param initialCapacity the initial capacity of the underlying direct buffer
62       * @param maxCapacity     the maximum capacity of the underlying direct buffer
63       * @param allowSectionedInternalNioBufferAccess
64       * {@code true} if {@link #internalNioBuffer(int, int)} is allowed to be called,
65       * or {@code false} if it should throw an exception.
66       */
67      UnpooledDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity,
68                            boolean allowSectionedInternalNioBufferAccess) {
69          super(maxCapacity);
70          ObjectUtil.checkNotNull(alloc, "alloc");
71          checkPositiveOrZero(initialCapacity, "initialCapacity");
72          checkPositiveOrZero(maxCapacity, "maxCapacity");
73          if (initialCapacity > maxCapacity) {
74              throw new IllegalArgumentException(String.format(
75                      "initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity));
76          }
77  
78          this.alloc = alloc;
79          setByteBuffer(allocateDirect(initialCapacity), false);
80          this.allowSectionedInternalNioBufferAccess = allowSectionedInternalNioBufferAccess;
81      }
82  
83      /**
84       * Creates a new direct buffer by wrapping the specified initial buffer.
85       *
86       * @param maxCapacity the maximum capacity of the underlying direct buffer
87       */
88      protected UnpooledDirectByteBuf(ByteBufAllocator alloc, ByteBuffer initialBuffer, int maxCapacity) {
89          this(alloc, initialBuffer, maxCapacity, false, true);
90      }
91  
92      UnpooledDirectByteBuf(ByteBufAllocator alloc, ByteBuffer initialBuffer,
93              int maxCapacity, boolean doFree, boolean slice) {
94          super(maxCapacity);
95          ObjectUtil.checkNotNull(alloc, "alloc");
96          ObjectUtil.checkNotNull(initialBuffer, "initialBuffer");
97          if (!initialBuffer.isDirect()) {
98              throw new IllegalArgumentException("initialBuffer is not a direct buffer.");
99          }
100         if (initialBuffer.isReadOnly()) {
101             throw new IllegalArgumentException("initialBuffer is a read-only buffer.");
102         }
103 
104         int initialCapacity = initialBuffer.remaining();
105         if (initialCapacity > maxCapacity) {
106             throw new IllegalArgumentException(String.format(
107                     "initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity));
108         }
109 
110         this.alloc = alloc;
111         doNotFree = !doFree;
112         setByteBuffer((slice ? initialBuffer.slice() : initialBuffer).order(ByteOrder.BIG_ENDIAN), false);
113         writerIndex(initialCapacity);
114         allowSectionedInternalNioBufferAccess = true;
115     }
116 
117     /**
118      * Allocate a new direct {@link ByteBuffer} with the given initialCapacity.
119      */
120     protected ByteBuffer allocateDirect(int initialCapacity) {
121         return ByteBuffer.allocateDirect(initialCapacity);
122     }
123 
124     /**
125      * Free a direct {@link ByteBuffer}
126      */
127     protected void freeDirect(ByteBuffer buffer) {
128         PlatformDependent.freeDirectBuffer(buffer);
129     }
130 
131     void setByteBuffer(ByteBuffer buffer, boolean tryFree) {
132         if (tryFree) {
133             ByteBuffer oldBuffer = this.buffer;
134             if (oldBuffer != null) {
135                 if (doNotFree) {
136                     doNotFree = false;
137                 } else {
138                     freeDirect(oldBuffer);
139                 }
140             }
141         }
142 
143         this.buffer = buffer;
144         tmpNioBuf = null;
145         capacity = buffer.remaining();
146     }
147 
148     @Override
149     public boolean isDirect() {
150         return true;
151     }
152 
153     @Override
154     public int capacity() {
155         return capacity;
156     }
157 
158     @Override
159     public ByteBuf capacity(int newCapacity) {
160         checkNewCapacity(newCapacity);
161         int oldCapacity = capacity;
162         if (newCapacity == oldCapacity) {
163             return this;
164         }
165         int bytesToCopy;
166         if (newCapacity > oldCapacity) {
167             bytesToCopy = oldCapacity;
168         } else {
169             trimIndicesToCapacity(newCapacity);
170             bytesToCopy = newCapacity;
171         }
172         ByteBuffer oldBuffer = buffer;
173         ByteBuffer newBuffer = allocateDirect(newCapacity);
174         oldBuffer.position(0).limit(bytesToCopy);
175         newBuffer.position(0).limit(bytesToCopy);
176         newBuffer.put(oldBuffer).clear();
177         setByteBuffer(newBuffer, true);
178         return this;
179     }
180 
181     @Override
182     public ByteBufAllocator alloc() {
183         return alloc;
184     }
185 
186     @Override
187     public ByteOrder order() {
188         return ByteOrder.BIG_ENDIAN;
189     }
190 
191     @Override
192     public boolean hasArray() {
193         return false;
194     }
195 
196     @Override
197     public byte[] array() {
198         throw new UnsupportedOperationException("direct buffer");
199     }
200 
201     @Override
202     public int arrayOffset() {
203         throw new UnsupportedOperationException("direct buffer");
204     }
205 
206     @Override
207     public boolean hasMemoryAddress() {
208         return false;
209     }
210 
211     @Override
212     public long memoryAddress() {
213         throw new UnsupportedOperationException();
214     }
215 
216     @Override
217     public byte getByte(int index) {
218         ensureAccessible();
219         return _getByte(index);
220     }
221 
222     @Override
223     protected byte _getByte(int index) {
224         return buffer.get(index);
225     }
226 
227     @Override
228     public short getShort(int index) {
229         ensureAccessible();
230         return _getShort(index);
231     }
232 
233     @Override
234     protected short _getShort(int index) {
235         return buffer.getShort(index);
236     }
237 
238     @Override
239     protected short _getShortLE(int index) {
240         return ByteBufUtil.swapShort(buffer.getShort(index));
241     }
242 
243     @Override
244     public int getUnsignedMedium(int index) {
245         ensureAccessible();
246         return _getUnsignedMedium(index);
247     }
248 
249     @Override
250     protected int _getUnsignedMedium(int index) {
251         return (getByte(index) & 0xff)     << 16 |
252                (getByte(index + 1) & 0xff) << 8  |
253                getByte(index + 2) & 0xff;
254     }
255 
256     @Override
257     protected int _getUnsignedMediumLE(int index) {
258         return getByte(index) & 0xff             |
259                (getByte(index + 1) & 0xff) << 8  |
260                (getByte(index + 2) & 0xff) << 16;
261     }
262 
263     @Override
264     public int getInt(int index) {
265         ensureAccessible();
266         return _getInt(index);
267     }
268 
269     @Override
270     protected int _getInt(int index) {
271         return buffer.getInt(index);
272     }
273 
274     @Override
275     protected int _getIntLE(int index) {
276         return ByteBufUtil.swapInt(buffer.getInt(index));
277     }
278 
279     @Override
280     public long getLong(int index) {
281         ensureAccessible();
282         return _getLong(index);
283     }
284 
285     @Override
286     protected long _getLong(int index) {
287         return buffer.getLong(index);
288     }
289 
290     @Override
291     protected long _getLongLE(int index) {
292         return ByteBufUtil.swapLong(buffer.getLong(index));
293     }
294 
295     @Override
296     public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
297         checkDstIndex(index, length, dstIndex, dst.capacity());
298         if (dst.hasArray()) {
299             getBytes(index, dst.array(), dst.arrayOffset() + dstIndex, length);
300         } else if (dst.nioBufferCount() > 0) {
301             for (ByteBuffer bb: dst.nioBuffers(dstIndex, length)) {
302                 int bbLen = bb.remaining();
303                 getBytes(index, bb);
304                 index += bbLen;
305             }
306         } else {
307             dst.setBytes(dstIndex, this, index, length);
308         }
309         return this;
310     }
311 
312     @Override
313     public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
314         getBytes(index, dst, dstIndex, length, false);
315         return this;
316     }
317 
318     void getBytes(int index, byte[] dst, int dstIndex, int length, boolean internal) {
319         checkDstIndex(index, length, dstIndex, dst.length);
320 
321         ByteBuffer tmpBuf;
322         if (internal) {
323             tmpBuf = internalNioBuffer(index, length);
324         } else {
325             tmpBuf = (ByteBuffer) buffer.duplicate().clear().position(index).limit(index + length);
326         }
327         tmpBuf.get(dst, dstIndex, length);
328     }
329 
330     @Override
331     public ByteBuf readBytes(byte[] dst, int dstIndex, int length) {
332         checkReadableBytes(length);
333         getBytes(readerIndex, dst, dstIndex, length, true);
334         readerIndex += length;
335         return this;
336     }
337 
338     @Override
339     public ByteBuf getBytes(int index, ByteBuffer dst) {
340         getBytes(index, dst, false);
341         return this;
342     }
343 
344     void getBytes(int index, ByteBuffer dst, boolean internal) {
345         checkIndex(index, dst.remaining());
346 
347         ByteBuffer tmpBuf;
348         if (internal) {
349             tmpBuf = internalNioBuffer(index, dst.remaining());
350         } else {
351             tmpBuf = (ByteBuffer) buffer.duplicate().clear().position(index).limit(index + dst.remaining());
352         }
353         dst.put(tmpBuf);
354     }
355 
356     @Override
357     public ByteBuf readBytes(ByteBuffer dst) {
358         int length = dst.remaining();
359         checkReadableBytes(length);
360         getBytes(readerIndex, dst, true);
361         readerIndex += length;
362         return this;
363     }
364 
365     @Override
366     public ByteBuf setByte(int index, int value) {
367         ensureAccessible();
368         _setByte(index, value);
369         return this;
370     }
371 
372     @Override
373     protected void _setByte(int index, int value) {
374         buffer.put(index, (byte) value);
375     }
376 
377     @Override
378     public ByteBuf setShort(int index, int value) {
379         ensureAccessible();
380         _setShort(index, value);
381         return this;
382     }
383 
384     @Override
385     protected void _setShort(int index, int value) {
386         buffer.putShort(index, (short) value);
387     }
388 
389     @Override
390     protected void _setShortLE(int index, int value) {
391         buffer.putShort(index, ByteBufUtil.swapShort((short) value));
392     }
393 
394     @Override
395     public ByteBuf setMedium(int index, int value) {
396         ensureAccessible();
397         _setMedium(index, value);
398         return this;
399     }
400 
401     @Override
402     protected void _setMedium(int index, int value) {
403         setByte(index, (byte) (value >>> 16));
404         setByte(index + 1, (byte) (value >>> 8));
405         setByte(index + 2, (byte) value);
406     }
407 
408     @Override
409     protected void _setMediumLE(int index, int value) {
410         setByte(index, (byte) value);
411         setByte(index + 1, (byte) (value >>> 8));
412         setByte(index + 2, (byte) (value >>> 16));
413     }
414 
415     @Override
416     public ByteBuf setInt(int index, int value) {
417         ensureAccessible();
418         _setInt(index, value);
419         return this;
420     }
421 
422     @Override
423     protected void _setInt(int index, int value) {
424         buffer.putInt(index, value);
425     }
426 
427     @Override
428     protected void _setIntLE(int index, int value) {
429         buffer.putInt(index, ByteBufUtil.swapInt(value));
430     }
431 
432     @Override
433     public ByteBuf setLong(int index, long value) {
434         ensureAccessible();
435         _setLong(index, value);
436         return this;
437     }
438 
439     @Override
440     protected void _setLong(int index, long value) {
441         buffer.putLong(index, value);
442     }
443 
444     @Override
445     protected void _setLongLE(int index, long value) {
446         buffer.putLong(index, ByteBufUtil.swapLong(value));
447     }
448 
449     @Override
450     public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
451         checkSrcIndex(index, length, srcIndex, src.capacity());
452         if (src.nioBufferCount() > 0) {
453             for (ByteBuffer bb: src.nioBuffers(srcIndex, length)) {
454                 int bbLen = bb.remaining();
455                 setBytes(index, bb);
456                 index += bbLen;
457             }
458         } else {
459             src.getBytes(srcIndex, this, index, length);
460         }
461         return this;
462     }
463 
464     @Override
465     public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
466         checkSrcIndex(index, length, srcIndex, src.length);
467         ByteBuffer tmpBuf = internalNioBuffer(index, length);
468         tmpBuf.put(src, srcIndex, length);
469         return this;
470     }
471 
472     @Override
473     public ByteBuf setBytes(int index, ByteBuffer src) {
474         ensureAccessible();
475         if (src == tmpNioBuf) {
476             src = src.duplicate();
477         }
478         ByteBuffer tmpBuf = internalNioBuffer(index, src.remaining());
479         tmpBuf.put(src);
480         return this;
481     }
482 
483     @Override
484     public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException {
485         getBytes(index, out, length, false);
486         return this;
487     }
488 
489     void getBytes(int index, OutputStream out, int length, boolean internal) throws IOException {
490         ensureAccessible();
491         if (length == 0) {
492             return;
493         }
494         ByteBufUtil.readBytes(alloc(), internal ? internalNioBuffer() : buffer.duplicate(), index, length, out);
495     }
496 
497     @Override
498     public ByteBuf readBytes(OutputStream out, int length) throws IOException {
499         checkReadableBytes(length);
500         getBytes(readerIndex, out, length, true);
501         readerIndex += length;
502         return this;
503     }
504 
505     @Override
506     public int getBytes(int index, GatheringByteChannel out, int length) throws IOException {
507         return getBytes(index, out, length, false);
508     }
509 
510     private int getBytes(int index, GatheringByteChannel out, int length, boolean internal) throws IOException {
511         ensureAccessible();
512         if (length == 0) {
513             return 0;
514         }
515 
516         ByteBuffer tmpBuf;
517         if (internal) {
518             tmpBuf = internalNioBuffer(index, length);
519         } else {
520             tmpBuf = (ByteBuffer) buffer.duplicate().clear().position(index).limit(index + length);
521         }
522         return out.write(tmpBuf);
523     }
524 
525     @Override
526     public int getBytes(int index, FileChannel out, long position, int length) throws IOException {
527         return getBytes(index, out, position, length, false);
528     }
529 
530     private int getBytes(int index, FileChannel out, long position, int length, boolean internal) throws IOException {
531         ensureAccessible();
532         if (length == 0) {
533             return 0;
534         }
535 
536         ByteBuffer tmpBuf = internal ? internalNioBuffer(index, length) :
537                 (ByteBuffer) buffer.duplicate().clear().position(index).limit(index + length);
538         return out.write(tmpBuf, position);
539     }
540 
541     @Override
542     public int readBytes(GatheringByteChannel out, int length) throws IOException {
543         checkReadableBytes(length);
544         int readBytes = getBytes(readerIndex, out, length, true);
545         readerIndex += readBytes;
546         return readBytes;
547     }
548 
549     @Override
550     public int readBytes(FileChannel out, long position, int length) throws IOException {
551         checkReadableBytes(length);
552         int readBytes = getBytes(readerIndex, out, position, length, true);
553         readerIndex += readBytes;
554         return readBytes;
555     }
556 
557     @Override
558     public int setBytes(int index, InputStream in, int length) throws IOException {
559         ensureAccessible();
560         if (buffer.hasArray()) {
561             return in.read(buffer.array(), buffer.arrayOffset() + index, length);
562         } else {
563             byte[] tmp = ByteBufUtil.threadLocalTempArray(length);
564             int readBytes = in.read(tmp, 0, length);
565             if (readBytes <= 0) {
566                 return readBytes;
567             }
568             ByteBuffer tmpBuf = internalNioBuffer(index, readBytes);
569             tmpBuf.put(tmp, 0, readBytes);
570             return readBytes;
571         }
572     }
573 
574     @Override
575     public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
576         ensureAccessible();
577         ByteBuffer tmpBuf = internalNioBuffer(index, length);
578         try {
579             return in.read(tmpBuf);
580         } catch (ClosedChannelException ignored) {
581             return -1;
582         }
583     }
584 
585     @Override
586     public int setBytes(int index, FileChannel in, long position, int length) throws IOException {
587         ensureAccessible();
588         ByteBuffer tmpBuf = internalNioBuffer(index, length);
589         try {
590             return in.read(tmpBuf, position);
591         } catch (ClosedChannelException ignored) {
592             return -1;
593         }
594     }
595 
596     @Override
597     public int nioBufferCount() {
598         return 1;
599     }
600 
601     @Override
602     public ByteBuffer[] nioBuffers(int index, int length) {
603         return new ByteBuffer[] { nioBuffer(index, length) };
604     }
605 
606     @Override
607     public final boolean isContiguous() {
608         return true;
609     }
610 
611     @Override
612     public ByteBuf copy(int index, int length) {
613         ensureAccessible();
614         ByteBuffer src;
615         try {
616             src = (ByteBuffer) buffer.duplicate().clear().position(index).limit(index + length);
617         } catch (IllegalArgumentException ignored) {
618             throw new IndexOutOfBoundsException("Too many bytes to read - Need " + (index + length));
619         }
620 
621         return alloc().directBuffer(length, maxCapacity()).writeBytes(src);
622     }
623 
624     @Override
625     public ByteBuffer internalNioBuffer(int index, int length) {
626         checkIndex(index, length);
627         if (!allowSectionedInternalNioBufferAccess) {
628             throw new UnsupportedOperationException("Bug: unsafe access to shared internal chunk buffer");
629         }
630         return (ByteBuffer) internalNioBuffer().clear().position(index).limit(index + length);
631     }
632 
633     private ByteBuffer internalNioBuffer() {
634         ByteBuffer tmpNioBuf = this.tmpNioBuf;
635         if (tmpNioBuf == null) {
636             this.tmpNioBuf = tmpNioBuf = buffer.duplicate();
637         }
638         return tmpNioBuf;
639     }
640 
641     @Override
642     public ByteBuffer nioBuffer(int index, int length) {
643         checkIndex(index, length);
644         return ((ByteBuffer) buffer.duplicate().position(index).limit(index + length)).slice();
645     }
646 
647     @Override
648     protected void deallocate() {
649         ByteBuffer buffer = this.buffer;
650         if (buffer == null) {
651             return;
652         }
653 
654         this.buffer = null;
655 
656         if (!doNotFree) {
657             freeDirect(buffer);
658         }
659     }
660 
661     @Override
662     public ByteBuf unwrap() {
663         return null;
664     }
665 }