20200213
Plan
60min: RocksDB Write Procedure
Notes
RocksDB Write Procedure
主要完善和具体昨天的流程,并且验证了昨天的猜想,正是通过这样的方式,完成了 wal+memtable 的并发写入,因为这个状态机是知道最后一个 writer 的,而最后一个 writer 负责更新 sequence number。
leader
- JoinBatchWriter: 这个是任何一个 writer 都会被调用的方法,通过调用这个方法,可以知道自己的角色(昨天说过这是个状态机,通过 SetState 控制)。决定自己是 leader 还是 follower 的逻辑是这样的,调用这个方法会向 write_thread_.newest_writer_(是个无锁的链表) 里面插入 writer,如果发现自己是 head,那么就是 leader(STATE_GROUP_LEADER),否则就会 block 住,等待后续的流程走完,既可能是 follower,也可能是 leader。
- EnterAsBatchGroupLeader: 成为 leader 之后,会负责构建整个 WriteGroup,其中重要的逻辑是,从 newest_writers_ 的链表中,取出从 leader 到当前最新的 writer 这么多 writers 放入到 WriteGroup 中去。
- LaunchParallelMemTableWriters: 这时将 WriteGroup 中的所有 writer 设置程 STATE_PARALLEL_MEMTABLE_WRITER。
- leader 自己通过 WriteBatchInternal::InsertInto 完成写入。
- CompleteParallelMemTableWriter: 操作 WaitGroup,将 WaitGroup 里面的 running_ 计数器自减,如果发现自己不是最后一个 completed 的,会 block 住 (AwaitState: STATE_COMPLTED),等待最后一个退出 writer 进行通知 (SetState:STATE_COMPLETED),该调用的返回值表明自己是否为最后一个退出的 writer。
- ExitAsBatchGroupLeader: 这个方法只有在上一步的返回为 true (表明自己为最后一个退出的 writer) 的时候才会被调用,负责作为 leader 和最后完成写入的 writer 退出。无论是 leader 和 follower 都会调用,最重要的工作有两个,一是挑选出下一个 leader(因此 block 在 JoinBatchWriter 中的 writer 是有可能成为 leader 的),至于这个最新的 leader 很自然的会是这个 WaitGroup 中 last_writer_ 的下一个 writer,二是通知所有的 follower 完成(SetState:STATE_COMPLETED)。
follower
- JoinBatchWriter: 正如上面所述,当 block 在这个函数中时,没有被选做下一个 leader 的时候,那么就会成为某一个 leader 的 follower(STATE_PARALLEL_MEMTABLE_WRITER),需要注意此时自己 (writer) 的 WriterGroup 已经被设置好了。
- 调用 WriteBatchInternal::InsertInto 完成自己的写入。
- CompleteParallelMemTableWriter: 这个流程和上述一样。
- ExitAsBatchGroupFollower: 根据上一步的返回值,如果为 true (表明自己为最后一个退出的 writer) 才会调用。会做两件事情,调用ExitAsBatchGroupLeader (挑选下一个 leader,通知所有的 follower 完成), 通知 leader 完成。
明天的计划
目前还有这几点比较感兴趣:
- 控制 sequence number 的细节。
- 在 await state 里面做的优化细节(感觉仅仅为了省一点点的时间,做了非常多的东西,非常值得研究学习)。
- 如何在代码中做高效的统计(目前看到是 thread local 的变量来做统计的)。
- pipeline write procedure 是怎么样的?有什么作用?
- two queue 又是什么?有什么作用?
More
#include <iostream>
using namespace std;
class S {
public: int id;
S():id(0){}
};
int main() {
auto s = S();
s.id = 10;
new (&s) S;
std::cout << s.id;
return 0;
}
// output: 0