etcd中的環形隊列inflights

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
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章