Fix IOOBE after buffer truncation / Add CompositeByteBuf.addComponents()
- plus some bug fixes while running unit tests
This commit is contained in:
parent
8d813b127c
commit
26e64eb305
@ -21,6 +21,12 @@ public interface CompositeByteBuf extends ByteBuf, Iterable<ByteBuf> {
|
|||||||
|
|
||||||
void addComponent(ByteBuf buffer);
|
void addComponent(ByteBuf buffer);
|
||||||
void addComponent(int cIndex, ByteBuf buffer);
|
void addComponent(int cIndex, ByteBuf buffer);
|
||||||
|
|
||||||
|
void addComponents(ByteBuf... buffers);
|
||||||
|
void addComponents(Iterable<ByteBuf> buffers);
|
||||||
|
void addComponents(int cIndex, ByteBuf... buffers);
|
||||||
|
void addComponents(int cIndex, Iterable<ByteBuf> buffers);
|
||||||
|
|
||||||
void removeComponent(int cIndex);
|
void removeComponent(int cIndex);
|
||||||
void removeComponents(int cIndex, int numComponents);
|
void removeComponents(int cIndex, int numComponents);
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ import java.nio.ByteOrder;
|
|||||||
import java.nio.channels.GatheringByteChannel;
|
import java.nio.channels.GatheringByteChannel;
|
||||||
import java.nio.channels.ScatteringByteChannel;
|
import java.nio.channels.ScatteringByteChannel;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -58,19 +59,9 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
|
|||||||
"maxNumComponents: " + maxNumComponents + " (expected: >= 2)");
|
"maxNumComponents: " + maxNumComponents + " (expected: >= 2)");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffers == null) {
|
|
||||||
throw new NullPointerException("buffers");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.maxNumComponents = maxNumComponents;
|
this.maxNumComponents = maxNumComponents;
|
||||||
|
|
||||||
// TODO: Handle the case where the number of specified buffers already exceeds maxNumComponents.
|
addComponents(0, buffers);
|
||||||
for (ByteBuf b: buffers) {
|
|
||||||
if (b == null) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
addComponent(b);
|
|
||||||
}
|
|
||||||
setIndex(0, capacity());
|
setIndex(0, capacity());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,19 +73,8 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
|
|||||||
"maxNumComponents: " + maxNumComponents + " (expected: >= 2)");
|
"maxNumComponents: " + maxNumComponents + " (expected: >= 2)");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffers == null) {
|
|
||||||
throw new NullPointerException("buffers");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.maxNumComponents = maxNumComponents;
|
this.maxNumComponents = maxNumComponents;
|
||||||
|
addComponents(0, buffers);
|
||||||
// TODO: Handle the case where the numer of specified buffers already exceeds maxNumComponents.
|
|
||||||
for (ByteBuf b: buffers) {
|
|
||||||
if (b == null) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
addComponent(b);
|
|
||||||
}
|
|
||||||
setIndex(0, capacity());
|
setIndex(0, capacity());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,6 +83,16 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
|
|||||||
addComponent(components.size(), buffer);
|
addComponent(components.size(), buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addComponents(ByteBuf... buffers) {
|
||||||
|
addComponents(components.size(), buffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addComponents(Iterable<ByteBuf> buffers) {
|
||||||
|
addComponents(components.size(), buffers);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addComponent(int cIndex, ByteBuf buffer) {
|
public void addComponent(int cIndex, ByteBuf buffer) {
|
||||||
checkComponentIndex(cIndex);
|
checkComponentIndex(cIndex);
|
||||||
@ -111,13 +101,18 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
|
|||||||
throw new NullPointerException("buffer");
|
throw new NullPointerException("buffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (buffer instanceof Iterable) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Iterable<ByteBuf> composite = (Iterable<ByteBuf>) buffer;
|
||||||
|
addComponents(cIndex, composite);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int readableBytes = buffer.readableBytes();
|
int readableBytes = buffer.readableBytes();
|
||||||
if (readableBytes == 0) {
|
if (readableBytes == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Handle the case where buffer is actually another CompositeByteBuf.
|
|
||||||
|
|
||||||
// Consolidate if the number of components will exceed the allowed maximum by the current
|
// Consolidate if the number of components will exceed the allowed maximum by the current
|
||||||
// operation.
|
// operation.
|
||||||
final int numComponents = components.size();
|
final int numComponents = components.size();
|
||||||
@ -126,7 +121,9 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
|
|||||||
|
|
||||||
ByteBuf consolidated = buffer.unsafe().newBuffer(capacity);
|
ByteBuf consolidated = buffer.unsafe().newBuffer(capacity);
|
||||||
for (int i = 0; i < numComponents; i ++) {
|
for (int i = 0; i < numComponents; i ++) {
|
||||||
consolidated.writeBytes(components.get(i).buf);
|
ByteBuf b = components.get(i).buf;
|
||||||
|
consolidated.writeBytes(b);
|
||||||
|
b.unsafe().release();
|
||||||
}
|
}
|
||||||
consolidated.writeBytes(buffer, buffer.readerIndex(), readableBytes);
|
consolidated.writeBytes(buffer, buffer.readerIndex(), readableBytes);
|
||||||
|
|
||||||
@ -154,6 +151,129 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addComponents(int cIndex, ByteBuf... buffers) {
|
||||||
|
checkComponentIndex(cIndex);
|
||||||
|
|
||||||
|
if (buffers == null) {
|
||||||
|
throw new NullPointerException("buffers");
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuf lastBuf = null;
|
||||||
|
int cnt = 0;
|
||||||
|
int readableBytes = 0;
|
||||||
|
for (ByteBuf b: buffers) {
|
||||||
|
if (b == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lastBuf = b;
|
||||||
|
cnt ++;
|
||||||
|
readableBytes += b.readableBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readableBytes == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consolidate if the number of components will exceed the maximum by this operation.
|
||||||
|
final int numComponents = components.size();
|
||||||
|
if (numComponents + cnt > maxNumComponents) {
|
||||||
|
final ByteBuf consolidated;
|
||||||
|
if (numComponents != 0) {
|
||||||
|
final int capacity = components.get(numComponents - 1).endOffset + readableBytes;
|
||||||
|
consolidated = lastBuf.unsafe().newBuffer(capacity);
|
||||||
|
for (int i = 0; i < cIndex; i ++) {
|
||||||
|
ByteBuf b = components.get(i).buf;
|
||||||
|
consolidated.writeBytes(b);
|
||||||
|
b.unsafe().release();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ByteBuf b: buffers) {
|
||||||
|
if (b == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
consolidated.writeBytes(b, b.readerIndex(), b.readableBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = cIndex; i < numComponents; i ++) {
|
||||||
|
ByteBuf b = components.get(i).buf;
|
||||||
|
consolidated.writeBytes(b);
|
||||||
|
b.unsafe().release();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
consolidated = lastBuf.unsafe().newBuffer(readableBytes);
|
||||||
|
for (ByteBuf b: buffers) {
|
||||||
|
if (b == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
consolidated.writeBytes(b, b.readerIndex(), b.readableBytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component c = new Component(consolidated);
|
||||||
|
c.endOffset = c.length;
|
||||||
|
components.clear();
|
||||||
|
components.add(c);
|
||||||
|
updateComponentOffsets(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No need for consolidation
|
||||||
|
for (ByteBuf b: buffers) {
|
||||||
|
if (b == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b.readable()) {
|
||||||
|
addComponent(cIndex ++, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addComponents(int cIndex, Iterable<ByteBuf> buffers) {
|
||||||
|
if (buffers == null) {
|
||||||
|
throw new NullPointerException("buffers");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffers instanceof DefaultCompositeByteBuf) {
|
||||||
|
List<Component> list = ((DefaultCompositeByteBuf) buffers).components;
|
||||||
|
ByteBuf[] array = new ByteBuf[list.size()];
|
||||||
|
for (int i = 0; i < array.length; i ++) {
|
||||||
|
array[i] = list.get(i).buf;
|
||||||
|
}
|
||||||
|
addComponents(cIndex, array);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffers instanceof List) {
|
||||||
|
List<ByteBuf> list = (List<ByteBuf>) buffers;
|
||||||
|
ByteBuf[] array = new ByteBuf[list.size()];
|
||||||
|
for (int i = 0; i < array.length; i ++) {
|
||||||
|
array[i] = list.get(i);
|
||||||
|
}
|
||||||
|
addComponents(cIndex, array);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffers instanceof Collection) {
|
||||||
|
Collection<ByteBuf> col = (Collection<ByteBuf>) buffers;
|
||||||
|
ByteBuf[] array = new ByteBuf[col.size()];
|
||||||
|
int i = 0;
|
||||||
|
for (ByteBuf b: col) {
|
||||||
|
array[i ++] = b;
|
||||||
|
}
|
||||||
|
addComponents(cIndex, array);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ByteBuf> list = new ArrayList<ByteBuf>();
|
||||||
|
for (ByteBuf b: buffers) {
|
||||||
|
list.add(b);
|
||||||
|
}
|
||||||
|
addComponents(cIndex, list.toArray(new ByteBuf[list.size()]));
|
||||||
|
}
|
||||||
|
|
||||||
private void checkComponentIndex(int cIndex) {
|
private void checkComponentIndex(int cIndex) {
|
||||||
if (cIndex < 0 || cIndex > components.size()) {
|
if (cIndex < 0 || cIndex > components.size()) {
|
||||||
throw new IndexOutOfBoundsException(String.format(
|
throw new IndexOutOfBoundsException(String.format(
|
||||||
@ -339,6 +459,12 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
|
|||||||
i.set(newC);
|
i.set(newC);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (readerIndex() > newCapacity) {
|
||||||
|
setIndex(newCapacity, newCapacity);
|
||||||
|
} else if (writerIndex() > newCapacity) {
|
||||||
|
writerIndex(newCapacity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -868,7 +994,7 @@ public class DefaultCompositeByteBuf extends AbstractByteBuf implements Composit
|
|||||||
@Override
|
@Override
|
||||||
public ByteBuffer nioBuffer(int index, int length) {
|
public ByteBuffer nioBuffer(int index, int length) {
|
||||||
if (components.size() == 1) {
|
if (components.size() == 1) {
|
||||||
return components.get(0).buf.nioBuffer();
|
return components.get(0).buf.nioBuffer(index, length);
|
||||||
}
|
}
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
@ -173,6 +173,8 @@ public class DirectByteBuf extends AbstractByteBuf {
|
|||||||
newBuffer.position(readerIndex).limit(writerIndex);
|
newBuffer.position(readerIndex).limit(writerIndex);
|
||||||
newBuffer.put(oldBuffer);
|
newBuffer.put(oldBuffer);
|
||||||
newBuffer.clear();
|
newBuffer.clear();
|
||||||
|
} else {
|
||||||
|
setIndex(newCapacity, newCapacity);
|
||||||
}
|
}
|
||||||
setByteBuffer(newBuffer);
|
setByteBuffer(newBuffer);
|
||||||
}
|
}
|
||||||
|
@ -103,6 +103,8 @@ public class HeapByteBuf extends AbstractByteBuf {
|
|||||||
writerIndex(writerIndex = newCapacity);
|
writerIndex(writerIndex = newCapacity);
|
||||||
}
|
}
|
||||||
System.arraycopy(array, readerIndex, newArray, readerIndex, writerIndex - readerIndex);
|
System.arraycopy(array, readerIndex, newArray, readerIndex, writerIndex - readerIndex);
|
||||||
|
} else {
|
||||||
|
setIndex(newCapacity, newCapacity);
|
||||||
}
|
}
|
||||||
setArray(newArray);
|
setArray(newArray);
|
||||||
}
|
}
|
||||||
|
@ -46,15 +46,34 @@ public abstract class AbstractCompositeChannelBufferTest extends
|
|||||||
@Override
|
@Override
|
||||||
protected ByteBuf newBuffer(int length) {
|
protected ByteBuf newBuffer(int length) {
|
||||||
buffers = new ArrayList<ByteBuf>();
|
buffers = new ArrayList<ByteBuf>();
|
||||||
for (int i = 0; i < length; i ++) {
|
for (int i = 0; i < length + 45; i += 45) {
|
||||||
buffers.add(Unpooled.EMPTY_BUFFER);
|
buffers.add(Unpooled.EMPTY_BUFFER);
|
||||||
buffers.add(Unpooled.wrappedBuffer(new byte[1]));
|
buffers.add(Unpooled.wrappedBuffer(new byte[1]));
|
||||||
buffers.add(Unpooled.EMPTY_BUFFER);
|
buffers.add(Unpooled.EMPTY_BUFFER);
|
||||||
|
buffers.add(Unpooled.wrappedBuffer(new byte[2]));
|
||||||
|
buffers.add(Unpooled.EMPTY_BUFFER);
|
||||||
|
buffers.add(Unpooled.wrappedBuffer(new byte[3]));
|
||||||
|
buffers.add(Unpooled.EMPTY_BUFFER);
|
||||||
|
buffers.add(Unpooled.wrappedBuffer(new byte[4]));
|
||||||
|
buffers.add(Unpooled.EMPTY_BUFFER);
|
||||||
|
buffers.add(Unpooled.wrappedBuffer(new byte[5]));
|
||||||
|
buffers.add(Unpooled.EMPTY_BUFFER);
|
||||||
|
buffers.add(Unpooled.wrappedBuffer(new byte[6]));
|
||||||
|
buffers.add(Unpooled.EMPTY_BUFFER);
|
||||||
|
buffers.add(Unpooled.wrappedBuffer(new byte[7]));
|
||||||
|
buffers.add(Unpooled.EMPTY_BUFFER);
|
||||||
|
buffers.add(Unpooled.wrappedBuffer(new byte[8]));
|
||||||
|
buffers.add(Unpooled.EMPTY_BUFFER);
|
||||||
|
buffers.add(Unpooled.wrappedBuffer(new byte[9]));
|
||||||
|
buffers.add(Unpooled.EMPTY_BUFFER);
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer = Unpooled.wrappedBuffer(
|
buffer = Unpooled.wrappedBuffer(
|
||||||
Integer.MAX_VALUE, buffers.toArray(new ByteBuf[buffers.size()])).order(order);
|
Integer.MAX_VALUE, buffers.toArray(new ByteBuf[buffers.size()])).order(order);
|
||||||
|
|
||||||
|
// Truncate to the requested capacity.
|
||||||
|
buffer.capacity(length);
|
||||||
|
|
||||||
assertEquals(length, buffer.capacity());
|
assertEquals(length, buffer.capacity());
|
||||||
assertEquals(length, buffer.readableBytes());
|
assertEquals(length, buffer.readableBytes());
|
||||||
assertFalse(buffer.writable());
|
assertFalse(buffer.writable());
|
||||||
|
Loading…
Reference in New Issue
Block a user