2021SC@SDUSC hbase代码分析(十三)HFile分析(5)

2021SC@SDUSC hbase源码分析(十三)HFile分析(五)

2021SC@SDUSC 2021SC@SDUSC
2021SC@SDUSC 2021SC@SDUSC

索引相关Block

HFile索引简介

根据索引层级的不同,HFile中索引结构分为两种:single-level和multi-level,前者表示单层索引,后者表示多级索引,一般为两级或三级。HFile V1版本中只有single-level一种索引结构,V2版本中引入多级索引。之所以引入多级索引,是因为随着HFile文件越来越大,Data Block越来越多,索引数据也越来越大,已经无法全部加载到内存中,多级索引可以只加载部分索引,从而降低内存使用空间。同布隆过滤器内存使用问题一样,这也是V1版本升级到V2版本最重要的因素之一。

V2版本Index Block有两类:Root Index BlockNonRoot Index Block。NonRootIndex Block又分为Intermediate Index Block和Leaf Index Block两种。HFile中索引是树状结构,Root Index Block表示索引数根节点,Intermediate Index Block表示中间节点,Leaf Index Block表示叶子节点,叶子节点直接指向实际DataBlock

索引结构

HFile索引结构如下图:

请添加图片描述

1. Root Index Block

简介

Root Index Block表示索引树根节点索引块,可以作为Bloom Block的直接索引,也可以作为Data Block索引的根索引。在Single-Level和Multi-Level中两种索引结构对应的Root Index Block稍有差异,如图示:

请添加图片描述

源码分析

上图中的Index Entry表示具体的索引对象,每个索引对象由3个字段组成:

  1. Block Offset表示索引指向Data Block的偏移量;

  2. BlockDataSize表示索引指向Data Block在磁盘上的大小;

  3. BlockKey表示索引指向Data Block中的第一个Key。

protected long[] blockOffsets;
protected int[] blockDataSizes;

/**
     * @param i from 0 to {@link #getRootBlockCount() - 1}
     */
public long getRootBlockOffset(int i) {
    return blockOffsets[i];
}

/**
     * @param i zero-based index of a root-level block
     * @return the on-disk size of the root-level block for version 2, or the
     *         uncompressed size for version 1
     */
public int getRootBlockDataSize(int i) {
    return blockDataSizes[i];
}

除此之外,还有另外3个字段用来记录MidKey的相关信息,这些信息用于在对HFile进行split操作时,快速定位HFile的切分点位置。需要注意的是单层索引结构和多级索引结构相比,仅缺少与MidKey相关的这三个字段。

public void readMultiLevelIndexRoot(HFileBlock blk,
    final int numEntries) throws IOException {
  DataInputStream in = readRootIndex(blk, numEntries);
  // after reading the root index the checksum bytes have to
  // be subtracted to know if the mid key exists.
  int checkSumBytes = blk.totalChecksumBytes();
  if ((in.available() - checkSumBytes) < MID_KEY_METADATA_SIZE) {
    // No mid-key metadata available.
    return;
  }
  midLeafBlockOffset = in.readLong();
  midLeafBlockOnDiskSize = in.readInt();
  midKeyEntry = in.readInt();
}

上述代码是对MidKeyEntry实体进行赋值操作的方法。

Root Index Block位于整个HFile的“ load-on-open ”部分,因此会在RegionServer打开HFile时直接加载到内存中。此处需要注意的是,在Trailer Block中有一个字段为DataIndexCount,表示Root Index Block中Index Entry的个数。

/**
 * The number of entries in the root data index.
 */
private int dataIndexCount;


@org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting
    HFileProtos.FileTrailerProto toProtobuf() {
    HFileProtos.FileTrailerProto.Builder builder = HFileProtos.FileTrailerProto.newBuilder()
        .setFileInfoOffset(fileInfoOffset)
        .setLoadOnOpenDataOffset(loadOnOpenDataOffset)
        .setUncompressedDataIndexSize(uncompressedDataIndexSize)
        .setTotalUncompressedBytes(totalUncompressedBytes)
        .setDataIndexCount(dataIndexCount)
        .setMetaIndexCount(metaIndexCount)
        .setEntryCount(entryCount)
        .setNumDataIndexLevels(numDataIndexLevels)
        .setFirstDataBlockOffset(firstDataBlockOffset)
        .setLastDataBlockOffset(lastDataBlockOffset)
        .setComparatorClassName(getHBase1CompatibleName(comparatorClassName))
        .setCompressionCodec(compressionCodec.ordinal());
    if (encryptionKey != null) {
        builder.setEncryptionKey(UnsafeByteOperations.unsafeWrap(encryptionKey));
    }
    return builder.build();
}

只有知道Entry的个数才能正确地将所有Index Entry加载到内存。

2. NonRoot Index Block

简介

当HFile中Data Block越来越多,单层结构的根索引会不断膨胀,超过一定阈值之后就会分裂为多级结构的索引结构。多级结构中根节点是Root Index Block。而索引树的中间层节点和叶子节点在HBase中存储为NonRoot Index Block,但从Block结构的视角分析,无论是中间节点还是叶子节点,其都拥有相同的结构。其结构如下图:

请添加图片描述

相关分析

和Root Index Block相同,NonRoot Index Block中最核心的字段也是IndexEntry,用于指向叶子节点块或者Data Block。

但是Non-Root Index Block多了EntryOffset 和 numEntires

numEntires: 记录entry的数量

EntryOffset: 是Non-Root Index Block内部索引字段,表示Index Entry在该block中的相对偏移量,相对于第一个Index Entry,用于实现Block内部的二分查找,故针对Non-Root Index Block,在其内部定位一个key的具体索引,不是通过遍历而是通过二分查找实现,可以更加高效快速定位到待查找的key

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值