2023-09-13  阅读(4)
原文作者:https://blog.csdn.net/wangwei19871103/category_9681495_2.html 原文地址: https://blog.csdn.net/wangwei19871103/article/details/104493244

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

其实写也是类似的:

202309132206045931.png

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

202309132206063512.png
切片这个时候有用了,而且是源缓冲区:

202309132206090063.png

isDirect是否是直接缓冲区

只有组件里的缓冲区全部是直接缓冲区的时候,才是直接缓冲区。

202309132206110774.png

capacity有多少可读字节

202309132206137745.png

deallocate释放缓冲区

202309132206142146.png

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

组件数量两个的时候可能就没结果了。

202309132206153057.png

202309132206163648.png

202309132206173469.png

2023091322061833010.png

2023091322061927011.png
主要的方法都介绍了,只要理解这些,其他的大部分方法也都是这些简单的组合而已,就不多说了。

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


Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。

它的内容包括:

  • 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
  • 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
  • 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
  • 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
  • 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
  • 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
  • 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
  • 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw

目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:

想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询

同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。

阅读全文