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, 然后主要做如下工作
- renew leader lease, 使用proposal时候的时间戳来更新leader lease.
- 调用该proposal cb的
invoke_comitted
。 - 将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_term
和applied_index
这两项会放到ApplyRes,后面通知PeerFsm, PeerFsm会更新PeerStorage中的
apply_state
和applied_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.