Async Write

提交raft proposal

Peer调用raft RawNode::propose方法,将RaftCmdRequest 提交给raft log, 然后将write callback和要写入的log entry的index放入了本地的proposals等待队列。

这个地方和ReadIndex一样,会带上当前时间戳,作为后续renew lease的时间戳

处理raft committed

leader节点在应用propse log entry后,会将该log entry先保存在本地,然后复制到各个follower上,待集群中大部分节点 都保存了该log entry时, log entry达到comitted 状态,TiKV可以安全的把它apply 到kv engine上了。

Peer在handle_raft_committed_entries时,会根据log entry的term和index找到它在proposals队列中 对应的proposal, 然后主要做如下工作

  1. renew leader lease, 使用proposal时候的时间戳来更新leader lease.
  2. 调用该proposal cb的invoke_comitted
  3. 将comitted entries和它们的cbs 打包发给apply fsm处理。

Apply to KvEngine

comitted entries, 连同它对应的Proposals, 被路由到ApplyFsm后,由ApplyFsm 负责执行comitted entries中的RaftCmdRequest 保存完毕后,调用回调cb.invoke_with_response,通知write 已经apply 到kv engine了.

这些Proposals首先会被放到ApplyDelegate::pending_cmds队列中, 等raft cmd被执行完毕后, 从ApplyDelegate::pending_cmds队列中,找到对应的Proposal, 然后将它的callback 放入 ApplyContext::cbs中。

最后再ApplyContext::flush时, 回调ApplyContext::cbs中的callback, 然后将ApplyRes 发 给PeerFsm.

RaftApplyState

处理完一个comitted entry后,会更新applied_index_termapplied_index 这两项会放到ApplyRes,后面通知PeerFsm, PeerFsm会更新PeerStorage中的 apply_stateapplied_index_term.

在生成snaptask时,也会用到这两项。

exec raft cmd

write有四种命令,Put, Delete, DeleteRange, IngestSst, 其中put/delete是写到write batch上的。

ApplyResult::yield

每次ApplyPoller::handle_normal时,会在ApplyDelegate::handle_start中记录开始的时间, 然后在ApplyDelegate::handle_raft_entry_normal, 每次处理一个raft log entries, 如果需要write batch需要写入kv engine的话,就调用ApplyContext::commit,将write batch 提交,然后计算已经消耗的时间。如果时间超过ApplyContext::yield_duration, 就返回ApplyResult::yield.

ApplyDelegate::handle_raft_committed_entries中,会将剩余的committed entries 保存到 ApplyDelegate::yield_state中。

等下次重新开始handle_normal时,先调用resume_pending, 先处理ApplyDelegate::yield_state中的log entries.