Netty CompositeByteBuf 原理

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);
    }
}

你可能感兴趣的:(Netty CompositeByteBuf 原理)