Hfile分为4部分,其中loadOnOpen section 和trailer这2部分是open file时就会加载到内存的。
Step1:
读取文件末尾的4Bytes,得到Hfile format版本号,进而知道Trailer部分的大小, v2和v3都固定为4096Bytes;
Step2:
读取文件末尾的4096Bytes,这部分整体作为一个block,包含一些重要的元数据信息,目前有15个,分为以下几类;
偏移量:loadOnOpenDataOffset、fileinfoOffset、firstDataBlockOffset、lastDataBlockOffset;
数量和大小:totalUncomressedBytes、entryCount、dataIndexCount、metaIndexCount、uncompressedDataIndexSize、numDataIndexLevels
算法:compressionCodec、comparatorClassName、encryptionKey
版本号:majorVersion、minorVersion
其中,fileinfoOffset在v2以后已经没有实际用途
示例:
fileinfoOffset=1231091280,
loadOnOpenDataOffset=1231084052,
dataIndexCount=143,
metaIndexCount=0,
totalUncomressedBytes=4052639474,
entryCount=44722287,
compressionCodec=SNAPPY,
uncompressedDataIndexSize=18657365,
numDataIndexLevels=2,
firstDataBlockOffset=0,
lastDataBlockOffset=1231031083,
comparatorClassName=org.apache.hadoop.hbase.CellComparatorImpl,
encryptionKey=NONE,
majorVersion=3,
minorVersion=3
Step3:
根据loadOnOpenDataOffset读取Root Data Index block,包含numEntries和具体entry数据,每个entry包含offset、dataSize和key;
这里entry所表示的block类型与文件大小有关:
如果文件较小,Trailer中numDataIndexLevels字段的值为1,entry表示的是dataBlock,
如果文件较大,Trailer中numDataIndexLevels字段的值为2,entry表示的是leafIndexBlock
如果文件很大,Trailer中numDataIndexLevels字段的值为3,entry表示的是IntermediaLevelIndexBlock
较大和很大的阈值分别大约为100M和100G,该阈值与key长度和block大小相关;
读取分为2步:先读header(固定33字节),再根据header里面onDiskSizeWithoutHeader的值读取data部分;
这里在读取data时有个优化,会额外多读取一个header大小的数据,目的是使下一个block的读取可以一步完成,减少一次io交互,后续几个block的读取都是如此;
另外,该block末尾还存储了几个值,用于split时快速找到splitPoint:midLeafBlockOffset、midLeafBlockOnDiskSize、midKeyEntry;
Step4:
读取FileInfo该block以键值对的方式存储了一些元数据,读取之后内存中以Map形式存在,作为对比,Trailer内部只存储值,以位置顺序区分不同属性;
另外,这部分没有大小限制,可以根据需要灵活扩展,当前版本存储的属性示例如下;
BLOOM_FILTER_TYPE = ROW
DELETE_FAMILY_COUNT = 0
EARLIEST_PUT_TS = 1479619233886
KEY_VALUE_VERSION = 1
LAST_BLOOM_KEY = 69993111f5d1dfa4179d9f278192a0ad
MAJOR_COMPACTION_KEY = true
MAX_MEMSTORE_TS_KEY = 15986682
MAX_SEQ_ID_KEY = 15986682
TIMERANGE = 1479619233886....1577672100675
hfile.AVG_KEY_LEN = 73
hfile.AVG_VALUE_LEN = 5
hfile.CREATE_TIME_TS = 1577728182220
hfile.LASTKEY = 69993111f5d1dfa4179d9f278192a0ad/tag:userkn_zhengxin_list/1575836971202/Put/vlen=0/mvcc=0
Step5:
读取General BloomFilter Meta And Index
BloomFilter block的index固定只有一层,结构与RootDataIndex 类似;
meta部分额外包含了几个与bloom相关的算法和统计信息:totalByteSize、hashCount、hashType、totalKeyCount、totalMaxKeys;
Step6:
读取DeteleFamily BloomFilter Meta And Index
该block结构与General BloomFilter一致;