CompositeByteBuf.addComponent always assume reference count ownership
Motivation: The current interface for CompositeByteBuf.addComponent is not clear under what conditions ownership is transferred when addComponent is called. There should be a well defined behavior so that users can ensure that no leaks occur. Modifications: - CompositeByteBuf.addComponent should always assume reference count ownership Result: Users that call CompositeByteBuf.addComponent do not have to independently check if the buffer's ownership has been transferred and if not independently release the buffer. Fixes https://github.com/netty/netty/issues/4760
This commit is contained in:
parent
7a7160f176
commit
6312c2f00b
@ -33,6 +33,8 @@ import java.util.List;
|
|||||||
import java.util.ListIterator;
|
import java.util.ListIterator;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
|
import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A virtual buffer which shows multiple buffers as a single merged buffer. It is recommended to use
|
* A virtual buffer which shows multiple buffers as a single merged buffer. It is recommended to use
|
||||||
* {@link ByteBufAllocator#compositeBuffer()} or {@link Unpooled#wrappedBuffer(ByteBuf...)} instead of calling the
|
* {@link ByteBufAllocator#compositeBuffer()} or {@link Unpooled#wrappedBuffer(ByteBuf...)} instead of calling the
|
||||||
@ -117,13 +119,16 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the given {@link ByteBuf}.
|
* Add the given {@link ByteBuf}.
|
||||||
*
|
* <p>
|
||||||
* Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
|
* Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
|
||||||
* If you need to have it increased you need to handle it by your own.
|
* If you need to have it increased you need to handle it by your own.
|
||||||
*
|
* <p>
|
||||||
* @param buffer the {@link ByteBuf} to add
|
* {@link ByteBuf#release()} ownership of {@code buffer} is transfered to this {@link CompositeByteBuf}.
|
||||||
|
* @param buffer the {@link ByteBuf} to add. {@link ByteBuf#release()} ownership is transfered to this
|
||||||
|
* {@link CompositeByteBuf}.
|
||||||
*/
|
*/
|
||||||
public CompositeByteBuf addComponent(ByteBuf buffer) {
|
public CompositeByteBuf addComponent(ByteBuf buffer) {
|
||||||
|
checkNotNull(buffer, "buffer");
|
||||||
addComponent0(components.size(), buffer);
|
addComponent0(components.size(), buffer);
|
||||||
consolidateIfNeeded();
|
consolidateIfNeeded();
|
||||||
return this;
|
return this;
|
||||||
@ -131,11 +136,14 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the given {@link ByteBuf}s.
|
* Add the given {@link ByteBuf}s.
|
||||||
*
|
* <p>
|
||||||
* Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
|
* Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
|
||||||
* If you need to have it increased you need to handle it by your own.
|
* If you need to have it increased you need to handle it by your own.
|
||||||
*
|
* <p>
|
||||||
* @param buffers the {@link ByteBuf}s to add
|
* {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects in {@code buffers} is transfered to this
|
||||||
|
* {@link CompositeByteBuf}.
|
||||||
|
* @param buffers the {@link ByteBuf}s to add. {@link ByteBuf#release()} ownership of all {@link ByteBuf#release()}
|
||||||
|
* ownership of all {@link ByteBuf} objects is transfered to this {@link CompositeByteBuf}.
|
||||||
*/
|
*/
|
||||||
public CompositeByteBuf addComponents(ByteBuf... buffers) {
|
public CompositeByteBuf addComponents(ByteBuf... buffers) {
|
||||||
addComponents0(components.size(), buffers);
|
addComponents0(components.size(), buffers);
|
||||||
@ -145,11 +153,14 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the given {@link ByteBuf}s.
|
* Add the given {@link ByteBuf}s.
|
||||||
*
|
* <p>
|
||||||
* Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
|
* Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
|
||||||
* If you need to have it increased you need to handle it by your own.
|
* If you need to have it increased you need to handle it by your own.
|
||||||
*
|
* <p>
|
||||||
* @param buffers the {@link ByteBuf}s to add
|
* {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects in {@code buffers} is transfered to this
|
||||||
|
* {@link CompositeByteBuf}.
|
||||||
|
* @param buffers the {@link ByteBuf}s to add. {@link ByteBuf#release()} ownership of all {@link ByteBuf#release()}
|
||||||
|
* ownership of all {@link ByteBuf} objects is transfered to this {@link CompositeByteBuf}.
|
||||||
*/
|
*/
|
||||||
public CompositeByteBuf addComponents(Iterable<ByteBuf> buffers) {
|
public CompositeByteBuf addComponents(Iterable<ByteBuf> buffers) {
|
||||||
addComponents0(components.size(), buffers);
|
addComponents0(components.size(), buffers);
|
||||||
@ -159,56 +170,73 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the given {@link ByteBuf} on the specific index.
|
* Add the given {@link ByteBuf} on the specific index.
|
||||||
*
|
* <p>
|
||||||
* Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
|
* Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
|
||||||
* If you need to have it increased you need to handle it by your own.
|
* If you need to have it increased you need to handle it by your own.
|
||||||
*
|
* <p>
|
||||||
* @param cIndex the index on which the {@link ByteBuf} will be added
|
* {@link ByteBuf#release()} ownership of {@code buffer} is transfered to this {@link CompositeByteBuf}.
|
||||||
* @param buffer the {@link ByteBuf} to add
|
* @param cIndex the index on which the {@link ByteBuf} will be added.
|
||||||
|
* @param buffer the {@link ByteBuf} to add. {@link ByteBuf#release()} ownership is transfered to this
|
||||||
|
* {@link CompositeByteBuf}.
|
||||||
*/
|
*/
|
||||||
public CompositeByteBuf addComponent(int cIndex, ByteBuf buffer) {
|
public CompositeByteBuf addComponent(int cIndex, ByteBuf buffer) {
|
||||||
|
checkNotNull(buffer, "buffer");
|
||||||
addComponent0(cIndex, buffer);
|
addComponent0(cIndex, buffer);
|
||||||
consolidateIfNeeded();
|
consolidateIfNeeded();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Precondition is that {@code buffer != null}.
|
||||||
|
*/
|
||||||
private int addComponent0(int cIndex, ByteBuf buffer) {
|
private int addComponent0(int cIndex, ByteBuf buffer) {
|
||||||
checkComponentIndex(cIndex);
|
assert buffer != null;
|
||||||
|
boolean wasAdded = false;
|
||||||
|
try {
|
||||||
|
checkComponentIndex(cIndex);
|
||||||
|
|
||||||
if (buffer == null) {
|
int readableBytes = buffer.readableBytes();
|
||||||
throw new NullPointerException("buffer");
|
|
||||||
}
|
|
||||||
|
|
||||||
int readableBytes = buffer.readableBytes();
|
// No need to consolidate - just add a component to the list.
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
// No need to consolidate - just add a component to the list.
|
Component c = new Component(buffer.order(ByteOrder.BIG_ENDIAN).slice());
|
||||||
Component c = new Component(buffer.order(ByteOrder.BIG_ENDIAN).slice());
|
if (cIndex == components.size()) {
|
||||||
if (cIndex == components.size()) {
|
wasAdded = components.add(c);
|
||||||
components.add(c);
|
if (cIndex == 0) {
|
||||||
if (cIndex == 0) {
|
c.endOffset = readableBytes;
|
||||||
c.endOffset = readableBytes;
|
} else {
|
||||||
|
Component prev = components.get(cIndex - 1);
|
||||||
|
c.offset = prev.endOffset;
|
||||||
|
c.endOffset = c.offset + readableBytes;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Component prev = components.get(cIndex - 1);
|
components.add(cIndex, c);
|
||||||
c.offset = prev.endOffset;
|
wasAdded = true;
|
||||||
c.endOffset = c.offset + readableBytes;
|
if (readableBytes != 0) {
|
||||||
|
updateComponentOffsets(cIndex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
return cIndex;
|
||||||
components.add(cIndex, c);
|
} finally {
|
||||||
if (readableBytes != 0) {
|
if (!wasAdded) {
|
||||||
updateComponentOffsets(cIndex);
|
buffer.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cIndex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the given {@link ByteBuf}s on the specific index
|
* Add the given {@link ByteBuf}s on the specific index
|
||||||
*
|
* <p>
|
||||||
* Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
|
* Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
|
||||||
* If you need to have it increased you need to handle it by your own.
|
* If you need to have it increased you need to handle it by your own.
|
||||||
*
|
* <p>
|
||||||
* @param cIndex the index on which the {@link ByteBuf} will be added.
|
* {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects in {@code buffers} is transfered to this
|
||||||
* @param buffers the {@link ByteBuf}s to add
|
* {@link CompositeByteBuf}.
|
||||||
|
* @param cIndex the index on which the {@link ByteBuf} will be added. {@link ByteBuf#release()} ownership of all
|
||||||
|
* {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects is transfered to this
|
||||||
|
* {@link CompositeByteBuf}.
|
||||||
|
* @param buffers the {@link ByteBuf}s to add. {@link ByteBuf#release()} ownership of all {@link ByteBuf#release()}
|
||||||
|
* ownership of all {@link ByteBuf} objects is transfered to this {@link CompositeByteBuf}.
|
||||||
*/
|
*/
|
||||||
public CompositeByteBuf addComponents(int cIndex, ByteBuf... buffers) {
|
public CompositeByteBuf addComponents(int cIndex, ByteBuf... buffers) {
|
||||||
addComponents0(cIndex, buffers);
|
addComponents0(cIndex, buffers);
|
||||||
@ -217,24 +245,38 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int addComponents0(int cIndex, ByteBuf... buffers) {
|
private int addComponents0(int cIndex, ByteBuf... buffers) {
|
||||||
checkComponentIndex(cIndex);
|
checkNotNull(buffers, "buffers");
|
||||||
|
int i = 0;
|
||||||
|
try {
|
||||||
|
checkComponentIndex(cIndex);
|
||||||
|
|
||||||
if (buffers == null) {
|
// No need for consolidation
|
||||||
throw new NullPointerException("buffers");
|
while (i < buffers.length) {
|
||||||
}
|
// Increment i now to prepare for the next iteration and prevent a duplicate release (addComponent0
|
||||||
|
// will release if an exception occurs, and we also release in the finally block here).
|
||||||
// No need for consolidation
|
ByteBuf b = buffers[i++];
|
||||||
for (ByteBuf b: buffers) {
|
if (b == null) {
|
||||||
if (b == null) {
|
break;
|
||||||
break;
|
}
|
||||||
|
cIndex = addComponent0(cIndex, b) + 1;
|
||||||
|
int size = components.size();
|
||||||
|
if (cIndex > size) {
|
||||||
|
cIndex = size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cIndex = addComponent0(cIndex, b) + 1;
|
return cIndex;
|
||||||
int size = components.size();
|
} finally {
|
||||||
if (cIndex > size) {
|
for (; i < buffers.length; ++i) {
|
||||||
cIndex = size;
|
ByteBuf b = buffers[i];
|
||||||
|
if (b != null) {
|
||||||
|
try {
|
||||||
|
b.release();
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cIndex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -242,9 +284,13 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements
|
|||||||
*
|
*
|
||||||
* Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
|
* Be aware that this method does not increase the {@code writerIndex} of the {@link CompositeByteBuf}.
|
||||||
* If you need to have it increased you need to handle it by your own.
|
* If you need to have it increased you need to handle it by your own.
|
||||||
*
|
* <p>
|
||||||
|
* {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects in {@code buffers} is transfered to this
|
||||||
|
* {@link CompositeByteBuf}.
|
||||||
* @param cIndex the index on which the {@link ByteBuf} will be added.
|
* @param cIndex the index on which the {@link ByteBuf} will be added.
|
||||||
* @param buffers the {@link ByteBuf}s to add
|
* @param buffers the {@link ByteBuf}s to add. {@link ByteBuf#release()} ownership of all
|
||||||
|
* {@link ByteBuf#release()} ownership of all {@link ByteBuf} objects is transfered to this
|
||||||
|
* {@link CompositeByteBuf}.
|
||||||
*/
|
*/
|
||||||
public CompositeByteBuf addComponents(int cIndex, Iterable<ByteBuf> buffers) {
|
public CompositeByteBuf addComponents(int cIndex, Iterable<ByteBuf> buffers) {
|
||||||
addComponents0(cIndex, buffers);
|
addComponents0(cIndex, buffers);
|
||||||
@ -253,21 +299,32 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int addComponents0(int cIndex, Iterable<ByteBuf> buffers) {
|
private int addComponents0(int cIndex, Iterable<ByteBuf> buffers) {
|
||||||
if (buffers == null) {
|
|
||||||
throw new NullPointerException("buffers");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buffers instanceof ByteBuf) {
|
if (buffers instanceof ByteBuf) {
|
||||||
// If buffers also implements ByteBuf (e.g. CompositeByteBuf), it has to go to addComponent(ByteBuf).
|
// If buffers also implements ByteBuf (e.g. CompositeByteBuf), it has to go to addComponent(ByteBuf).
|
||||||
return addComponent0(cIndex, (ByteBuf) buffers);
|
return addComponent0(cIndex, (ByteBuf) buffers);
|
||||||
}
|
}
|
||||||
|
checkNotNull(buffers, "buffers");
|
||||||
|
|
||||||
if (!(buffers instanceof Collection)) {
|
if (!(buffers instanceof Collection)) {
|
||||||
List<ByteBuf> list = new ArrayList<ByteBuf>();
|
List<ByteBuf> list = new ArrayList<ByteBuf>();
|
||||||
for (ByteBuf b: buffers) {
|
try {
|
||||||
list.add(b);
|
for (ByteBuf b: buffers) {
|
||||||
|
list.add(b);
|
||||||
|
}
|
||||||
|
buffers = list;
|
||||||
|
} finally {
|
||||||
|
if (buffers != list) {
|
||||||
|
for (ByteBuf b: buffers) {
|
||||||
|
if (b != null) {
|
||||||
|
try {
|
||||||
|
b.release();
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
buffers = list;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection<ByteBuf> col = (Collection<ByteBuf>) buffers;
|
Collection<ByteBuf> col = (Collection<ByteBuf>) buffers;
|
||||||
@ -1457,10 +1514,7 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
private ByteBuf allocBuffer(int capacity) {
|
private ByteBuf allocBuffer(int capacity) {
|
||||||
if (direct) {
|
return direct ? alloc().directBuffer(capacity) : alloc().heapBuffer(capacity);
|
||||||
return alloc().directBuffer(capacity);
|
|
||||||
}
|
|
||||||
return alloc().heapBuffer(capacity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1482,7 +1536,6 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
void freeIfNecessary() {
|
void freeIfNecessary() {
|
||||||
// Unwrap so that we can free slices, too.
|
|
||||||
buf.release(); // We should not get a NPE here. If so, it must be a bug.
|
buf.release(); // We should not get a NPE here. If so, it must be a bug.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user