inflights结构体在progress.go文件中,主要用于记录当前节点已发出未收到的响应的MsgApp消息,具体实现如下
type inflights struct {
// the starting index in the buffer
start int //记录第一条MsgApp消息的下标
// number of inflights in the buffer
count int //记录MsgApp消息的个数
// the size of the buffer
size int //当前inflights实例中记录的MsgApp消息个数的上限(最大长度)。
// buffer contains the index of the last entry
// inside one message.
buffer []uint64 //用来记录MsgApp消息相关信息的数组,其中记录的是MsgApp消息中最后一条Entry记录的索引值,被当成环形数组使用
}
func newInflights(size int) *inflights {
return &inflights{
size: size,
}
}
// add adds an inflight into inflights
//用来记录发送出去的MsgApp消息(一个一个的递增)
func (in *inflights) add(inflight uint64) {
if in.full() { //检测当前buffer数组是否已经被填充满了
panic("cannot add into a full inflights")
}
next := in.start + in.count //获取新增消息的下标
size := in.size
if next >= size { //环形队列
next -= size
}
if next >= len(in.buffer) { //初始化的buffer数组较短,随着使用会不断进行扩容(2倍),其扩容的上限为size
in.growBuf()
}
in.buffer[next] = inflight //在next位置记录消息中最后一条Entry记录的索引值
in.count++ //递增count字段
}
// grow the inflight buffer by doubling up to inflights.size. We grow on demand
// instead of preallocating to inflights.size to handle systems which have
// thousands of Raft groups per process.
func (in *inflights) growBuf() {
newSize := len(in.buffer) * 2
if newSize == 0 {
newSize = 1
} else if newSize > in.size {
newSize = in.size
}
newBuffer := make([]uint64, newSize)
copy(newBuffer, in.buffer)
in.buffer = newBuffer
}
// freeTo frees the inflights smaller or equal to the given `to` flight.
//将指定消息及其之前的消息全部清空,释放inflights空间,让后面的消息继续发送。
func (in *inflights) freeTo(to uint64) {
if in.count == 0 || to < in.buffer[in.start] { //边界检测
// out of the left side of the window
return
}
idx := in.start
var i int
for i = 0; i < in.count; i++ {
if to < in.buffer[idx] { // found the first large inflight
break
}
// increase index and maybe rotate
size := in.size
if idx++; idx >= size {
idx -= size
}
}
// free i inflights and set new start index
in.count -= i
in.start = idx
if in.count == 0 {
// inflights is empty, reset the start index so that we don't grow the
// buffer unnecessarily.
in.start = 0
}
}
func (in *inflights) freeFirstOne() { in.freeTo(in.buffer[in.start]) }
// full returns true if the inflights is full.
func (in *inflights) full() bool {
return in.count == in.size
}
// resets frees all inflights.
func (in *inflights) reset() {
in.count = 0
in.start = 0
}