比较啰嗦:(
RaftLogGC过程 和 快照生成没有关系。也就是说整个RaftLogGC这一过程没有快照生成的步骤。快照生成是在Raft层驱动的,也可以看成是RaftLogGC过程的结果触发了快照。先说一下两个过程的大概步骤。
RaftLogGC的过程:
(1)在 raft_worker.go 中的 HandleMsg 负责处理 raftCh 中收到的消息,这里假设是message.MsgTypeTick消息。因此触发 onTick 函数、onRaftGCLogTick函数。
(2)从 onRaftGCLogTick 函数开始,当发现已经 applied 的日志超过 RaftLogGcCountLimit,就会发送一个 CompactLogRequest 的 AdminRequest。
(3)这个消息通过 proposeRaftCommand 到了 rawnode.go 中的 Propose 函数,进入了raft模块,封装成日志,等待复制,提交等。
(4)在 raft_worker.go 中的 HandleRaftReady,负责将raft层中的更改通过 Ready 来通知上层。因此,这里需要apply包含 AdminCmdType_CompactLog 的日志项。
(5)这个时候需要更新applyState的信息,并且调用 ScheduleCompactLog 生成一个gc Task。
(6)worker.go 中的 Start 函数通过 receiver 接收任务,在 raftlog_gc.go 中的 Handle 函数中处理,删除 badger 中的一些元信息。
(7)最后是通过 rownode.go 中的 Advance 更新raft中的apply等变量。
snapshot的发送流程:
(1)raft.go 中的 sendAppend 函数中,调用 raftLog.storage.Snapshot() 函数,新建一个 RegionTaskGen 的任务,异步产生快照,并且将 snapState 的状态改为 Generating 表示正在产生快照。另外,这次调用应该返回一个快照暂时不能获得的Error。
(2) region_task.go 中的 handleGen 函数负责产生快照,调用 doSnapshot 产生快照。
(3)当下次调用 Snapshot() 的时候,如果快照已经产生了,则接收并验证快照,返回结果。
(4)那么 raft.go 中 snapshotMsg 被存储在了 msgs 中。等待通过 Ready 处理。
(5) HandleRaftReady 中通过调用 send 通过 transport 将消息封装成 RaftMessage 发送到对应的store。
(6)通过 transport.go 中 ServerTransport 的 send 函数发送。在 SendStore 中调用 Resolve ,产生一个 resolveAddrTask 任务,通过 Handle 中 getAddr 获得StoreId的地址,并通过 callback 更新 raftClient 的 addrs 。
(7)在 WriteData 函数中,由于是发送快照的消息,所以通过 SendSnapshotSock 函数建立一个 sendSnapTask 任务。
(8)在 snap_runner.go 中,通过 sendSnap 发送快照。。。。。。。
见(7)通过调用 Advance 将结果写回到raft层中。
发送快照是因为Leader当中已经没有了需要发送给Follower的日志项(通过Leader存储的每个Follower的NextIndex来判断)。这其实是在SendAppendMsg中,需要改一下发送流程,如果没有这个日志项(Leader.firstIndex>Prs[follower].nextIndex 大概是这个意思)就需要发送快照了,调用storage.snapshot()方法生成。。。。。。
生成snapshot见上面一个问题。
ScheduleCompactLog 里面真的就只是一个截断而已.
(1)raft中调用 peer_storage.go 中的 snapshot 函数(假设)。生成一个RegionTaskGen的快照任务。
(2)region_task.go 中的 Handle 函数通过调用 handleGen 产生快照。
。。。。(可以自己看看怎么生成的,有时间继续写。。。)
(3)在下一次 Raft 调用 Snapshot时,会检查快照生成是否完成。如果是,Raft应该将快照信息发送给其他 peer,而快照的发送和接收工作则由 snap_runner.go 处理(异步)。