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