整體上,sstable文件分為數據區與索引區,尾部的footer指出了meta index block與data index block的偏移與大小,data index block指出了各data block的偏移與大小,meta index block指出了各meta block的偏移與大小。
1)DataBlock:存儲Key-Value記錄,分為Data、type、CRC三部分
2)MetaBlock:暫時沒有使用
3)MetaBlock_index:記錄filter的相關信息(本文暫時沒有考慮filter)
4)IndexBlock:描述一個DataBlock,存儲着對應DataBlock的最大Key值,DataBlock在.sst文件中的偏移量和大小
5)Footer :索引的索引,記錄IndexBlock和MetaIndexBlock在SSTable中的偏移量了和大小
footer
先看footer結構。如下圖。footer位於sstable文件尾部,占用空間固定為48個字節。其末尾8個字節是一個magic_number。metaindex_handle與index_handle物理上占用了40個字節,但實際上存儲可能連32字節都不到。每一個handle的結構BlockHandle如右圖,邏輯上分別表示offset+size,在內存中占用16個字節,但存儲時由於采用可變長度編碼,每個handle的物理存儲通常不到8+8字節。因此這里兩個handle總共占用不到32個字節,剩余填充0。

leveldb footer + block handle
BlockHandle指出了block的偏移與大小。在sstable文件中,一般有多個data block,多個meta block(當前版本只有一個filter block,可擴充),1個meta index block,1個data index block。其中filter block的內部結構稍微不同於其他Block,但都是用BlockHandle來指向的。
block
邏輯上主要分為數據與重啟點。重啟點也是一個指針,指出了一些特殊的位置。data block中的key是有序存儲的,相鄰的key之間可能有重復,因此存儲時采用前綴壓縮,后一個key只存儲與前一個key不同的部分。那些重啟點指出的位置就表示該key不按前綴壓縮,而是完整存儲該key。除了減少壓縮空間之外,重啟點的第二個作用就是加速讀取。如果說data index block可以通過二分來定位具體的block,那么重啟點則可以通過二分的方法來定位具體的重啟點位置,進一步減少了需要讀取的數據。對於leveldb來講,可以通過options.block_size與options.block_restart_interval來設置block的大小與重啟點的間隔。默認data block的大小為4K。而重啟點則每隔16個key。具體的單條record的存儲格式如下圖所示。
Block格式
Record 格式
data index block
Index Block的結構與Data Block一樣,只不過每個group只包含一條記錄,即Data Block的最大Key與偏移。其實這里說最大Key並不是很准確,理論上,只要保存最大Key就可以實現二分查找,但是Level DB在這里做了個優化,它並保存最大key,而是保存一個能分隔兩個Data Block的最短Key,如:假定Data Block1的最后一個Key為“abcdefg”,Data Block2的第一個Key為“abzxcv”,則index可以記錄Data Block1的索引key為“abd”;這樣的分割串可以有很多,只要保證Data Block1中的所有Key都小於等於此索引,Data Block2中的所有Key都大於此索引即可。這種優化縮減了索引長度,查詢時可以有效減小比較次數。
data block與meta index block、data index block都是采用block來存儲的(filter block稍微不同)。而對於block來講,其都是按(key,value)格式存儲一條條的record的。對於這些不同類型的block,其(key,value)都是什么了?總結如下圖。現在只有一個meta block用於filter,因此meta index block中也只有一條記錄,其key是filter. + filter_policy的name。
不同block的key, value
sstable格式