Buffer中的public void write(Buffer source, long byteCount)解析

发布时间 2023-04-12 11:47:45作者: lianzhen
  这个把source缓冲区中的数据写到当前缓冲区的方法是比较经典的:
  
   if (source == null) throw new IllegalArgumentException("source == null");
   //这个判断是防止自己把数据写到自身这个Buffer中 
   if (source == this) throw new IllegalArgumentException("source == this");
   //每个Segment中最大存储的自己是8k,因此写的时候需要进行校验
   checkOffsetAndCount(source.size, 0, byteCount);
   
   //核心设计来了
   每次读取source中的数据时,都是从head开始,如果当前的剩余的byteCount小于head中的有效数据
   判断当前buffer中的尾Segment有没有操作权限并且可用空间能否放得下当前剩余的byteCount,如果可以放的下直接
   调用source.head.writeTo(tail, (int) byteCount)方法把source中的数据写进tail中;结束
   否则就把head分割成两部分。
   
   此时source的head就是分割的后一个Segment,而前一个Segment则给到了当前的Segment了,成为了他的尾Segment。
   
      while (byteCount > 0) {
      // 说明当前剩余的长度包含在了source的头中,也意味着循环的结束
      if (byteCount < (source.head.limit - source.head.pos)) {
        //找到当前Segment的尾部
        Segment tail = head != null ? head.prev : null;
        //权限判断和可用空间的判断是否都符合写入条件
        if (tail != null && tail.owner
            && (byteCount + tail.limit - (tail.shared ? 0 : tail.pos) <= Segment.SIZE)) {
          //如果符合要求,那就直接把source中byteCount长度的字节移动到tail中
          source.head.writeTo(tail, (int) byteCount);
          //更新source的长度
          source.size -= byteCount;
          //更新当前缓冲区的长度
          size += byteCount;
          //结束
          return;
        } else {
         
          //不符合上述条件的,我没就通过split把head分割成2部分,前一部分就是我们需要写入的数据,此时也是source的头Segment
          source.head = source.head.split((int) byteCount);
        }
      }

      //需要移动的就是source的头
      Segment segmentToMove = source.head;
      //计算移动的长度,更新会用到
      long movedByteCount = segmentToMove.limit - segmentToMove.pos;
      //通过pop方法位source指定新的head
      source.head = segmentToMove.pop();
      //如果当前的buffer时空的,那么segmentToMove直接作为buffer的头即可
      if (head == null) {
        head = segmentToMove;
        head.next = head.prev = head;
      } else {
        //否则就把segmentToMove插入到尾部
        Segment tail = head.prev;
        tail = tail.push(segmentToMove);
        //这里还进行了一次压缩:里面也会进行write操作
        tail.compact();
      }
      //更新source的长度
      source.size -= movedByteCount;
      //更新当前缓冲区的长度
      size += movedByteCount;
      //更新剩余需要写入的长度
      byteCount -= movedByteCount;
    }