tinyKV project2ab 部分raftlog疑问

我看到test中使用了commitNoopEntry(r, s)函数,
有一句 s.Append(r.RaftLog.unstableEntries())
此时这个noop 包被append到storage里,
同时log.entries里仍存在这个包,我该在entries里删掉它吗,
还是说保留并且修改raftlog.Lastindex函数重新计算这个值

1赞

应该不用吧,append 之后已经更新 raft log 的 stabled 字段了。不会重复存储这条数据。

1赞

我的理解是不需要删除entries中的东西,首先是paper里有提到Leader是Append-Only的,它在启动时也是把storage中的entries都写入log中,我认为是直接更改index就好

1赞

下面是etcd 的部分代码
从代码中的最后几行能看到,log 被 append 到了 r.Raftlog.storage 中,但 r.raftlog.entris 仍保留了 log

raftlog.entries 中的则在 stableto 函数中完成删除.

func commitNoopEntry(r *raft, s *MemoryStorage) {
	if r.state != StateLeader {
		panic("it should only be used when it is the leader")
	}
	r.bcastAppend()
	// simulate the response of MsgApp
	msgs := r.readMessages()
	for _, m := range msgs {
		if m.Type != pb.MsgApp || len(m.Entries) != 1 || m.Entries[0].Data != nil {
			panic("not a message to append noop entry")
		}
		r.Step(acceptAndReply(m))
	}
	// ignore further messages to refresh followers' commit index
	r.readMessages()
	s.Append(r.raftLog.unstableEntries())
	r.raftLog.appliedTo(r.raftLog.committed)
	r.raftLog.stableTo(r.raftLog.lastIndex(), r.raftLog.lastTerm())
}
func (l *raftLog) stableTo(i, t uint64) { l.unstable.stableTo(i, t) }

func (u *unstable) stableTo(i, t uint64) {
	gt, ok := u.maybeTerm(i)
	if !ok {
		return
	}
	// if i < offset, term is matched with the snapshot
	// only update the unstable entries if term is matched with
	// an unstable entry.
	if gt == t && i >= u.offset {
		u.entries = u.entries[i+1-u.offset:]
		u.offset = i + 1
		u.shrinkEntriesArray()
	}
}

但 tinykv 似乎并未提供类似接口

3赞

不用删除的,append到storage的日志知识进行了持久化,目的是如果节点crash了可以保存之前的状态,和RaftLog本身需要继续持有日志进行Raft的继续是不矛盾的。

这部分日志无论是否删除,对节点的同步都不会照成影响,etcd删除应该是出于节省内存之类的考虑?

主要是stable了的log未必是正确的日志,比如一种情况:出现网络分区以后,旧Leader被分到了少数区域,他会不断得到日志,然后他的日志也会被stable。但是这些日志都不会被commit以及apply。 多数分区的新Leader的日志才是正确的日志,网络分区结束以后,老Leader需要落选,并且他的日志需要全部被drop掉,包括stable的日志

十分感谢你的回复,你的回复对我的帮助很大.

1赞