lucene工具类-ByteBlockPool

slice具体使用 ByteSliceWriter ByteSliceReader

ByteBlockPool
维护多个字节数组,可自动扩容,来对外提供基本的字节类型数据存储的功能,类似于jdk ArrayList数据的实现,调用者可以把ByteBlockPool当成是一个无限扩容的数组使用

slice
在ByteBlockPool基础上 又封装出slice的逻辑,slice是ByteBlockPool 上的某一段数据,刚开始分配很少的字节数,写满后新创建slice,越往后slice越大,每个slice后四个字节存放下一个slice的位置信息,以此可以用多个间断的slice来表示一个数据,slice的扩容规则如下


public final static int[] NEXT_LEVEL_ARRAY = {1, 2, 3, 4, 5, 6, 7, 8, 9, 9};
public final static int[] LEVEL_SIZE_ARRAY = {5, 14, 20, 30, 40, 40, 80, 80, 120, 200};

    final int level = slice[upto] & 15;//slice[upto]初始为16 在写入slice的时候 初始一定都为0 遇到不为0的就是slice的结束位置
    final int newLevel = NEXT_LEVEL_ARRAY[level];
    final int newSize = LEVEL_SIZE_ARRAY[newLevel];

buffers 字节数组
bufferUpto buffers写入位置
buffer buffers数组中当前的元素
byteUpto buffer的写入位置

public int allocSlice(final byte[] slice, final int upto) {

    final int level = slice[upto] & 15;//buffers中位置
    final int newLevel = NEXT_LEVEL_ARRAY[level];
    final int newSize = LEVEL_SIZE_ARRAY[newLevel];

    // Maybe allocate another block
    if (byteUpto > BYTE_BLOCK_SIZE-newSize) {
      nextBuffer();
    }

    final int newUpto = byteUpto;
    final int offset = newUpto + byteOffset;
    byteUpto += newSize;

    // Copy forward the past 3 bytes (which we are about
    // to overwrite with the forwarding address):
    buffer[newUpto] = slice[upto-3];
    buffer[newUpto+1] = slice[upto-2];
    buffer[newUpto+2] = slice[upto-1];

    // Write forwarding address at end of last slice: slice最后四个字节存放 下个slice的开始位置
    slice[upto-3] = (byte) (offset >>> 24);
    slice[upto-2] = (byte) (offset >>> 16);
    slice[upto-1] = (byte) (offset >>> 8);
    slice[upto] = (byte) offset;
        
    // Write new level:
    buffer[byteUpto-1] = (byte) (16|newLevel);

    return newUpto+3;
  }
  public void readBytes(final long offset, final byte bytes[], int bytesOffset, int bytesLength) {
    int bytesLeft = bytesLength;
    int bufferIndex = (int) (offset >> BYTE_BLOCK_SHIFT);//offset 得到buffers中的其实位置
    int pos = (int) (offset & BYTE_BLOCK_MASK);//得到buffer中的位置
    while (bytesLeft > 0) {//处理数据属于两个buffer的情况
      byte[] buffer = buffers[bufferIndex++];
      int chunk = Math.min(bytesLeft, BYTE_BLOCK_SIZE - pos);
      System.arraycopy(buffer, pos, bytes, bytesOffset, chunk);
      bytesOffset += chunk;
      bytesLeft -= chunk;
      pos = 0;
    }
  }
  public int newSlice(final int size) {
    if (byteUpto > BYTE_BLOCK_SIZE-size)
      nextBuffer();
    final int upto = byteUpto;
    byteUpto += size;
    buffer[byteUpto-1] = 16;//赋值为16 调用时 会重upto开始写入,当遇到buffer[pos]位置不为0 时,会调用allocSlice方法 通过 16&15得到当前NEXT_LEVEL_ARRAY中level
    return upto;
  }
public void nextBuffer() {//buffers写入位置bufferUpto 达到buffers的最大长度时 对buffers拷贝 扩容
    if (1+bufferUpto == buffers.length) {//bufferUpto 
      byte[][] newBuffers = new byte[ArrayUtil.oversize(buffers.length+1,//根据当前机器64/32位和对象引用占用字节数获得最新长度
                                                        NUM_BYTES_OBJECT_REF)][];
      System.arraycopy(buffers, 0, newBuffers, 0, buffers.length);//拷贝操作
      buffers = newBuffers;
    }
    buffer = buffers[1+bufferUpto] = allocator.getByteBlock();//allocator分配器负责初始化buffers中每个数组的大小
    bufferUpto++;//buffers写入位置+1

    byteUpto = 0;//buffer写入位置
    byteOffset += BYTE_BLOCK_SIZE;//指针位置初始化
  }
public void setBytesRef(BytesRef term, int textStart) {//通过指定位置开始读取一个BytesRes
    final byte[] bytes = term.bytes = buffers[textStart >> BYTE_BLOCK_SHIFT];
    int pos = textStart & BYTE_BLOCK_MASK;
    if ((bytes[pos] & 0x80) == 0) {//小于128 一个字节 表示长度
      // length is 1 byte
      term.length = bytes[pos];
      term.offset = pos+1;
    } else {
      // length is 2 bytes 大于128两个字节表示长度
      term.length = (bytes[pos]&0x7f) + ((bytes[pos+1]&0xff)<<7);
      term.offset = pos+2;
    }
    assert term.length >= 0;
  }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值