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