Netty CompositeByteBuf 簡介
CompositeByteBuf 在聚合時使用,多個buffer合并時鬼悠,不需要copy,通過
CompositeByteBuf 可以把需要合并的bytebuf 組合起來,對外提供統(tǒng)一的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;
創(chuàng)建
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 擴(kuò)容
CompositeByteBuf 在增加新的bytebuf后匿垄,會檢查CompositeByteBuf的數(shù)組components 大小移宅,默認(rèn)大小是16归粉,即在
組合了16個bytebuf后,就要擴(kuò)容了漏峰。
先說下是CompositeByteBuf怎么擴(kuò)容的糠悼,CompositeByteBuf是創(chuàng)建一個新的bytebuf,把數(shù)組里的16個bytebuf 寫到這個新創(chuàng)建bytebuf里浅乔,然后吧數(shù)組清空掉倔喂,并把新創(chuàng)建的一個大的bytebuf添加到數(shù)組里,類似歸并的做法靖苇,涉及到多次copy席噩,所以盡量不需要擴(kuò)容。
擴(kuò)容的源碼如下:
final int numComponents = components.size();
if (numComponents > maxNumComponents) {
final int capacity = components.get(numComponents - 1).endOffset;
//創(chuàng)建一個大的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的數(shù)據(jù)到consolidated
consolidated.writeBytes(b);
// 釋放c的資源。
c.freeIfNecessary();
}
Component c = new Component(consolidated);
c.endOffset = c.length;
components.clear();
components.add(c);
}
}