rocksdb engine 寫邏輯

# rocksdb engine 寫邏輯

## 執(zhí)行路徑

DB::Put(key, value)是一個寫操作簡單封裝, 最終都會打包一個WriteBatch對象锻离,調(diào)用rocksdb::DBImpl::WriteImpl來完成寫网严。

也可以手工構(gòu)造一個WriteBatch晚岭,作為一個批量事務(wù)操作州袒,放入多個key/value操作看尼,一次提交递鹉。

```cpp

#0? rocksdb::MemTable::Add (this=0x1619800, s=1, type=rocksdb::kTypeValue, key=..., value=..., allow_concurrent=false, post_process_info=0x0) at db/memtable.cc:425

#1? 0x00000000005c25c2 in rocksdb::MemTableInserter::PutCF (this=0x7fffffffa8b0, column_family_id=0, key=..., value=...) at db/write_batch.cc:869

#2? 0x00000000005bdfe7 in rocksdb::WriteBatch::Iterate (this=0x7fffffffb0c0, handler=0x7fffffffa8b0) at db/write_batch.cc:381

#3? 0x00000000005bfa41 in rocksdb::WriteBatchInternal::InsertInto (writers=..., sequence=1, memtables=0x1616100, flush_scheduler=0x1608808, ignore_missing_column_families=false, log_number=0, db=0x1608000,

concurrent_memtable_writes=false) at db/write_batch.cc:1206

#4? 0x00000000004c85ae in rocksdb::DBImpl::WriteImpl (this=0x1608000, write_options=..., my_batch=0x7fffffffb0c0, callback=0x0, log_used=0x0, log_ref=0, disable_memtable=false) at db/db_impl.cc:4953

#5? 0x00000000004c6b72 in rocksdb::DBImpl::Write (this=0x1608000, write_options=..., my_batch=0x7fffffffb0c0) at db/db_impl.cc:4585

#6? 0x00000000004ccd99 in rocksdb::DB::Put (this=0x1608000, opt=..., column_family=0x15d6500, key=..., value=...) at db/db_impl.cc:5803

#7? 0x00000000004c69f0 in rocksdb::DBImpl::Put (this=0x1608000, o=..., column_family=0x15d6500, key=..., val=...) at db/db_impl.cc:4560

```

## WriteBatch

一個WriteBatch就是一個事務(wù),里面會有很多條操作記錄藏斩,可以調(diào)用WriteBatch.Put/Delete...等操作加入操作(Key/Value)

WriteBatch.rep_ 是一個binary buffer, 用于存儲batch中所有操作的記錄躏结,格式如下:

WriteBatch.content\_flags_ 標(biāo)記batch中含有的操作類型集合。

field | length? | description |

---------:| :----- |:-----

kHeader | FixInt64 | 序列號狰域,單調(diào)遞增媳拴, Batch sequence的起始值

Count | FixInt32 | 操作記錄個數(shù)

Type | FixInt8 + Var32Int | 操作類型 + column_family(if != 0)

Key | Var32String | key binary buffer

Value | Var32String | value binary buffer

Type/Key/Value每個記錄重復(fù)一條, kHeader/Count batch對象共用

## rocksdb::DBImpl::WriteImpl

- 新建一個WriteThread::Writer對象北专,關(guān)聯(lián)到傳入的batch object.

- 調(diào)用write\_thread_.JoinBatchGroup(&w);

### Group Commit

為了提高commit性能禀挫,存儲引擎會將很多線程的并發(fā)write合并到一個group,批量寫日志拓颓,write memory table,然后一次性commit.

JoinBatchGroup調(diào)用LinkOne(w, &linked_as_leader);將當(dāng)前write\_thread_中的writer連接成一個鏈表语婴,其中write\_thread_.newest\_writer_是鏈表的頭,是最新加入的follower驶睦,而第一個加入鏈表的也就是當(dāng)前group的leader(link_older=nullptr).

follower(newest_writer) --*link_older*--> follower --*link_older*--> follower --*link_older*--> **leader** ----> nullptr

如果當(dāng)前的Writer成為了Leader砰左,那么返回做剩下的提交邏輯,如果當(dāng)前已經(jīng)有了Leader场航,需要等待Write.state成為STATE_GROUP_LEADER | STATE_PARALLEL_FOLLOWER | STATE_COMPLETED

- As Leader

- 檢查是否需要Flush, 如果需要缠导,找出所有column_family中最大的MemTable的CF,調(diào)用SwitchMemtable,凍結(jié)當(dāng)前active memtable, 調(diào)用SchedulePendingFlush調(diào)度刷盤溉痢。

- 取當(dāng)前的versions_的LastSequence僻造。 開始持有DBImpl::mutex

- 調(diào)用write\_thread_.EnterAsBatchGroupLeader,這個函數(shù)確定當(dāng)前提交的批次應(yīng)該包含哪些數(shù)據(jù)

- 計算當(dāng)前可以批量提交的最大長度max_size; 如果leader.size<128KB max_size=leader.size+128KB孩饼,如果>128KB髓削,max_size=1MB.

- 調(diào)用CreateMissingNewerLinks(newest_writer),將整個鏈表的反向鏈接建立起來(link_newer)镀娶,成了一個雙向鏈表立膛。

- 從leader開始反向遍歷,一直到newest_writer,? 累加每個batch的size梯码,一直到max_size宝泵,超過之后截斷,同時檢查每個writer的sync/no_slowdown/disableWAL是否一致轩娶,不一致的地方也開始截斷儿奶,用last_writer標(biāo)記鏈表的結(jié)束位置,作為函數(shù)輸出參數(shù)返回鳄抒。w->callback->AllowWriteBatching()闯捎,也可以設(shè)置不想被batch的writer. 并且把符合條件的writer batch都push到write_group的vector中搅窿。

- 檢查是否可以parallel提交,條件有幾個:1. memtable支持隙券,2.allow_concurrent_memtable_write設(shè)置男应,3.write_group 有多個batch, 4. batch中沒有merge操作。

- 確定當(dāng)前提交的group的current_sequence=last_sequence+1(作為起始sequence), 并且將sequence先進行占位娱仔,一次性**為write_group中每個batch的每個操作記錄都分配一個sequence**. (注意writer.ShouldWriteToMemtable標(biāo)記為false的不計入sequence)

- 將write_group中的每個batch的數(shù)據(jù)都append到一個新的WriteBatch對象merged_batch中(tmp\_batch_)沐飘,如果group中只有一個batch, 那么就用這個batch,沒必要拷貝數(shù)據(jù)了。

- 設(shè)置新的merged_batch對象的sequence為current_sequence(起始sequence)

- 寫WAL牲迫,用的數(shù)據(jù)就是merged\_batch中的rep_ (如果是多個batch耐朴,那么tmp\_batch_可以清理了)

- 如果不允許并發(fā):串行執(zhí)行write memtable,調(diào)用WriteBatchInternal::InsertInto將write_group中所有數(shù)據(jù)串行寫入到memtable.

- 并行執(zhí)行(concurrent_memtable_writes)

- WriteThread::ParallelGroup 建立一個并行寫memtable group,pg.leader/last_writer分別指向鏈表的頭和尾盹憎。

- write\_thread_.LaunchParallelFollowers: 設(shè)置鏈表中每個writer.sequence為之前分配好的sequence筛峭,(注意每個batch分配自己的一段,調(diào)用InsertInto的時候再每個Key設(shè)置自己的sequence)陪每,設(shè)置writer.state為STATE_PARALLEL_FOLLOWER

- 作為Leader的writer batch開始寫memtable

- 調(diào)用write\_thread_.CompleteParallelWorker(&w)判斷是不是最后一個完成write memtable的線程

- 正常情況下(如果early_exit_allowed為false)影晓,只有l(wèi)eader會最后做收尾工作,因此即便leader不是最后一個寫完memtable的線程檩禾,也會等待writer.state == STATE\_COMPLETED 才會退出, 并返回true,表示需要做最后的提交工作(update versions_.LastSequence)挂签,leader的STATE_COMPLETEDe是由最后一個退出的follower線程設(shè)置的。

- follower線程如果不是最后一個完成工作的線程盼产,那么會一直等到writer.state == STATE_COMPLETED退出饵婆。

- follower線程如果是最后一個完成工作的線程,那么會先把group.leader.state設(shè)置為STATE_COMPLETED戏售,然后等待自己變成STATE_COMPLETED侨核,退出。

- 如果 CompleteParallelWorker返回了true(leader等到了STATE\_COMPLETED或者自己就是最后一個)灌灾,做提交動作更新全局的sequence: versions_->SetLastSequence(last_sequence);

- 調(diào)用write\_thread_.ExitAsBatchGroupLeader

- 注意當(dāng)前的newest\_writer_可能已經(jīng)加了很多新的write batch進來了搓译,在上一次commit的過程中,新進來的write batch還會一直往write\_thread_的鏈表上掛紧卒,但是本次提交的截止的點在EnterAsBatchGroupLeader時候確定的侥衬,因此退出的時候會將本次提交鏈還剩余的writer鏈诗祸,重新建立好反向鏈接跑芳,設(shè)置緊接著的writer為新的Leader,之前調(diào)用JoinBatchGroup等待的線程直颅,又可以繼續(xù)執(zhí)行下一批事務(wù)博个。

- 遍歷write_group中所有的writer, 設(shè)置所有writer的state為STATE_COMPLETED,這樣還在調(diào)用CompleteParallelWorker的follower線程就會退出功偿。

- As follower

- JoinBatchGroup之后如果沒有成為Leader盆佣,那就等著Leader線程在LaunchParallelFollowers的時候把自己設(shè)置為follower狀態(tài)往堡,一旦設(shè)置完,就進入follower寫memtable邏輯共耍,最后判斷CompleteParallelWorker是否可以退出虑灰,一般是等待所有的batch都干完活以后退出。

- 如果allow_concurrent_memtable_write沒有打開, follower線程會一直等待Leader干完所有的事情痹兜,最后調(diào)用ExitAsBatchGroupLeader設(shè)置狀態(tài)為STATE_COMPLETED后直接退出穆咐。

### writer鏈表在group commit過程中的變化

![link_list](rocksdb_writer_link_list.png)

### writer對象狀態(tài)變遷圖

![state_flow](rocksdb_writer_state_flow.png)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市字旭,隨后出現(xiàn)的幾起案子对湃,更是在濱河造成了極大的恐慌,老刑警劉巖遗淳,帶你破解...
    沈念sama閱讀 211,817評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拍柒,死亡現(xiàn)場離奇詭異,居然都是意外死亡屈暗,警方通過查閱死者的電腦和手機拆讯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來养叛,“玉大人往果,你說我怎么就攤上這事∫磺Γ” “怎么了陕贮?”我有些...
    開封第一講書人閱讀 157,354評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長潘飘。 經(jīng)常有香客問我肮之,道長,這世上最難降的妖魔是什么卜录? 我笑而不...
    開封第一講書人閱讀 56,498評論 1 284
  • 正文 為了忘掉前任戈擒,我火速辦了婚禮,結(jié)果婚禮上艰毒,老公的妹妹穿的比我還像新娘筐高。我一直安慰自己,他們只是感情好丑瞧,可當(dāng)我...
    茶點故事閱讀 65,600評論 6 386
  • 文/花漫 我一把揭開白布柑土。 她就那樣靜靜地躺著,像睡著了一般绊汹。 火紅的嫁衣襯著肌膚如雪稽屏。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,829評論 1 290
  • 那天西乖,我揣著相機與錄音狐榔,去河邊找鬼坛增。 笑死,一個胖子當(dāng)著我的面吹牛薄腻,可吹牛的內(nèi)容都是我干的收捣。 我是一名探鬼主播,決...
    沈念sama閱讀 38,979評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼庵楷,長吁一口氣:“原來是場噩夢啊……” “哼坏晦!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起嫁乘,我...
    開封第一講書人閱讀 37,722評論 0 266
  • 序言:老撾萬榮一對情侶失蹤昆婿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蜓斧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體仓蛆,經(jīng)...
    沈念sama閱讀 44,189評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,519評論 2 327
  • 正文 我和宋清朗相戀三年挎春,在試婚紗的時候發(fā)現(xiàn)自己被綠了看疙。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,654評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡直奋,死狀恐怖能庆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情脚线,我是刑警寧澤搁胆,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站邮绿,受9級特大地震影響渠旁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜船逮,卻給世界環(huán)境...
    茶點故事閱讀 39,940評論 3 313
  • 文/蒙蒙 一顾腊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧挖胃,春花似錦杂靶、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至凛辣,卻和暖如春抱既,著一層夾襖步出監(jiān)牢的瞬間职烧,已是汗流浹背扁誓。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評論 1 266
  • 我被黑心中介騙來泰國打工防泵, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蝗敢。 一個月前我還...
    沈念sama閱讀 46,382評論 2 360
  • 正文 我出身青樓捷泞,卻偏偏與公主長得像,于是被迫代替她去往敵國和親寿谴。 傳聞我的和親對象是個殘疾皇子锁右,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,543評論 2 349

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