/*
 * Copyright 2012 The Netty Project
 *
 * The Netty Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

Abstraction of a byte buffer - the fundamental data structure to represent a low-level binary and text message. Netty uses its own buffer API instead of NIO ByteBuffer to represent a sequence of bytes. This approach has significant advantage over using ByteBuffer. Netty's new buffer type, ByteBuf, has been designed from ground up to address the problems of ByteBuffer and to meet the daily needs of network application developers. To list a few cool features:
  • You can define your buffer type if necessary.
  • Transparent zero copy is achieved by built-in composite buffer type.
  • A dynamic buffer type is provided out-of-the-box, whose capacity is expanded on demand, just like StringBuffer.
  • There's no need to call the flip() method anymore.
  • It is often faster than ByteBuffer.

Extensibility

ByteBuf has rich set of operations optimized for rapid protocol implementation. For example, ByteBuf provides various operations for accessing unsigned values and strings and searching for certain byte sequence in a buffer. You can also extend or wrap existing buffer type to add convenient accessors. The custom buffer type still implements ByteBuf interface rather than introducing an incompatible type.

Transparent Zero Copy

To lift up the performance of a network application to the extreme, you need to reduce the number of memory copy operation. You might have a set of buffers that could be sliced and combined to compose a whole message. Netty provides a composite buffer which allows you to create a new buffer from the arbitrary number of existing buffers with no memory copy. For example, a message could be composed of two parts; header and body. In a modularized application, the two parts could be produced by different modules and assembled later when the message is sent out.
+--------+----------+
| header |   body   |
+--------+----------+
If ByteBuffer were used, you would have to create a new big buffer and copy the two parts into the new buffer. Alternatively, you can perform a gathering write operation in NIO, but it restricts you to represent the composite of buffers as an array of ByteBuffers rather than a single buffer, breaking the abstraction and introducing complicated state management. Moreover, it's of no use if you are not going to read or write from an NIO channel.
// The composite type is incompatible with the component type.
ByteBuffer[] message = new ByteBuffer[] { header, body };
By contrast, ByteBuf does not have such caveats because it is fully extensible and has a built-in composite buffer type.
// The composite type is compatible with the component type. ByteBuf message = Unpooled.wrappedBuffer(header, body); // Therefore, you can even create a composite by mixing a composite and an // ordinary buffer. ByteBuf messageWithFooter = Unpooled.wrappedBuffer(message, footer); // Because the composite is still a ByteBuf, you can access its content // easily, and the accessor method will behave just like it's a single buffer // even if the region you want to access spans over multiple components. The // unsigned integer being read here is located across body and footer. messageWithFooter.getUnsignedInt( messageWithFooter.readableBytes() - footer.readableBytes() - 1); 

Automatic Capacity Extension

Many protocols define variable length messages, which means there's no way to determine the length of a message until you construct the message or it is difficult and inconvenient to calculate the length precisely. It is just like when you build a String. You often estimate the length of the resulting string and let StringBuffer expand itself on demand.
// A new dynamic buffer is created. Internally, the actual buffer is created // lazily to avoid potentially wasted memory space. ByteBuf b = Unpooled.buffer(4); // When the first write attempt is made, the internal buffer is created with // the specified initial capacity (4). b.writeByte('1'); b.writeByte('2'); b.writeByte('3'); b.writeByte('4'); // When the number of written bytes exceeds the initial capacity (4), the // internal buffer is reallocated automatically with a larger capacity. b.writeByte('5'); 

Better Performance

Most frequently used buffer implementation of ByteBuf is a very thin wrapper of a byte array (i.e. byte[]). Unlike ByteBuffer, it has no complicated boundary check and index compensation, and therefore it is easier for a JVM to optimize the buffer access. More complicated buffer implementation is used only for sliced or composite buffers, and it performs as well as ByteBuffer.
/** * Abstraction of a byte buffer - the fundamental data structure * to represent a low-level binary and text message. * * Netty uses its own buffer API instead of NIO {@link java.nio.ByteBuffer} to * represent a sequence of bytes. This approach has significant advantage over * using {@link java.nio.ByteBuffer}. Netty's new buffer type, * {@link io.netty.buffer.ByteBuf}, has been designed from ground * up to address the problems of {@link java.nio.ByteBuffer} and to meet the * daily needs of network application developers. To list a few cool features: * <ul> * <li>You can define your buffer type if necessary.</li> * <li>Transparent zero copy is achieved by built-in composite buffer type.</li> * <li>A dynamic buffer type is provided out-of-the-box, whose capacity is * expanded on demand, just like {@link java.lang.StringBuffer}.</li> * <li>There's no need to call the {@code flip()} method anymore.</li> * <li>It is often faster than {@link java.nio.ByteBuffer}.</li> * </ul> * * <h3>Extensibility</h3> * * {@link io.netty.buffer.ByteBuf} has rich set of operations * optimized for rapid protocol implementation. For example, * {@link io.netty.buffer.ByteBuf} provides various operations * for accessing unsigned values and strings and searching for certain byte * sequence in a buffer. You can also extend or wrap existing buffer type * to add convenient accessors. The custom buffer type still implements * {@link io.netty.buffer.ByteBuf} interface rather than * introducing an incompatible type. * * <h3>Transparent Zero Copy</h3> * * To lift up the performance of a network application to the extreme, you need * to reduce the number of memory copy operation. You might have a set of * buffers that could be sliced and combined to compose a whole message. Netty * provides a composite buffer which allows you to create a new buffer from the * arbitrary number of existing buffers with no memory copy. For example, a * message could be composed of two parts; header and body. In a modularized * application, the two parts could be produced by different modules and * assembled later when the message is sent out. * <pre> * +--------+----------+ * | header | body | * +--------+----------+ * </pre> * If {@link java.nio.ByteBuffer} were used, you would have to create a new big * buffer and copy the two parts into the new buffer. Alternatively, you can * perform a gathering write operation in NIO, but it restricts you to represent * the composite of buffers as an array of {@link java.nio.ByteBuffer}s rather * than a single buffer, breaking the abstraction and introducing complicated * state management. Moreover, it's of no use if you are not going to read or * write from an NIO channel. * <pre> * // The composite type is incompatible with the component type. * ByteBuffer[] message = new ByteBuffer[] { header, body }; * </pre> * By contrast, {@link io.netty.buffer.ByteBuf} does not have such * caveats because it is fully extensible and has a built-in composite buffer * type. * <pre> * // The composite type is compatible with the component type. * {@link io.netty.buffer.ByteBuf} message = {@link io.netty.buffer.Unpooled}.wrappedBuffer(header, body); * * // Therefore, you can even create a composite by mixing a composite and an * // ordinary buffer. * {@link io.netty.buffer.ByteBuf} messageWithFooter = {@link io.netty.buffer.Unpooled}.wrappedBuffer(message, footer); * * // Because the composite is still a {@link io.netty.buffer.ByteBuf}, you can access its content * // easily, and the accessor method will behave just like it's a single buffer * // even if the region you want to access spans over multiple components. The * // unsigned integer being read here is located across body and footer. * messageWithFooter.getUnsignedInt( * messageWithFooter.readableBytes() - footer.readableBytes() - 1); * </pre> * * <h3>Automatic Capacity Extension</h3> * * Many protocols define variable length messages, which means there's no way to * determine the length of a message until you construct the message or it is * difficult and inconvenient to calculate the length precisely. It is just * like when you build a {@link java.lang.String}. You often estimate the length * of the resulting string and let {@link java.lang.StringBuffer} expand itself * on demand. * <pre> * // A new dynamic buffer is created. Internally, the actual buffer is created * // lazily to avoid potentially wasted memory space. * {@link io.netty.buffer.ByteBuf} b = {@link io.netty.buffer.Unpooled}.buffer(4); * * // When the first write attempt is made, the internal buffer is created with * // the specified initial capacity (4). * b.writeByte('1'); * * b.writeByte('2'); * b.writeByte('3'); * b.writeByte('4'); * * // When the number of written bytes exceeds the initial capacity (4), the * // internal buffer is reallocated automatically with a larger capacity. * b.writeByte('5'); * </pre> * * <h3>Better Performance</h3> * * Most frequently used buffer implementation of * {@link io.netty.buffer.ByteBuf} is a very thin wrapper of a * byte array (i.e. {@code byte[]}). Unlike {@link java.nio.ByteBuffer}, it has * no complicated boundary check and index compensation, and therefore it is * easier for a JVM to optimize the buffer access. More complicated buffer * implementation is used only for sliced or composite buffers, and it performs * as well as {@link java.nio.ByteBuffer}. */
package io.netty.buffer;