Leveldb源碼解析第四篇【sstable添加key的流程】

版權聲明:本文爲博主原創文章,未經博主允許不得轉載。

  1. 添加一個key-value需要構造一個TableBuilder
  2. 在構造TableBuilder時會構造一個Rep
    • Rep裏面有BlockBuilder類型的data_block和index_block,還有FilterBlockBuilder類型的filter_block
    • index_block的重啓點頻率設置爲1(默認是16)
    • filter_block會調用StartBlock,傳遞的參數爲0,這行貌似沒啥用
  3. 調用TableBuilder的Add函數
  4. 首先判斷這個key是不是data block的第一個key
  5. 如果是,就要寫入index block了,這裏我們考慮一個極端情況,這個key是table的第一個key,那麼再算上一個data block的最後一個key和當前key的中間key時,last_key是爲空的,在FindShortestSeparator中r->last_key不會發生任何變化,也就是還是初始值,空值;上一個data block的偏移信息和大小都是0,那麼index_block中第一行的key爲空,經過我的測試,任何一個字符串都不空大)
  6. 在filter_block中添加key,實際是在string類型的keys_中追加key,然後在start_中添加key的長度
  7. 將當前key賦值給last_key
  8. data_block中添加key-value,調用BlockBuilder::Add方法,將shared|non_shared|value.size|key_non_shared_data|value_data放到buffer_中
  9. 如果data_block的大小已經大於或等於閾值,那麼就要刷新table了,這個地方data_block的大小是什麼計算出來的呢,buffer_大小加上重啓點個數乘以4再加上重啓點個數佔用的4個字節(這裏的4個字節是大衆機型,有可能有的機型uint32不是4個字節)
  10. 如果data block小於閾值的話,那就繼續上面的步驟,否則就開始flush吧;整個table可能當成是一個string,string先把所有的data block寫完,然後在寫其他東東
    • 這裏調用WriteBlock將data block放到一個長串中,調用的是block的Finish函數,長串中包含key-value、重啓點和重啓點個數;然後看是否要壓縮這個長串,再將這個長串寫入到文件中
    • 將r->pending_handle的偏移設置爲當前r的偏移(如果是第一個data block,那麼現在r的偏移就是0),大小設置爲寫入的block長串的大小,然後寫入長串,在寫入五個字節的後綴,其中前4個字節是長串的crc信息,最後一個字節是這個長串有沒有壓縮
    • 將r的偏移設置爲當前寫入文件的長度
  11. data_block寫完後開始構造filter_block,也就是調用filter_block的StartBlock函數,傳入的參數是當前r的偏移,也就是此時r寫入文件的大小
    • 算出要構造幾個bitmap(在第2步中,構造rep的時候有調用StartBlock,但是沒啥用,不知道爲啥有這一步),構造幾個bitmap就要調用幾次GenerateFilter,如果是循環中的第一次調用,將當前result的大小加到filter_offsets_中(第一次是0),然後創建一個bitmap,bitmap最後一個字節存放的是一個key需要算多少次hash;並將bitmap放在filter的result_中,result_也是一個長字符串;接下來繼續循環中的第二次,此時filter中的keys已經清空了,那麼將此時result_的大小添加到filter_offsets_中,後面還有循環的話也是這個做法
  12. 如果table完成了的話,調用Finish函數
    • 先flush一下,將data block寫入文件,同樣的,繼續構造bitmap
    • 再調用filter_block的Finish函數,將filter_block完結,調用一次GenerateFilter,將所有bitmap的大小寫入到filter_offsets_中,將filter_offsets_中的偏移量放到result_中,再將偏移量的個數寫入到result_中,最後追加一個字節放kFilterBaseLg
    • 將filter 的result_寫入到文件中,filter_block_handle的偏移存放r此時的偏移,也就是data block寫完後指針指向的點,大小爲result_的大小,然後就和上面一樣了,在寫入5個字節,前四個是crc信息,最後一個是時候壓縮
    • 寫完filter後,開始寫meta_index_block,meta_index_block是一個blockbuilder類型,只存放一個key-value,key的內容是filter的名字,value的信息是filter_block_handle的信息,也就是通過meta_index_block我可以快速得到所有data block的filter的信息,然後將meta_index_block寫入到文件中
    • 接下來就是index_block了,在index_block中追加最後一個key,這個key要比last_key大一丟丟,value的值是最後一個data block偏移和最後一個data block的大小
    • 將index_block寫入到文件中,最後加5個字節,和上面一樣
  13. 最後是footer,footer中存放了metaindex和index的偏移信息,將footer信息寫入到文件中

【作者:antonyxu https://antonyxux.github.io/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章