Lab 2D
lab 2D 是实现日志压缩的
assignment指示完成三个函数:Snapshot、CondInstallSnapshot和InstallSnapshot RPC
Snapshot
Snapshot函数是 上层与 raft来交互的,上层调用Snapshot函数来让leader进行snapshot。
这个函数有几个比较重要的rules :
如果 index <= lastSnapshotIndex ,那说明这个snotshop请求是过期的,可能由于各种网络原因之类的引起,这时候就要拒绝这个请求
要进行snapshot丢弃的日志,首先应该已经被 commit 且 apply了
需要持久化快照信息
CondInstallSnapshot
CondInstallSnapshot这个函数可以设计为永远只返回true
在向applyCh写入一条消息后,会调用CondInstallSnapshot()接口是用来判断是否可以实施快照的,比如判断一下快照的index是否小于节点的commitIndex。
如 config.go/applierSnap():
接收到一条 applyCh {
if cfg.rafts[i].CondInstallSnapshot(m.SnapshotTerm,
m.SnapshotIndex, m.Snapshot) {
cfg.logs[i] = make(map[int]interface{})
r := bytes.NewBuffer(m.Snapshot)
d := labgob.NewDecoder(r)
var v int
if d.Decode(&v) != nil {
log.Fatalf("decode error\n")
}
cfg.logs[i][m.SnapshotIndex] = v
lastApplied = m.SnapshotIndex
}
}因为在 lab2B 实现中,往 applych发送log entry时是不持有锁的
因为教授说过,在发送 applych的时候不能持有锁。
上层实现时是在接收到一定的log entry 时进行snapshot,在snapshot返回时service不会进行任何操作,如果此时锁还在发送 log entry 的channel那里,进行 snapshot又需要获取锁,所以会造成死锁。
因此lab assignment选择让 log entry 和 snapshot 并发执行,这样子你就不能确定service什么时候能接收到snapshot了。
我们必须引入CondInstallSnapshot函数,确定service接收到snapshot的时间。
InstallSnapshot
InstallSnapshot 也有几个重要的规则:
如果 leader term 小于自己的term,就立刻拒绝
snapshot也相当于一次心跳,需要重置选举时间等心跳操作
如果发送过来的快照落后于当前已经应用的快照,那就直接拒绝
follower应用成功后需要更新 commitIndex 和 lastapplied
如果leader 发送snapshot成功,需要更新 发送给那个 server的对应的matchIndex和nextIndex
Last updated