use of io.netty.channel.FileRegion in project netty by netty.
the class HttpResponseEncoderTest method testLargeFileRegionChunked.
@Test
public void testLargeFileRegionChunked() throws Exception {
EmbeddedChannel channel = new EmbeddedChannel(new HttpResponseEncoder());
HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
response.headers().set(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED);
assertTrue(channel.writeOutbound(response));
ByteBuf buffer = channel.readOutbound();
assertEquals("HTTP/1.1 200 OK\r\n" + HttpHeaderNames.TRANSFER_ENCODING + ": " + HttpHeaderValues.CHUNKED + "\r\n\r\n", buffer.toString(CharsetUtil.US_ASCII));
buffer.release();
assertTrue(channel.writeOutbound(FILE_REGION));
buffer = channel.readOutbound();
assertEquals("80000000\r\n", buffer.toString(CharsetUtil.US_ASCII));
buffer.release();
FileRegion region = channel.readOutbound();
assertSame(FILE_REGION, region);
region.release();
buffer = channel.readOutbound();
assertEquals("\r\n", buffer.toString(CharsetUtil.US_ASCII));
buffer.release();
assertTrue(channel.writeOutbound(LastHttpContent.EMPTY_LAST_CONTENT));
buffer = channel.readOutbound();
assertEquals("0\r\n\r\n", buffer.toString(CharsetUtil.US_ASCII));
buffer.release();
assertFalse(channel.finish());
}
use of io.netty.channel.FileRegion in project netty by netty.
the class HttpObjectEncoder method encode.
@Override
protected void encode(ChannelHandlerContext ctx, Object msg, List<Object> out) throws Exception {
ByteBuf buf = null;
if (msg instanceof HttpMessage) {
if (state != ST_INIT) {
throw new IllegalStateException("unexpected message type: " + StringUtil.simpleClassName(msg) + ", state: " + state);
}
@SuppressWarnings({ "unchecked", "CastConflictsWithInstanceof" }) H m = (H) msg;
buf = ctx.alloc().buffer((int) headersEncodedSizeAccumulator);
// Encode the message.
encodeInitialLine(buf, m);
state = isContentAlwaysEmpty(m) ? ST_CONTENT_ALWAYS_EMPTY : HttpUtil.isTransferEncodingChunked(m) ? ST_CONTENT_CHUNK : ST_CONTENT_NON_CHUNK;
sanitizeHeadersBeforeEncode(m, state == ST_CONTENT_ALWAYS_EMPTY);
encodeHeaders(m.headers(), buf);
ByteBufUtil.writeShortBE(buf, CRLF_SHORT);
headersEncodedSizeAccumulator = HEADERS_WEIGHT_NEW * padSizeForAccumulation(buf.readableBytes()) + HEADERS_WEIGHT_HISTORICAL * headersEncodedSizeAccumulator;
}
// See https://github.com/netty/netty/issues/2983 for more information.
if (msg instanceof ByteBuf) {
final ByteBuf potentialEmptyBuf = (ByteBuf) msg;
if (!potentialEmptyBuf.isReadable()) {
out.add(potentialEmptyBuf.retain());
return;
}
}
if (msg instanceof HttpContent || msg instanceof ByteBuf || msg instanceof FileRegion) {
switch(state) {
case ST_INIT:
throw new IllegalStateException("unexpected message type: " + StringUtil.simpleClassName(msg) + ", state: " + state);
case ST_CONTENT_NON_CHUNK:
final long contentLength = contentLength(msg);
if (contentLength > 0) {
if (buf != null && buf.writableBytes() >= contentLength && msg instanceof HttpContent) {
// merge into other buffer for performance reasons
buf.writeBytes(((HttpContent) msg).content());
out.add(buf);
} else {
if (buf != null) {
out.add(buf);
}
out.add(encodeAndRetain(msg));
}
if (msg instanceof LastHttpContent) {
state = ST_INIT;
}
break;
}
// fall-through!
case ST_CONTENT_ALWAYS_EMPTY:
if (buf != null) {
// We allocated a buffer so add it now.
out.add(buf);
} else {
// Need to produce some output otherwise an
// IllegalStateException will be thrown as we did not write anything
// Its ok to just write an EMPTY_BUFFER as if there are reference count issues these will be
// propagated as the caller of the encode(...) method will release the original
// buffer.
// Writing an empty buffer will not actually write anything on the wire, so if there is a user
// error with msg it will not be visible externally
out.add(Unpooled.EMPTY_BUFFER);
}
break;
case ST_CONTENT_CHUNK:
if (buf != null) {
// We allocated a buffer so add it now.
out.add(buf);
}
encodeChunkedContent(ctx, msg, contentLength(msg), out);
break;
default:
throw new Error();
}
if (msg instanceof LastHttpContent) {
state = ST_INIT;
}
} else if (buf != null) {
out.add(buf);
}
}
use of io.netty.channel.FileRegion in project netty by netty.
the class SocketFileRegionTest method testFileRegion0.
private static void testFileRegion0(ServerBootstrap sb, Bootstrap cb, boolean voidPromise, final boolean autoRead, boolean defaultFileRegion) throws Throwable {
sb.childOption(ChannelOption.AUTO_READ, autoRead);
cb.option(ChannelOption.AUTO_READ, autoRead);
final int bufferSize = 1024;
final File file = PlatformDependent.createTempFile("netty-", ".tmp", null);
file.deleteOnExit();
final FileOutputStream out = new FileOutputStream(file);
final Random random = PlatformDependent.threadLocalRandom();
// Prepend random data which will not be transferred, so that we can test non-zero start offset
final int startOffset = random.nextInt(8192);
for (int i = 0; i < startOffset; i++) {
out.write(random.nextInt());
}
// .. and here comes the real data to transfer.
out.write(data, bufferSize, data.length - bufferSize);
// .. and then some extra data which is not supposed to be transferred.
for (int i = random.nextInt(8192); i > 0; i--) {
out.write(random.nextInt());
}
out.close();
ChannelInboundHandler ch = new SimpleChannelInboundHandler<Object>() {
@Override
public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
if (!autoRead) {
ctx.read();
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
};
TestHandler sh = new TestHandler(autoRead);
sb.childHandler(sh);
cb.handler(ch);
Channel sc = sb.bind().sync().channel();
Channel cc = cb.connect(sc.localAddress()).sync().channel();
FileRegion region = new DefaultFileRegion(new RandomAccessFile(file, "r").getChannel(), startOffset, data.length - bufferSize);
FileRegion emptyRegion = new DefaultFileRegion(new RandomAccessFile(file, "r").getChannel(), 0, 0);
if (!defaultFileRegion) {
region = new FileRegionWrapper(region);
emptyRegion = new FileRegionWrapper(emptyRegion);
}
// https://github.com/netty/netty/issues/2964
if (voidPromise) {
assertEquals(cc.voidPromise(), cc.write(Unpooled.wrappedBuffer(data, 0, bufferSize), cc.voidPromise()));
assertEquals(cc.voidPromise(), cc.write(emptyRegion, cc.voidPromise()));
assertEquals(cc.voidPromise(), cc.writeAndFlush(region, cc.voidPromise()));
} else {
assertNotEquals(cc.voidPromise(), cc.write(Unpooled.wrappedBuffer(data, 0, bufferSize)));
assertNotEquals(cc.voidPromise(), cc.write(emptyRegion));
assertNotEquals(cc.voidPromise(), cc.writeAndFlush(region));
}
while (sh.counter < data.length) {
if (sh.exception.get() != null) {
break;
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// Ignore.
}
}
sh.channel.close().sync();
cc.close().sync();
sc.close().sync();
if (sh.exception.get() != null && !(sh.exception.get() instanceof IOException)) {
throw sh.exception.get();
}
if (sh.exception.get() != null) {
throw sh.exception.get();
}
// Make sure we did not receive more than we expected.
assertThat(sh.counter, is(data.length));
}
use of io.netty.channel.FileRegion in project rocketmq-rocketmq-all-4.1.0-incubating by lirenzuo.
the class QueryMessageProcessor method viewMessageById.
public RemotingCommand viewMessageById(ChannelHandlerContext ctx, RemotingCommand request) throws RemotingCommandException {
final RemotingCommand response = RemotingCommand.createResponseCommand(null);
final ViewMessageRequestHeader requestHeader = (ViewMessageRequestHeader) request.decodeCommandCustomHeader(ViewMessageRequestHeader.class);
response.setOpaque(request.getOpaque());
final SelectMappedBufferResult selectMappedBufferResult = this.brokerController.getMessageStore().selectOneMessageByOffset(requestHeader.getOffset());
if (selectMappedBufferResult != null) {
response.setCode(ResponseCode.SUCCESS);
response.setRemark(null);
try {
FileRegion fileRegion = new OneMessageTransfer(response.encodeHeader(selectMappedBufferResult.getSize()), selectMappedBufferResult);
ctx.channel().writeAndFlush(fileRegion).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
selectMappedBufferResult.release();
if (!future.isSuccess()) {
log.error("Transfer one message from page cache failed, ", future.cause());
}
}
});
} catch (Throwable e) {
log.error("", e);
selectMappedBufferResult.release();
}
return null;
} else {
response.setCode(ResponseCode.SYSTEM_ERROR);
response.setRemark("can not find message by the offset, " + requestHeader.getOffset());
}
return response;
}
use of io.netty.channel.FileRegion in project netty by netty.
the class AbstractNioByteChannel method doWrite.
@Override
protected void doWrite(ChannelOutboundBuffer in) throws Exception {
int writeSpinCount = -1;
boolean setOpWrite = false;
for (; ; ) {
Object msg = in.current();
if (msg == null) {
// Wrote all messages.
clearOpWrite();
// Directly return here so incompleteWrite(...) is not called.
return;
}
if (msg instanceof ByteBuf) {
ByteBuf buf = (ByteBuf) msg;
int readableBytes = buf.readableBytes();
if (readableBytes == 0) {
in.remove();
continue;
}
boolean done = false;
long flushedAmount = 0;
if (writeSpinCount == -1) {
writeSpinCount = config().getWriteSpinCount();
}
for (int i = writeSpinCount - 1; i >= 0; i--) {
int localFlushedAmount = doWriteBytes(buf);
if (localFlushedAmount == 0) {
setOpWrite = true;
break;
}
flushedAmount += localFlushedAmount;
if (!buf.isReadable()) {
done = true;
break;
}
}
in.progress(flushedAmount);
if (done) {
in.remove();
} else {
// Break the loop and so incompleteWrite(...) is called.
break;
}
} else if (msg instanceof FileRegion) {
FileRegion region = (FileRegion) msg;
boolean done = region.transferred() >= region.count();
if (!done) {
long flushedAmount = 0;
if (writeSpinCount == -1) {
writeSpinCount = config().getWriteSpinCount();
}
for (int i = writeSpinCount - 1; i >= 0; i--) {
long localFlushedAmount = doWriteFileRegion(region);
if (localFlushedAmount == 0) {
setOpWrite = true;
break;
}
flushedAmount += localFlushedAmount;
if (region.transferred() >= region.count()) {
done = true;
break;
}
}
in.progress(flushedAmount);
}
if (done) {
in.remove();
} else {
// Break the loop and so incompleteWrite(...) is called.
break;
}
} else {
// Should not reach here.
throw new Error();
}
}
incompleteWrite(setOpWrite);
}
Aggregations