LevelDB:讀操作

前面寫(xiě)了兩篇文章介紹 LevelDB 的整體架構(gòu)接口使用壶愤。這篇文章,我們從代碼的角度看看 LevelDB 的設(shè)計(jì)與實(shí)現(xiàn)函筋,先從讀操作開(kāi)始贝润。

LevelDB 的版本更新不是很頻繁,整體變化不大掂墓。本文的源代碼參考和索引的版本是 LevelDB v1.20谦纱。

LevelDB 的目錄結(jié)構(gòu)很簡(jiǎn)單,就不用介紹了君编,直接進(jìn)入正題吧跨嘉。

leveldb::DB

LevelDB 暴露給外部的操作接口都封裝在 leveldb::DB 這個(gè)抽象類(lèi)里,具體實(shí)現(xiàn)是 leveldb::DBImpl 吃嘿。使用時(shí)偿荷,leveldb::DB 用于引用一個(gè) LevelDB 實(shí)例。一個(gè) LevelDB 實(shí)例可以簡(jiǎn)單認(rèn)為是一個(gè)支持并發(fā)讀寫(xiě)和持久化的 map唠椭。

LevelDB 暴露給外部的操作接口都很簡(jiǎn)單跳纳,具體可以根據(jù)上面提供的索引鏈接看看代碼和注釋。

讀操作

leveldb::DB::Get 根據(jù) Key 獲取 Value贪嫂,先看看函數(shù)的原型:

virtual Status Get(const ReadOptions& options, const Slice& key, std::string* value) = 0;

leveldb::ReadOptions 是讀操作的一些參數(shù)寺庄。verify_checksumsfill_cache 是兩個(gè)偏優(yōu)化的參數(shù),重點(diǎn)是 snapshot 參數(shù),表示本次讀操作要從哪個(gè) Snapshot 讀取斗塘。snapshot 默認(rèn)是 NULL赢织,此時(shí) LevelDB 會(huì)從當(dāng)前 Snapshot 讀取。

講到 Snapshot馍盟,我們順便來(lái)看看 leveldb::Snapshot 的實(shí)現(xiàn)于置。leveldb::Snapshot是個(gè)空殼,具體實(shí)現(xiàn)是在 leveldb::SnapshotImpl 贞岭,也相當(dāng)簡(jiǎn)單八毯,和 Snapshot 相關(guān)的變量只有一個(gè) number_ (SequenceNumber) —— 不難看出 LevelDB 是通過(guò)維護(hù)一個(gè) Sequence Number 來(lái)實(shí)現(xiàn)快照功能。

LevelDB 單個(gè) Key 的讀取操作的具體實(shí)現(xiàn)是 leveldb::DBImpl::Get 瞄桨。我們來(lái)看看讀操作的過(guò)程:

  1. 獲取互斥鎖话速。
  2. 獲取本次讀操作的 Sequence Number:如果 ReadOptions 參數(shù)的 snaphot 不為空,則使用這個(gè) snapshot 的 Sequence Number芯侥;否則泊交,默認(rèn)使用 LastSequence(LastSequence 會(huì)在每次寫(xiě)操作后更新)。
  3. MemTable柱查, Immutable Memtable 和 Current Version 增加引用計(jì)數(shù)廓俭,避免在讀取過(guò)程中被后臺(tái)線程進(jìn)行 Compaction 時(shí)“垃圾回收”了。Version 主要用來(lái)維護(hù) SST 文件的版本信息唉工。
  4. 釋放互斥鎖 研乒,下面 5 和 6 兩步是沒(méi)有持有鎖的,特別是第 6 步酵紫。
  5. 構(gòu)造 LookupKey
  6. 查找
    1. 從 MemTable 查找 错维。
    2. 從 Immutable Memtable 查找奖地。
    3. 從 SST 文件查找
  7. 獲取互斥鎖
  8. 更新 SST 文件的統(tǒng)計(jì)信息赋焕,根據(jù)統(tǒng)計(jì)結(jié)果決定是否調(diào)度后臺(tái) Compaction参歹。
  9. MemTable, Immutable Memtable 和 Current Version 減少引用計(jì)數(shù)
  10. 釋放鎖(由析構(gòu)函數(shù)完成)隆判,返回結(jié)果犬庇。

MemTable

上面分析讀流程的時(shí)候,可以發(fā)現(xiàn)第 6 步侨嘀,從 Memtable臭挽、Immutable Memtable 和 Current Version 指向的 SST 文件查找內(nèi)容是不需要持有鎖的。這樣做沒(méi)有并發(fā)讀寫(xiě)的問(wèn)題嗎咬腕?

簡(jiǎn)單分析一下:引用計(jì)數(shù)保證了相關(guān)文件和內(nèi)存數(shù)據(jù)結(jié)構(gòu)不會(huì)被回收欢峰,而 Immutable Memtable 和 SST 文件都是只讀的,沒(méi)有并發(fā)讀寫(xiě)問(wèn)題。所以纽帖,只要看 MemTable 是否支持并發(fā)讀寫(xiě)宠漩。

leveldb::MemTable 底層的實(shí)現(xiàn)是 leveldb::SkipList 。在 leveldb::SKipList 有一段注釋說(shuō)明 懊直,簡(jiǎn)單地說(shuō)就是:

  1. 寫(xiě)寫(xiě)沖突需要外部同步扒吁。
  2. 讀寫(xiě)沖突不需要外部同步,只要保證 SkipList 不會(huì)被垃圾回收就好室囊。
  3. 這里的 SkipList 只插入雕崩,不修改和刪除

因此波俄,從這段注釋可以看出晨逝,MemTable 支持一寫(xiě)多讀同時(shí)并發(fā)操作。后面有機(jī)會(huì)聊到 LevelDB 的寫(xiě)操作再來(lái)介紹一下 SkipList 的 Insert 操作如何實(shí)現(xiàn)讀寫(xiě)并發(fā)不需要鎖懦铺。

LookupKey

LevelDB 通過(guò) user_key 和 sequence 構(gòu)造 leveldb::LookupKey 捉貌,用于 LevelDB 內(nèi)部接口的查找。參考 LookupKey 的代碼和注釋 冬念,其格式為:

LookupKey.png
  1. klength 的類(lèi)型是 varint32趁窃,是 leveldb 內(nèi)部編碼的可變長(zhǎng)度的 uint32_t,存儲(chǔ) userkey + tag 的長(zhǎng)度急前。表示一個(gè) varint32 最多需要 5 個(gè)字節(jié)醒陆。
  2. userkey 就是一個(gè) userkey 的 char 數(shù)組。
  3. tag 是使用 LittleEndian 編碼的 uint64裆针,其組成是 7 字節(jié)的 sequence 和 1 字節(jié)的 value_type刨摩。
  4. 所以,一個(gè) LookupKey 的最大長(zhǎng)度為: 5 + userkey size + 8 = userkey size + 13世吨。

SST 文件的查找

LevelDB 中將 SST 文件的管理實(shí)現(xiàn)成 leveldb::Version 澡刹,同時(shí)實(shí)現(xiàn)了 leveldb::VersionSet 管理多個(gè) Version —— 因?yàn)?LevelDB 要支持 MVCC 所以可能同時(shí)存在多個(gè)版本。

查找的時(shí)候耘婚,獲取當(dāng)前版本 current , 調(diào)用 leveldb::Version::Get 在 SST 上進(jìn)行查找罢浇。

  1. 從 level0 開(kāi)始一層一層查找 —— 小 level 的數(shù)據(jù)比大 level 新,所以如果先找到了的話可以直接返回沐祷。
  2. 在要查找的 level 收集需要查找的文件嚷闭。level0 的 sst 文件比較特殊,是直接由 Immutable MemTable dump 得到的赖临,因此胞锰,每個(gè)文件的 key 范圍可能重疊。level0 可能需要查找多個(gè)文件兢榨,其它 level 的 文件的 key 不會(huì)重疊胜蛉,至多只需要讀一個(gè)文件挠进。
  3. 對(duì)步驟 2 收集到的文件進(jìn)行查找。具體查找邏輯由 leveldb::TableCache::Get 實(shí)現(xiàn)誊册。這里面涉及一些 Cache 相關(guān)的實(shí)現(xiàn)领突,暫時(shí)略過(guò)。
  4. 查找過(guò)程會(huì)記錄一些統(tǒng)計(jì)信息:如果不止讀取一個(gè) sst 文件案怯,則記錄最后讀取的是哪個(gè) level 的哪個(gè)文件君旦。

讀觸發(fā)的 Compaction

讀取結(jié)束后,如果不止讀取一個(gè) sst 文件嘲碱,則更新統(tǒng)計(jì)信息金砍,決定是否觸發(fā) Compaction。更新統(tǒng)計(jì)信息時(shí)麦锯,直接將記錄的文件的 leveldb::FileMetaData 的 allowed_seeks 減一恕稠,當(dāng) allowed_seeks <= 0時(shí),表示讀取效率很低扶欣,需要執(zhí)行 Compaction鹅巍,減少這條路徑上的文件數(shù)量。

調(diào)用 MaybeScheduleCompaction 嘗試調(diào)度后臺(tái)線程的 Compaction料祠。

小結(jié)

這里只是簡(jiǎn)單介紹了 LevelDB 的讀操作的大概情況骆捧。實(shí)際上,LevelDB 的讀操作涉及很多東西髓绽,如:寫(xiě)操作相關(guān)的并發(fā)讀寫(xiě)敛苇、Sequence Number 等;Compaction 相關(guān)的 Version顺呕、VersionSet等枫攀;讀操作還有可能觸發(fā) Compaction;還有 Table Cache株茶、Block Cache 這些相關(guān)的東西沒(méi)提及来涨。

參考文檔

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市忌卤,隨后出現(xiàn)的幾起案子扫夜,更是在濱河造成了極大的恐慌楞泼,老刑警劉巖驰徊,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異堕阔,居然都是意外死亡棍厂,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)超陆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)牺弹,“玉大人浦马,你說(shuō)我怎么就攤上這事≌牌” “怎么了晶默?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)航攒。 經(jīng)常有香客問(wèn)我磺陡,道長(zhǎng),這世上最難降的妖魔是什么漠畜? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任币他,我火速辦了婚禮,結(jié)果婚禮上憔狞,老公的妹妹穿的比我還像新娘蝴悉。我一直安慰自己,他們只是感情好瘾敢,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布拍冠。 她就那樣靜靜地躺著,像睡著了一般廉丽。 火紅的嫁衣襯著肌膚如雪倦微。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,441評(píng)論 1 310
  • 那天正压,我揣著相機(jī)與錄音欣福,去河邊找鬼。 笑死焦履,一個(gè)胖子當(dāng)著我的面吹牛拓劝,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播嘉裤,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼郑临,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了屑宠?” 一聲冷哼從身側(cè)響起厢洞,我...
    開(kāi)封第一講書(shū)人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎典奉,沒(méi)想到半個(gè)月后躺翻,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡卫玖,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年公你,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片假瞬。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡陕靠,死狀恐怖迂尝,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情剪芥,我是刑警寧澤堤结,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布旬陡,位于F島的核電站箫荡,受9級(jí)特大地震影響锥忿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜寸认,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一签财、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧偏塞,春花似錦唱蒸、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至古今,卻和暖如春屁魏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背捉腥。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工氓拼, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人抵碟。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓桃漾,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親拟逮。 傳聞我的和親對(duì)象是個(gè)殘疾皇子撬统,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 版本控制或元信息管理,是LevelDB中比較重要的內(nèi)容敦迄。本文首先介紹其在整個(gè)LevelDB中不可替代的作用恋追;之后從...
    CatKang閱讀 5,496評(píng)論 12 12
  • LevelDB是Google傳奇工程師Jeff Dean和Sanjay Ghemawat開(kāi)源的KV存儲(chǔ)引擎,無(wú)論從...
    CatKang閱讀 4,842評(píng)論 5 25
  • 通過(guò)之前對(duì)LevelDB的整體流程罚屋,數(shù)據(jù)存儲(chǔ)以及元信息管理的介紹苦囱,我們已經(jīng)基本完整的了解了LevelDB。接下來(lái)兩...
    CatKang閱讀 3,703評(píng)論 0 5
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理沿后,服務(wù)發(fā)現(xiàn)沿彭,斷路器朽砰,智...
    卡卡羅2017閱讀 134,707評(píng)論 18 139
  • 作為一個(gè)存儲(chǔ)引擎尖滚,數(shù)據(jù)存儲(chǔ)自然是LevelDB重中之重的需求喉刘。我們已經(jīng)在庖丁解LevelDB之概覽中介紹了Leve...
    CatKang閱讀 4,626評(píng)論 2 11