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
}