比较啰嗦:(
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 处理(异步)。