raftLog
管理节点上的日志(数据)
type raftLog struct {
// memoryStorage实例
storage Storage
// unstable 实例
unstable unstable
// 已提交的位置
committed uint64
// 已应用的位置
applied uint64
logger Logger
// maxNextEntsSize是从对nextEnts的调用返回的消息的最大总数字节大小
maxNextEntsSize uint64
}
newLogWithSize
刚刚创建的时候unstable里的snapshot和ents为空
func newLogWithSize(storage Storage, logger Logger, maxNextEntsSize uint64) *raftLog {
if storage == nil {
log.Panic("storage must not be nil")
}
log := &raftLog{
storage: storage,
logger: logger,
maxNextEntsSize: maxNextEntsSize,
}
firstIndex, err := storage.FirstIndex()
if err != nil {
panic(err) // TODO(bdarnell)
}
lastIndex, err := storage.LastIndex()
if err != nil {
panic(err) // TODO(bdarnell)
}
log.unstable.offset = lastIndex + 1
log.unstable.logger = logger
// Initialize our committed and applied pointers to the time of the last compaction.
log.committed = firstIndex - 1
log.applied = firstIndex - 1
return log
}
maybeAppend
追加entry记录
//
func (l *raftLog) maybeAppend(index, logTerm, committed uint64, ents ...pb.Entry) (lastnewi uint64, ok bool) {
//判断是否过期数据和非法index
if l.matchTerm(index, logTerm) {
lastnewi = index + uint64(len(ents))
//遍历entry 判断是否与raftLog中已有的entry发生冲突
ci := l.findConflict(ents)
switch {
case ci == 0:
//包含全部待追加的记录
case ci <= l.committed:
//有冲突的位置是已提交的
//那就凉了
l.logger.Panicf("entry %d conflict with committed entry [committed(%d)]", ci, l.committed)
default:
//有冲突的位置是未提交的
//追加
offset := index + 1
l.append(ents[ci-offset:]...)
}
l.commitTo(min(committed, lastnewi))
return lastnewi, true
}
return 0, false
}
//查看是否有冲突找到没有开始的下标
func (l *raftLog) findConflict(ents []pb.Entry) uint64 {
for _, ne := range ents {
if !l.matchTerm(ne.Index, ne.Term) {
if ne.Index <= l.lastIndex() {
l.logger.Infof("found conflict at index %d [existing term: %d, conflicting term: %d]",
ne.Index, l.zeroTermOnErrCompacted(l.term(ne.Index)), ne.Term)
}
return ne.Index
}
}
return 0
}
entries
获取指定的entries记录
func (l *raftLog) entries(i, maxsize uint64) ([]pb.Entry, error) {
if i > l.lastIndex() {
return nil, nil
}
return l.slice(i, l.lastIndex()+1, maxsize)
}
// slice returns a slice of log entries from lo through hi-1, inclusive.
func (l *raftLog) slice(lo, hi, maxSize uint64) ([]pb.Entry, error) {
err := l.mustCheckOutOfBounds(lo, hi)
if err != nil {
return nil, err
}
if lo == hi {
return nil, nil
}
var ents []pb.Entry
//先用storage.Entries 获取 lo-l.unstable.offset
if lo < l.unstable.offset {
storedEnts, err := l.storage.Entries(lo, min(hi, l.unstable.offset), maxSize)
if err == ErrCompacted {
return nil, err
} else if err == ErrUnavailable {
l.logger.Panicf("entries[%d:%d) is unavailable from storage", lo, min(hi, l.unstable.offset))
} else if err != nil {
panic(err) // TODO(bdarnell)
}
// 若达到上限就返回
// check if ents has reached the size limitation
if uint64(len(storedEnts)) < min(hi, l.unstable.offset)-lo {
return storedEnts, nil
}
ents = storedEnts
}
//没达到上限在unstable里拿
if hi > l.unstable.offset {
unstable := l.unstable.slice(max(lo, l.unstable.offset), hi)
if len(ents) > 0 {
combined := make([]pb.Entry, len(ents)+len(unstable))
n := copy(combined, ents)
copy(combined[n:], unstable)
ents = combined
} else {
ents = unstable
}
}
//字节总数截断
return limitSize(ents, maxSize), nil
}