吃透Netty源码系列三十六之CompositeByteBuf详解二

removeComponent删除组件

前一篇讲了新增操作,接下来讲讲其他的,首先当然是删除啦,删除索引对应的缓冲区。原理就是获取对应的组件,然后释放,然后从组件数组中删除

  public CompositeByteBuf removeComponent(int cIndex) {
        checkComponentIndex(cIndex);
        Component comp = components[cIndex];
        if (lastAccessed == comp) {//查找的时候缓存用的
            lastAccessed = null;
        }
        comp.free();//释放缓冲区
        removeComp(cIndex);//删除组件
        if (comp.length() > 0) {//如果有可读数据被删除了,那就需要更新之后的组件索引
            updateComponentOffsets(cIndex);
        }
        return this;
    }
//删除索引对应的组件
    private void removeComp(int i) {
        removeCompRange(i, i + 1);
    }

getByte获取数据

增删讲完了,该说说读和写吧,获取指定索引的字节数据。

  @Override
    public byte getByte(int index) {
        Component c = findComponent(index);
        return c.buf.getByte(c.idx(index));//根据索引获取字节数据
    }

findComponent查找组件

如果缓存的那个索引区域就是我们要找的,就直接返回去,否则就要去找。

    private Component findComponent(int offset) {
        Component la = lastAccessed;//缓存的
        if (la != null && offset >= la.offset && offset < la.endOffset) {//索引在缓存组件内
           ensureAccessible();
           return la;
        }
        checkIndex(offset);
        return findIt(offset);
    }

findIt二分查找

二分查找法查找,找到的组件会缓存到lastAccessed

private Component findIt(int offset) {
        for (int low = 0, high = componentCount; low <= high;) {
            int mid = low + high >>> 1;
            Component c = components[mid];
            if (offset >= c.endOffset) {
                low = mid + 1;
            } else if (offset < c.offset) {
                high = mid - 1;
            } else {
                lastAccessed = c;
                return c;
            }
        }

        throw new Error("should not reach here");
    }

其实写也是类似的:
在这里插入图片描述

toComponentIndex获取偏移对应的组件索引

获取索引后当然就可以获取组件啦,当组件数量少的时候用了一些快速的方法,多了就用二分查找。

 public int toComponentIndex(int offset) {
        checkIndex(offset);
        return toComponentIndex0(offset);
    }
    //二分查找
    private int toComponentIndex0(int offset) {
        int size = componentCount;
        if (offset == 0) { // fast-path zero offset
            for (int i = 0; i < size; i++) {
                if (components[i].endOffset > 0) {
                    return i;//返回存在可读的第一个组件的索引
                }
            }
        }
        if (size <= 2) { // fast-path for 1 and 2 component count
            return size == 1 || offset < components[0].endOffset ? 0 : 1;//个数为1,直接就是0。如果是2的话,看偏移是否小于第一个组件的endOffset,是就是0,否就是1
        }
        for (int low = 0, high = size; low <= high;) {//二分查找
            int mid = low + high >>> 1;
            Component c = components[mid];
            if (offset >= c.endOffset) {
                low = mid + 1;
            } else if (offset < c.offset) {
                high = mid - 1;
            } else {
                return mid;
            }
        }

        throw new Error("should not reach here");
    }

addFlattenedComponents可以添加复合缓冲区

这个方法可以判断添加的是什么类型的,如果不是复合的就按一般方法处理,如果是符合的,就把里面可读的组件都添加进来,注意如果待添加的复合缓冲区不可读的话,就不会添加,什么也不做。

 public CompositeByteBuf addFlattenedComponents(boolean increaseWriterIndex, ByteBuf buffer) {
        checkNotNull(buffer, "buffer");
        final int ridx = buffer.readerIndex();
        final int widx = buffer.writerIndex();
        if (ridx == widx) {//不可读了就释放
            buffer.release();
            return this;
        }
        if (!(buffer instanceof CompositeByteBuf)) {//不是复合类型的就直接调用加入
            addComponent0(increaseWriterIndex, componentCount, buffer);
            consolidateIfNeeded();
            return this;
        }
        final CompositeByteBuf from = (CompositeByteBuf) buffer;
        from.checkIndex(ridx, widx - ridx);
        final Component[] fromComponents = from.components;//取出所有组件
        final int compCountBefore = componentCount;//增加前个数
        final int writerIndexBefore = writerIndex;//增加前的写索引
        try {//从读索引开始获取对应的fromComponents组件获取信息,并重新创建组件添加到最后
            for (int cidx = from.toComponentIndex0(ridx), newOffset = capacity();; cidx++) {
                final Component component = fromComponents[cidx];//获取索引对应的组件
                final int compOffset = component.offset;//获取偏移
                final int fromIdx = Math.max(ridx, compOffset);//起点索引
                final int toIdx = Math.min(widx, component.endOffset);//终点索引
                final int len = toIdx - fromIdx;//还有多少个可读字节
                if (len > 0) { // skip empty components //不是空的,就创建组件添加到后面
                    addComp(componentCount, new Component(
                            component.srcBuf.retain(), component.srcIdx(fromIdx),
                            component.buf, component.idx(fromIdx), newOffset, len, null));
                }
                if (widx == toIdx) {//已经处理完了
                    break;
                }
                newOffset += len;//更新偏移
            }
            if (increaseWriterIndex) {
                writerIndex = writerIndexBefore + (widx - ridx);
            }
            consolidateIfNeeded();//必要就合并
            buffer.release();//释放
            buffer = null;
            return this;
        } finally {
            if (buffer != null) {//有异常的话需要回滚
                // if we did not succeed, attempt to rollback any components that were added
                if (increaseWriterIndex) {
                    writerIndex = writerIndexBefore;
                }
                for (int cidx = componentCount - 1; cidx >= compCountBefore; cidx--) {
                    components[cidx].free();//释放缓冲区
                    removeComp(cidx);//删除组件
                }
            }
        }
    }

iterator获取缓冲区迭代器

就是把里面的缓冲区都封装到迭代器里了,而且是只读的,获取的是组件里源缓冲区的切片slice

    public Iterator<ByteBuf> iterator() {
        ensureAccessible();
        return componentCount == 0 ? EMPTY_ITERATOR : new CompositeByteBufIterator();
    }

在这里插入图片描述
切片这个时候有用了,而且是源缓冲区:
在这里插入图片描述

isDirect是否是直接缓冲区

只有组件里的缓冲区全部是直接缓冲区的时候,才是直接缓冲区。
在这里插入图片描述

capacity有多少可读字节

在这里插入图片描述

deallocate释放缓冲区

在这里插入图片描述

根据组件数量来判断的方法

组件数量两个的时候可能就没结果了。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
主要的方法都介绍了,只要理解这些,其他的大部分方法也都是这些简单的组合而已,就不多说了。

好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值