From 91ac87d75b155c6f61792103c197c38e2a817523 Mon Sep 17 00:00:00 2001 From: Armin Braun Date: Wed, 4 Dec 2019 19:36:52 +0100 Subject: [PATCH] Stop Allocating Buffers in CopyBytesSocketChannel (#49825) (#49832) * Stop Allocating Buffers in CopyBytesSocketChannel (#49825) The way things currently work, we read up to 1M from the channel and then potentially force all of it into the `ByteBuf` passed by Netty. Since that `ByteBuf` tends to by default be `64k` in size, large reads will force the buffer to grow, completely circumventing the logic of `allocHandle`. This seems like it could break `io.netty.channel.RecvByteBufAllocator.Handle#continueReading` since that method for the fixed-size allocator does check whether the last read was equal to the attempted read size. So if we set `64k` because that's what the buffer size is, then wirte `1M` to the buffer we will stop reading on the IO loop, even though the channel may still have bytes that we can read right away. More imporatantly though, this can lead to running OOM quite easily under IO pressure as we are forcing the heap buffers passed to the read to `reallocate`. Closes #49699 --- .../org/elasticsearch/transport/CopyBytesSocketChannel.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/transport-netty4/src/main/java/org/elasticsearch/transport/CopyBytesSocketChannel.java b/modules/transport-netty4/src/main/java/org/elasticsearch/transport/CopyBytesSocketChannel.java index 60e63ba7865..7e1db14e85b 100644 --- a/modules/transport-netty4/src/main/java/org/elasticsearch/transport/CopyBytesSocketChannel.java +++ b/modules/transport-netty4/src/main/java/org/elasticsearch/transport/CopyBytesSocketChannel.java @@ -119,8 +119,10 @@ public class CopyBytesSocketChannel extends NioSocketChannel { @Override protected int doReadBytes(ByteBuf byteBuf) throws Exception { final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle(); - allocHandle.attemptedBytesRead(byteBuf.writableBytes()); + int writeableBytes = Math.min(byteBuf.writableBytes(), MAX_BYTES_PER_WRITE); + allocHandle.attemptedBytesRead(writeableBytes); ByteBuffer ioBuffer = getIoBuffer(); + ioBuffer.limit(writeableBytes); int bytesRead = readFromSocketChannel(javaChannel(), ioBuffer); ioBuffer.flip(); if (bytesRead > 0) {