Netty CompositeByteBuf 简介
CompositeByteBuf 在聚合时使用,多个buffer合并时,不需要copy,通过
CompositeByteBuf 可以把需要合并的bytebuf 组合起来,对外提供统一的readindex和writerindex
CompositeByteBuf 里面有个ComponentList,继承ArrayList,聚合的bytebuf都放在ComponentList里面,最小容量为16。
Component
compositeByteBuf 的ComponentList 里存的是byteBuf的一个包装类Component,Component 如下:
private static final class Component {
final ByteBuf buf;
final int length;
int offset;
int endOffset;
Component(ByteBuf buf) {
this.buf = buf;
length = buf.readableBytes();
}
void freeIfNecessary() {
buf.release(); // We should not get a NPE here. If so, it must be a bug.
}
}
Component 的offset是上一个的endoffset,endoffset是offset+length;
创建
CompositeByteBuf content = ctx.alloc().compositeBuffer(maxCumulationBufferComponents);
maxCumulationBufferComponents 是指定ComponentList的大小,这样初始化的CompositeByteBuf的是空的
,即writerindex=readerindx=0
添加ByteBuf
content.addComponent(true, byteBuf);
添加到CompositeByteBuf 的ComponentList如下,increaseWriterIndex为true,代表更新writerIndex,cIndex为components.size()。
private int addComponent0(boolean increaseWriterIndex, int cIndex, ByteBuf buffer) {
assert buffer != null;
boolean wasAdded = false;
try {
//检查cindex是否超过ComponentList的容量
checkComponentIndex(cIndex);
int readableBytes = buffer.readableBytes();
// No need to consolidate - just add a component to the list.
@SuppressWarnings("deprecation")
//封装为Component,采用大端序
Component c = new Component(buffer.order(ByteOrder.BIG_ENDIAN).slice());
//比如第一次聚合的时候,cIndex=0,components.size() = 0;
if (cIndex == components.size()) {
wasAdded = components.add(c);
if (cIndex == 0) {
//如果是第一个buffer,则该Component的endOffset为buffer的大小。
c.endOffset = readableBytes;
} else {
//如果不是第一个buffer,则该buffer的offset为上一个的endO
Component prev = components.get(cIndex - 1);
c.offset = prev.endOffset;
c.endOffset = c.offset + readableBytes;
}
} else {
components.add(cIndex, c);
wasAdded = true;
if (readableBytes != 0) {
updateComponentOffsets(cIndex);
}
}
if (increaseWriterIndex) {
writerIndex(writerIndex() + buffer.readableBytes());
}
return cIndex;
} finally {
if (!wasAdded) {
buffer.release();
}
}
}
CompositeByteBuf 扩容
CompositeByteBuf 在增加新的bytebuf后,会检查CompositeByteBuf的数组components 大小,默认大小是16,即在
组合了16个bytebuf后,就要扩容了。
先说下是CompositeByteBuf怎么扩容的,CompositeByteBuf是创建一个新的bytebuf,把数组里的16个bytebuf 写到这个新创建bytebuf里,然后吧数组清空掉,并把新创建的一个大的bytebuf添加到数组里,类似归并的做法,涉及到多次copy,所以尽量不需要扩容。
扩容的源码如下:
final int numComponents = components.size();
if (numComponents > maxNumComponents) {
final int capacity = components.get(numComponents - 1).endOffset;
//创建一个大的bytebuf,容量会所有bytebuf的总和。
ByteBuf consolidated = allocBuffer(capacity);
// We're not using foreach to avoid creating an iterator.
for (int i = 0; i < numComponents; i ++) {
Component c = components.get(i);
ByteBuf b = c.buf;
//copy c的数据到consolidated
consolidated.writeBytes(b);
// 释放c的资源。
c.freeIfNecessary();
}
Component c = new Component(consolidated);
c.endOffset = c.length;
components.clear();
components.add(c);
}
}