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