下面列出了 io.netty.handler.codec.http.websocketx.ContinuationWebSocketFrame #io.netty.buffer.CompositeByteBuf 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
public static ByteBuf encodePacket(final Packet packet) throws IOException {
ByteBuf dataBytes = packet.getData();
boolean hasData = dataBytes != null;
CompositeByteBuf compositeByteBuf = PooledByteBufAllocator.DEFAULT.compositeBuffer(hasData ? 1 : 2);
byte[] typeBytes = packet.getType().getValueAsBytes();
int headerCapacity = typeBytes.length + DELIMITER_LENGTH + DELIMITER_LENGTH + (hasData ? DELIMITER_LENGTH : 0);
ByteBuf headerByteBuf = PooledByteBufAllocator.DEFAULT.buffer(headerCapacity, headerCapacity);
headerByteBuf.writeBytes(typeBytes);
headerByteBuf.writeBytes(DELIMITER_BYTES);
headerByteBuf.writeBytes(DELIMITER_BYTES);
if (hasData) {
headerByteBuf.writeBytes(DELIMITER_BYTES);
}
compositeByteBuf.addComponent(headerByteBuf);
int compositeReadableBytes = headerByteBuf.readableBytes();
if (hasData) {
compositeByteBuf.addComponent(dataBytes);
compositeReadableBytes += dataBytes.readableBytes();
}
compositeByteBuf.writerIndex(compositeReadableBytes);
return compositeByteBuf;
}
@Test
public void writableNioBuffers_worksWithComposite() {
CompositeByteBuf buf = alloc.compositeBuffer();
buf.addComponent(alloc.buffer(1));
buf.capacity(1);
try (BufUnwrapper unwrapper = new BufUnwrapper()) {
ByteBuffer[] internalBufs = unwrapper.writableNioBuffers(buf);
Truth.assertThat(internalBufs).hasLength(1);
internalBufs[0].put((byte) 'a');
buf.writerIndex(1);
assertEquals('a', buf.readByte());
} finally {
buf.release();
}
}
void cancelAssemble(int streamId) {
ByteBuf header = removeHeader(streamId);
CompositeByteBuf metadata = removeMetadata(streamId);
CompositeByteBuf data = removeData(streamId);
if (header != null) {
ReferenceCountUtil.safeRelease(header);
}
if (metadata != null) {
ReferenceCountUtil.safeRelease(metadata);
}
if (data != null) {
ReferenceCountUtil.safeRelease(data);
}
}
/**
* Encode a new sub-metadata information into a composite metadata {@link CompositeByteBuf
* buffer}, first verifying if the passed {@link String} matches a {@link WellKnownMimeType} (in
* which case it will be encoded in a compressed fashion using the mime id of that type).
*
* <p>Prefer using {@link #encodeAndAddMetadata(CompositeByteBuf, ByteBufAllocator, String,
* ByteBuf)} if you already know that the mime type is not a {@link WellKnownMimeType}.
*
* @param compositeMetaData the buffer that will hold all composite metadata information.
* @param allocator the {@link ByteBufAllocator} to use to create intermediate buffers as needed.
* @param mimeType the mime type to encode, as a {@link String}. well known mime types are
* compressed.
* @param metadata the metadata value to encode.
* @see #encodeAndAddMetadata(CompositeByteBuf, ByteBufAllocator, WellKnownMimeType, ByteBuf)
*/
// see #encodeMetadataHeader(ByteBufAllocator, String, int)
public static void encodeAndAddMetadataWithCompression(
CompositeByteBuf compositeMetaData,
ByteBufAllocator allocator,
String mimeType,
ByteBuf metadata) {
WellKnownMimeType wkn = WellKnownMimeType.fromString(mimeType);
if (wkn == WellKnownMimeType.UNPARSEABLE_MIME_TYPE) {
compositeMetaData.addComponents(
true, encodeMetadataHeader(allocator, mimeType, metadata.readableBytes()), metadata);
} else {
compositeMetaData.addComponents(
true,
encodeMetadataHeader(allocator, wkn.getIdentifier(), metadata.readableBytes()),
metadata);
}
}
@Test
public void writesBytesIntoPooledBuffer() throws IOException {
// given
ByteBufDeserializer deserializer = spy(new ByteBufDeserializer());
ByteBufAllocator allocator = mock(ByteBufAllocator.class);
when(deserializer.allocator()).thenReturn(allocator);
CompositeByteBuf byteBuf = mock(CompositeByteBuf.class);
when(allocator.compositeBuffer(eq(2))).thenReturn(byteBuf);
JsonParser jsonParser = mock(JsonParser.class);
byte[] bytes = UUID.randomUUID().toString().getBytes();
when(jsonParser.getBinaryValue()).thenReturn(bytes);
// when
deserializer.deserialize(jsonParser, null);
// then
verify(byteBuf).writeBytes(eq(bytes));
}
@Test
public void jacksonInjectedReleaseCallbackDoesNotThrow() throws IOException {
// given
FailedItemMarshaller failedItemMarshaller = new FailedItemMarshaller();
CompositeByteBuf byteBuf = new CompositeByteBuf(PooledByteBufAllocator.DEFAULT, false, 2).capacity(1024);
ByteBufItemSource itemSource = new ByteBufItemSource(byteBuf, source -> {});
FailedItemSource<ByteBuf> failedItemSource =
new FailedItemSource<>(itemSource, new FailedItemInfo(UUID.randomUUID().toString()));
ReusableByteBufOutputStream outputStream =
new ReusableByteBufOutputStream(byteBuf);
failedItemMarshaller.objectMapper().writeValue((OutputStream) outputStream, failedItemSource);
Bytes<Object> in = mock(Bytes.class);
ByteArrayInputStream inputStream = new ByteArrayInputStream(byteBuf.array());
when(in.inputStream()).thenReturn(inputStream);
FailedItemSource deserialized = (FailedItemSource) failedItemMarshaller.read(in, null);
// when
deserialized.release();
}
private static ByteBuf encode(EmbeddedChannel ch, Envelope... envelopes) {
for (Envelope env : envelopes) {
ch.writeOutbound(env);
if (env.getBuffer() != null) {
verify(env.getBuffer(), times(1)).recycleBuffer();
}
}
CompositeByteBuf encodedEnvelopes = new CompositeByteBuf(ByteBufAllocator.DEFAULT, false, envelopes.length);
ByteBuf buf;
while ((buf = (ByteBuf) ch.readOutbound()) != null) {
encodedEnvelopes.addComponent(buf);
}
return encodedEnvelopes.writerIndex(encodedEnvelopes.capacity());
}
@Override
public List<Object> encode(ByteBufAllocator alloc) {
ByteBuf meta = metadata(alloc);
ByteBuf head = alloc.buffer(FDFS_HEAD_LEN);
head.writeLong(meta.readableBytes() + size);
head.writeByte(cmd());
head.writeByte(ERRNO_OK);
CompositeByteBuf cbb = alloc.compositeBuffer();
cbb.addComponents(head, meta);
cbb.writerIndex(head.readableBytes() + meta.readableBytes());
List<Object> requests = new LinkedList<>();
requests.add(cbb);
requests.add(content);
return requests;
}
@Test
public void testNetty(){
CompositeByteBuf byteBuf = ByteBufAllocator.DEFAULT.compositeBuffer();
byteBuf.addComponent(Unpooled.wrappedBuffer("12345".getBytes()));
byteBuf.addComponent(Unpooled.wrappedBuffer("abcde".getBytes()));
System.out.println(ByteBufUtils.readToString(byteBuf));
ByteBuf buf = Unpooled.wrappedBuffer(Unpooled.wrappedBuffer("134".getBytes()), Unpooled.wrappedBuffer("abc".getBytes()));
System.out.println(buf.readableBytes());
byte []result = new byte[buf.readableBytes()];
buf.readBytes(result);
System.out.println(new String(result));
}
protected final ByteBuf captureWrite(ChannelHandlerContext ctx) {
ArgumentCaptor<ByteBuf> captor = ArgumentCaptor.forClass(ByteBuf.class);
verify(ctx, atLeastOnce()).write(captor.capture(), any(ChannelPromise.class));
CompositeByteBuf composite = Unpooled.compositeBuffer();
for (ByteBuf buf : captor.getAllValues()) {
composite.addComponent(buf);
composite.writerIndex(composite.writerIndex() + buf.readableBytes());
}
return composite;
}
/**
* Aggregate subsequent byte buffers into a single buffer.
*
* @return {@link ByteBufMono} of aggregated {@link ByteBuf}
*/
public final ByteBufMono aggregate() {
return Mono.defer(() -> {
CompositeByteBuf output = alloc.compositeBuffer();
return doOnNext(ByteBuf::retain)
.collectList()
.doOnDiscard(ByteBuf.class, ByteBufFlux::safeRelease)
.handle((list, sink) -> {
if (!list.isEmpty()) {
try {
output.addComponents(true, list);
}
catch(IllegalReferenceCountException e) {
if (log.isDebugEnabled()) {
log.debug("", e);
}
}
}
if (output.isReadable()) {
sink.next(output);
}
else {
sink.complete();
}
})
.doFinally(signalType -> safeRelease(output));
})
.as(ByteBufMono::maybeFuse);
}
@Override
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
if (RpcConstants.EXTRA_DEBUGGING) {
logger.debug("ChunkCreationHandler called with msg {} of size {} with chunkSize {}",
msg, msg.readableBytes(), chunkSize);
}
if (!ctx.channel().isOpen()) {
logger.debug("Channel closed, skipping encode inside {}.", RpcConstants.CHUNK_CREATION_HANDLER);
msg.release();
return;
}
// Calculate the number of chunks based on configured chunk size and input msg size
int numChunks = (int) Math.ceil((double) msg.readableBytes() / chunkSize);
// Initialize a composite buffer to hold numChunks chunk.
final CompositeByteBuf cbb = ctx.alloc().compositeBuffer(numChunks);
int cbbWriteIndex = 0;
int currentChunkLen = min(msg.readableBytes(), chunkSize);
// Create slices of chunkSize from input msg and add it to the composite buffer.
while (numChunks > 0) {
final ByteBuf chunkBuf = msg.slice(msg.readerIndex(), currentChunkLen);
chunkBuf.retain();
cbb.addComponent(chunkBuf);
cbbWriteIndex += currentChunkLen;
msg.skipBytes(currentChunkLen);
--numChunks;
currentChunkLen = min(msg.readableBytes(), chunkSize);
}
// Update the writerIndex of composite byte buffer. Netty doesn't do it automatically.
cbb.writerIndex(cbbWriteIndex);
// Add the final composite bytebuf into output buffer.
out.add(cbb);
}
@Override
public ByteBuf compress(ByteBuf uncompressed, int headerLen) {
checkNotNull(uncompressed);
checkArgument(uncompressed.readableBytes() >= 0);
if (headerLen == 0) {
return uncompressed.retain();
} else {
CompositeByteBuf composited = PooledByteBufAllocator.DEFAULT.compositeBuffer(2);
composited.addComponent(PooledByteBufAllocator.DEFAULT.buffer(headerLen, headerLen));
composited.addComponent(uncompressed.retain());
return composited;
}
}
/**
* {@inheritDoc}
* <p>This implementation uses Netty's {@link CompositeByteBuf}.
*/
@Override
public DataBuffer join(List<? extends DataBuffer> dataBuffers) {
Assert.notEmpty(dataBuffers, "DataBuffer List must not be empty");
int bufferCount = dataBuffers.size();
if (bufferCount == 1) {
return dataBuffers.get(0);
}
CompositeByteBuf composite = this.byteBufAllocator.compositeBuffer(bufferCount);
for (DataBuffer dataBuffer : dataBuffers) {
Assert.isInstanceOf(NettyDataBuffer.class, dataBuffer);
composite.addComponent(true, ((NettyDataBuffer) dataBuffer).getNativeBuffer());
}
return new NettyDataBuffer(composite, this);
}
/**
* Encode a new sub-metadata information into a composite metadata {@link CompositeByteBuf
* buffer}.
*
* @param compositeMetaData the buffer that will hold all composite metadata information.
* @param allocator the {@link ByteBufAllocator} to use to create intermediate buffers as needed.
* @param unknownCompressedMimeType the id of the {@link
* WellKnownMimeType#UNKNOWN_RESERVED_MIME_TYPE} to encode.
* @param metadata the metadata value to encode.
*/
// see #encodeMetadataHeader(ByteBufAllocator, byte, int)
static void encodeAndAddMetadata(
CompositeByteBuf compositeMetaData,
ByteBufAllocator allocator,
byte unknownCompressedMimeType,
ByteBuf metadata) {
compositeMetaData.addComponents(
true,
encodeMetadataHeader(allocator, unknownCompressedMimeType, metadata.readableBytes()),
metadata);
}
/**
* Returns a {@link IovArray} which is filled with the {@link CompositeByteBuf}.
*/
static IovArray get(CompositeByteBuf buf) throws Exception {
IovArray array = ARRAY.get();
array.clear();
array.add(buf);
return array;
}
@Test
public void canSerializeUniqueItemsSeparately() throws IOException {
// given
ObjectWriter writer = spy(new ObjectMapper().writerFor(BufferedIndex.class));
CompositeByteBuf byteBuf1 = createDefaultTestByteBuf();
ItemSource<ByteBuf> source1 = new ByteBufItemSource(byteBuf1, source -> {});
String index1 = UUID.randomUUID().toString();
BulkableAction action1 = new BufferedIndex.Builder(source1)
.index(index1)
.build();
CompositeByteBuf byteBuf2 = createDefaultTestByteBuf();
ItemSource<ByteBuf> source2 = new ByteBufItemSource(byteBuf2, source -> {});
String index2 = UUID.randomUUID().toString();
BulkableAction action2 = new BufferedIndex.Builder(source2)
.index(index2)
.build();
BufferedBulk bulk = (BufferedBulk) new BufferedBulk.Builder()
.withObjectWriter(writer)
.withObjectReader(mock(ObjectReader.class))
.withBuffer(new ByteBufItemSource(createDefaultTestByteBuf(), source -> {}))
.addAction(action1)
.addAction(action2)
.build();
// when
bulk.serializeRequest();
// then
ArgumentCaptor<BufferedIndex> captor = ArgumentCaptor.forClass(BufferedIndex.class);
verify(writer, times(2)).writeValue((OutputStream)any(), captor.capture());
List<BufferedIndex> allValues = captor.getAllValues();
assertEquals(2, allValues.size());
assertEquals(index1, allValues.get(0).getIndex());
assertEquals(index2, allValues.get(1).getIndex());
}
@Test
public void testStreamStartIsOnlyWrittenOnce() throws Exception {
ByteBuf in = Unpooled.wrappedBuffer(new byte[] {
'n', 'e', 't', 't', 'y'
});
channel.writeOutbound(in.copy());
in.readerIndex(0); // rewind the buffer to write the same data
channel.writeOutbound(in.copy());
assertTrue(channel.finish());
ByteBuf expected = Unpooled.wrappedBuffer(new byte[] {
(byte) 0xff, 0x06, 0x00, 0x00, 0x73, 0x4e, 0x61, 0x50, 0x70, 0x59,
0x01, 0x09, 0x00, 0x00, 0x6f, -0x68, -0x7e, -0x5e, 'n', 'e', 't', 't', 'y',
0x01, 0x09, 0x00, 0x00, 0x6f, -0x68, -0x7e, -0x5e, 'n', 'e', 't', 't', 'y',
});
CompositeByteBuf actual = Unpooled.compositeBuffer();
for (;;) {
ByteBuf m = (ByteBuf) channel.readOutbound();
if (m == null) {
break;
}
actual.addComponent(m);
actual.writerIndex(actual.writerIndex() + m.readableBytes());
}
assertEquals(releaseLater(expected), releaseLater(actual));
in.release();
}
@NotNull
protected Mono<Payload> remoteRequestResponse(ReactiveMethodMetadata methodMetadata, ByteBuf compositeMetadata, ByteBuf bodyBuf) {
return Mono.deferWithContext(context -> {
TraceContext traceContext = context.getOrDefault(TraceContext.class, null);
if (traceContext != null) {
CompositeByteBuf newCompositeMetadata = new CompositeByteBuf(PooledByteBufAllocator.DEFAULT, true, 2, compositeMetadata, tracingMetadata(traceContext).getContent());
Span span = tracer.newChild(traceContext);
return super.remoteRequestResponse(methodMetadata, newCompositeMetadata, bodyBuf)
.doOnError(span::error)
.doOnSuccess(payload -> span.finish());
}
return super.remoteRequestResponse(methodMetadata, compositeMetadata, bodyBuf);
});
}
@Override
protected Mono<Void> remoteFireAndForget(ReactiveMethodMetadata methodMetadata, ByteBuf compositeMetadata, ByteBuf bodyBuf) {
return Mono.deferWithContext(context -> {
TraceContext traceContext = context.getOrDefault(TraceContext.class, null);
if (traceContext != null) {
CompositeByteBuf newCompositeMetadata = new CompositeByteBuf(PooledByteBufAllocator.DEFAULT, true, 2, compositeMetadata, tracingMetadata(traceContext).getContent());
Span span = tracer.newChild(traceContext);
return super.remoteFireAndForget(methodMetadata, newCompositeMetadata, bodyBuf)
.doOnError(span::error)
.doOnSuccess(payload -> span.finish());
}
return super.remoteFireAndForget(methodMetadata, compositeMetadata, bodyBuf);
});
}
@Override
protected Flux<Payload> remoteRequestStream(ReactiveMethodMetadata methodMetadata, ByteBuf compositeMetadata, ByteBuf bodyBuf) {
return Flux.deferWithContext(context -> {
TraceContext traceContext = context.getOrDefault(TraceContext.class, null);
if (traceContext != null) {
CompositeByteBuf newCompositeMetadata = new CompositeByteBuf(PooledByteBufAllocator.DEFAULT, true, 2, compositeMetadata, tracingMetadata(traceContext).getContent());
Span span = tracer.newChild(traceContext);
return super.remoteRequestStream(methodMetadata, newCompositeMetadata, bodyBuf)
.doOnError(span::error)
.doOnComplete(span::finish);
}
return super.remoteRequestStream(methodMetadata, compositeMetadata, bodyBuf);
});
}
@Override
public ByteBuf getContent() {
CompositeByteBuf compositeByteBuf = PooledByteBufAllocator.DEFAULT.compositeBuffer();
for (Map.Entry<String, ByteBuf> entry : metadataStore.entrySet()) {
WellKnownMimeType wellKnownMimeType = WellKnownMimeType.fromString(entry.getKey());
if (wellKnownMimeType != UNPARSEABLE_MIME_TYPE) {
CompositeMetadataCodec.encodeAndAddMetadata(compositeByteBuf, PooledByteBufAllocator.DEFAULT, wellKnownMimeType, entry.getValue());
} else {
CompositeMetadataCodec.encodeAndAddMetadata(compositeByteBuf, PooledByteBufAllocator.DEFAULT, entry.getKey(), entry.getValue());
}
}
return compositeByteBuf;
}
private static void checkContentBuffer(FullHttpRequest aggregatedMessage) {
CompositeByteBuf buffer = (CompositeByteBuf) aggregatedMessage.content();
assertEquals(2, buffer.numComponents());
List<ByteBuf> buffers = buffer.decompose(0, buffer.capacity());
assertEquals(2, buffers.size());
for (ByteBuf buf: buffers) {
// This should be false as we decompose the buffer before to not have deep hierarchy
assertFalse(buf instanceof CompositeByteBuf);
}
aggregatedMessage.release();
}
private static ByteBuf encode(List<MutationCommand> commands) {
//FIXME a way of using the pooled allocator?
CompositeByteBuf compositeBuf = Unpooled.compositeBuffer(commands.size());
for (MutationCommand command : commands) {
byte[] pathBytes = command.path().getBytes(CharsetUtil.UTF_8);
short pathLength = (short) pathBytes.length;
ByteBuf commandBuf = Unpooled.buffer(4 + pathLength + command.fragment().readableBytes());
commandBuf.writeByte(command.opCode());
byte subdocFlags = 0;
if (command.createIntermediaryPath()) {
subdocFlags |= KeyValueHandler.SUBDOC_BITMASK_MKDIR_P;
}
if (command.xattr()) {
subdocFlags |= KeyValueHandler.SUBDOC_FLAG_XATTR_PATH;
}
if (command.expandMacros()) {
subdocFlags |= KeyValueHandler.SUBDOC_FLAG_EXPAND_MACROS;
}
commandBuf.writeByte(subdocFlags);
commandBuf.writeShort(pathLength);
commandBuf.writeInt(command.fragment().readableBytes());
commandBuf.writeBytes(pathBytes);
//copy the fragment but don't move indexes (in case it is retained and reused)
commandBuf.writeBytes(command.fragment(), command.fragment().readerIndex(), command.fragment().readableBytes());
//eagerly release the fragment once it's been copied
command.fragment().release();
//add the command to the composite buffer
compositeBuf.addComponent(commandBuf);
compositeBuf.writerIndex(compositeBuf.writerIndex() + commandBuf.readableBytes());
}
return compositeBuf;
}
private static ByteBuf newCompositeBuffer(ByteBufAllocator alloc) {
CompositeByteBuf compositeByteBuf = alloc.compositeBuffer();
compositeByteBuf.addComponent(true, alloc.directBuffer(4).writeInt(100));
compositeByteBuf.addComponent(true, alloc.directBuffer(8).writeLong(123));
compositeByteBuf.addComponent(true, alloc.directBuffer(8).writeLong(456));
assertEquals(EXPECTED_BYTES, compositeByteBuf.readableBytes());
return compositeByteBuf;
}
private ByteBuf write(ByteBuf message, boolean compressed) {
final int messageLength = message.readableBytes();
if (maxOutboundMessageSize >= 0 && messageLength > maxOutboundMessageSize) {
message.release();
throw new ArmeriaStatusException(
StatusCodes.RESOURCE_EXHAUSTED,
String.format("message too large %d > %d", messageLength,
maxOutboundMessageSize));
}
// Here comes some heuristics.
// TODO(trustin): Consider making this configurable.
if (messageLength <= 128) {
// Frame is so small that the cost of composition outweighs.
try {
final ByteBuf buf = alloc.buffer(HEADER_LENGTH + messageLength);
buf.writeByte(compressed ? COMPRESSED : UNCOMPRESSED);
buf.writeInt(messageLength);
buf.writeBytes(message);
return buf;
} finally {
message.release();
}
}
// Frame is fairly large that composition might reduce memory footprint.
return new CompositeByteBuf(alloc, true, 2,
alloc.buffer(HEADER_LENGTH)
.writeByte(compressed ? COMPRESSED : UNCOMPRESSED)
.writeInt(messageLength),
message);
}
public void testSimpleSendCompositeHeapByteBuf(Bootstrap sb, Bootstrap cb) throws Throwable {
CompositeByteBuf buf = Unpooled.compositeBuffer();
buf.addComponent(true, Unpooled.buffer().writeBytes(BYTES, 0, 2));
buf.addComponent(true, Unpooled.buffer().writeBytes(BYTES, 2, 2));
testSimpleSend(sb, cb, buf, true, BYTES, 1);
CompositeByteBuf buf2 = Unpooled.compositeBuffer();
buf2.addComponent(true, Unpooled.buffer().writeBytes(BYTES, 0, 2));
buf2.addComponent(true, Unpooled.buffer().writeBytes(BYTES, 2, 2));
testSimpleSend(sb, cb, buf2, true, BYTES, 4);
}
private ByteBuf captureWrites() {
ArgumentCaptor<ByteBuf> captor = ArgumentCaptor.forClass(ByteBuf.class);
verify(ctx, atLeastOnce()).write(captor.capture(), isA(ChannelPromise.class));
CompositeByteBuf composite = releaseLater(Unpooled.compositeBuffer());
for (ByteBuf buf : captor.getAllValues()) {
buf = releaseLater(buf.retain());
composite.addComponent(true, buf);
}
return composite;
}
/**
* Concatenates result of outbound Netty pipeline into an ByteBuf object.
* <p/>
* The optional byte buffer is returned only if a pipeline processing
* resulted in outgoing bytes. Otherwise optional return value is absent.
*/
private static Optional<ByteBuf> grabSentBytes(EmbeddedChannel channel) {
CompositeByteBuf outboundBytes = Unpooled.compositeBuffer();
Object result = channel.readOutbound();
while (result != null) {
outboundBytes.addComponent((ByteBuf) result);
result = channel.readOutbound();
}
if (outboundBytes.numComponents() > 0) {
return Optional.of((ByteBuf) outboundBytes);
}
return Optional.empty();
}
@Override
protected ByteBuf composeFirst(ByteBufAllocator allocator, ByteBuf first) {
if (first instanceof CompositeByteBuf) {
CompositeByteBuf composite = (CompositeByteBuf) first;
first = allocator.directBuffer(composite.readableBytes());
try {
first.writeBytes(composite);
} catch (Throwable cause) {
first.release();
PlatformDependent.throwException(cause);
}
composite.release();
}
return first;
}