1. 将解析后的记录(kTypeValue/kTypeDeletion)写入到WriteBatch中
  2. 将WAL日志写入log文件
  3. 将WriteBatch中的内容写到memtable中,事务完成

其中第2,3步在提交时完成

一个简单的insert 写入WriteBatch堆栈如下

一个简单的insert commit堆栈如下

  1. #1 rocksdb::(anonymous namespace)::SkipListRep::Insert
  2. #2 rocksdb::MemTable::Add
  3. #3 rocksdb::MemTableInserter::PutCF
  4. #4 rocksdb::WriteBatch::Iterate
  5. #5 rocksdb::WriteBatch::Iterate
  6. #6 rocksdb::WriteBatchInternal::InsertInto
  7. #8 rocksdb::DBImpl::Write
  8. #9 rocksdb::TransactionImpl::Commit
  9. #11 myrocks::Rdb_transaction::commit
  10. #12 myrocks::rocksdb_commit
  11. #13 ha_commit_low
  12. #15 ha_commit_trans
  13. #16 trans_commit_stmt
  14. #17 mysql_execute_command
  15. #18 mysql_parse
  16. #19 dispatch_command
  17. #20 do_command

这里只分析rocksdb引擎的提交流程,实际MyRocks提交时还需先写binlog(binlog开启的情况).

rocksdb引擎提交时就完成两个事情

  1. 写WAL日志(WAL开启的情况下rocksdb_write_disable_wal=off)
  2. 将之前的WriteBatch写入到memtable中

待提交的事务都依次加入到提交的writer队列中,这个writer队列被划分为一个一个group. 每个group有一个leader, 其他为follower,leader负责批量写WAL。每个group由双向链表link_older, link_newer链接。如下图所示

每个writer可能的状态如下

  • Init: writer的初始状态
  • Header: writer被选为leader
  • Follower: writer被选为follower
  • Completed:writer操作完成

writer的状态变迁跟group是否并发写memtable有关 当开启并发写memtable(rocksdb_allow_concurrent_memtable_write=on)且group中的writer至少有两个时,group才会并发写。

group并发写时writer的状态变迁图如下:

屏幕快照 2017-07-14 下午1.25.27.png

源码结构图如下(图片来自林青) 屏幕快照 2017-07-14 下午1.44.46.png

上面的图是在group内writer并发写memtable的情形。 非并发写memtable时,没有LaunchParallelFollowers/CompleteParallelWorker, Insertmemtable是由leader串行写入的。 这里group commit有以下要点

  1. 同一时刻只有一个leader, leader完成操作后,才设置下一个leader
  2. 需要等一个group都完成后,才会进行下一个group
  3. group中最后一个完成的writer负责完成提交和设置下一个leader
  4. Leader 负责批量写WAL
  5. 只有leader才会去调整双向链表link_older,link_newer.

注意这里2,3 应该可以优化改进为

  • 不需要等一个group完成再进行下一个group
  • 不同group的follower可以并发执行
  • 只有leader负责完成提交和设置下一个leader

rocksdb在提交写入时,需考虑以下几种情况,详见PreprocessWrite

  • WAL日志满,WAL日志超过rocksdb_max_total_wal_size,会从所有的colomn family中找出含有最老日志(the earliest log containing a prepared section)的column family进行flush, 以释放WAL日志空间
  • Buffer满,全局的write buffer超过rocksdb_db_write_buffer_size时,会从所有的colomn family中找出最先创建的memtable进行切换,详见HandleWriteBufferFull
  • 某些条件会触发延迟写
    • max_write_buffer_number > 3且 未刷immutable memtable总数 >=max_write_buffer_number-1
    • 自动compact开启时,level0的文件总数 >= level0_slowdown_writes_trigger
  • 某些条件会触发停写
    • 未刷immutable memtable总数 >=max_write_buffer_number

具体可参考RecalculateWriteStallConditions