diff --git a/buffer/src/main/java/io/netty/buffer/AbstractByteBuf.java b/buffer/src/main/java/io/netty/buffer/AbstractByteBuf.java index e7b856a8a7..e5bcbe7222 100644 --- a/buffer/src/main/java/io/netty/buffer/AbstractByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/AbstractByteBuf.java @@ -176,17 +176,17 @@ public abstract class AbstractByteBuf implements ByteBuf { @Override public void ensureWritableBytes(int minWritableBytes) { - if (minWritableBytes <= writableBytes()) { - return; - } - if (minWritableBytes < 0) { throw new IllegalArgumentException(String.format( "minWritableBytes: %d (expected: >= 0)", minWritableBytes)); } + if (minWritableBytes <= writableBytes()) { + return; + } + if (minWritableBytes > maxCapacity - writerIndex) { - throw new IllegalArgumentException(String.format( + throw new IndexOutOfBoundsException(String.format( "writerIndex(%d) + minWritableBytes(%d) exceeds maxCapacity(%d)", writerIndex, minWritableBytes, maxCapacity)); } @@ -198,6 +198,36 @@ public abstract class AbstractByteBuf implements ByteBuf { capacity(newCapacity); } + @Override + public int ensureWritableBytes(int minWritableBytes, boolean force) { + if (minWritableBytes < 0) { + throw new IllegalArgumentException(String.format( + "minWritableBytes: %d (expected: >= 0)", minWritableBytes)); + } + + if (minWritableBytes <= writableBytes()) { + return 0; + } + + if (minWritableBytes > maxCapacity - writerIndex) { + if (force) { + if (capacity() == maxCapacity()) { + return 1; + } + + capacity(maxCapacity()); + return 3; + } + } + + // Normalize the current capacity to the power of 2. + int newCapacity = calculateNewCapacity(writerIndex + minWritableBytes); + + // Adjust to the new capacity. + capacity(newCapacity); + return 2; + } + private int calculateNewCapacity(int minNewCapacity) { final int maxCapacity = this.maxCapacity; final int threshold = 1048576 * 4; // 4 MiB page diff --git a/buffer/src/main/java/io/netty/buffer/ByteBuf.java b/buffer/src/main/java/io/netty/buffer/ByteBuf.java index 09d19c4a59..e514ee5ec5 100644 --- a/buffer/src/main/java/io/netty/buffer/ByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/ByteBuf.java @@ -443,23 +443,35 @@ public interface ByteBuf extends ChannelBuf, Comparable { * Makes sure the number of {@linkplain #writableBytes() the writable bytes} * is equal to or greater than the specified value. If there is enough * writable bytes in this buffer, this method returns with no side effect. - * Otherwise: - * + * Otherwise, it raises an {@link IllegalArgumentException}. * - * @param writableBytes + * @param minWritableBytes * the expected minimum number of writable bytes * @throws IndexOutOfBoundsException - * if {@linkplain #writableBytes() the writable bytes} of this - * buffer is less than the specified value and if this buffer is - * not a dynamic buffer + * if {@link #writerIndex()} + {@code minWritableBytes} > {@link #maxCapacity()} */ - void ensureWritableBytes(int writableBytes); + void ensureWritableBytes(int minWritableBytes); + + /** + * Tries to make sure the number of {@linkplain #writableBytes() the writable bytes} + * is equal to or greater than the specified value. Unlike {@link #ensureWritableBytes(int)}, + * this method does not raise an exception but returns a code. + * + * @param minWritableBytes + * the expected minimum number of writable bytes + * @param force + * When {@link #writerIndex()} + {@code minWritableBytes} > {@link #maxCapacity()}: + * + * @return {@code 0} if the buffer has enough writable bytes, and its capacity is unchanged. + * {@code 1} if the buffer does not have enough bytes, and its capacity is unchanged. + * {@code 2} if the buffer has enough writable bytes, and its capacity has been increased. + * {@code 3} if the buffer does not have enough bytes, but its capacity has been + * increased to its maximum. + */ + int ensureWritableBytes(int minWritableBytes, boolean force); /** * Gets a boolean at the specified absolute (@code index) in this buffer. diff --git a/buffer/src/main/java/io/netty/buffer/SwappedByteBuf.java b/buffer/src/main/java/io/netty/buffer/SwappedByteBuf.java index cb3810116a..ef612d9301 100644 --- a/buffer/src/main/java/io/netty/buffer/SwappedByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/SwappedByteBuf.java @@ -172,6 +172,11 @@ public class SwappedByteBuf implements WrappedByteBuf { buf.ensureWritableBytes(writableBytes); } + @Override + public int ensureWritableBytes(int minWritableBytes, boolean force) { + return buf.ensureWritableBytes(minWritableBytes, force); + } + @Override public boolean getBoolean(int index) { return buf.getBoolean(index); diff --git a/codec/src/main/java/io/netty/handler/codec/ReplayingDecoderBuffer.java b/codec/src/main/java/io/netty/handler/codec/ReplayingDecoderBuffer.java index caab92a54a..65715972f4 100644 --- a/codec/src/main/java/io/netty/handler/codec/ReplayingDecoderBuffer.java +++ b/codec/src/main/java/io/netty/handler/codec/ReplayingDecoderBuffer.java @@ -139,6 +139,11 @@ class ReplayingDecoderBuffer implements ByteBuf { throw new UnreplayableOperationException(); } + @Override + public int ensureWritableBytes(int minWritableBytes, boolean force) { + throw new UnreplayableOperationException(); + } + @Override public ByteBuf duplicate() { throw new UnreplayableOperationException();