etcd结构体之Inflights
1. Inflights?
官方:
Inflights limits the number of MsgApp (represented by the largest index
contained within) sent to followers but not yet acknowledged by them. Callers
use Full() to check whether more messages can be sent, call Add() whenever
they are sending a new append, and release "quota" via FreeLE() whenever an
ack is received.
翻译:
Inflights用来记录leader节点已发送至follower节点但是还未收到确认的MsgApp消息的索引值。
1. 1 数据结构的定义
type Inflights struct {
// 循环数组开始
start int
// 数组内的值
count int
// buffer容量
size int
// buffer contains the index of the last entry
// inside one message.
buffer []uint64
}
其实Inflights的结构非常简单,就是一个简单的循环数组,start值用来记录循环数组的开始,即最旧的那个未被响应的消息。count用来记录当前数组有几个值,也就是已经发送但未响应的消息总数。buffer用来存储。
2. Inflight Methods
2.1 NewInflights()和Clone()
// 创建Inflights,只初始化了size,并没有初始化buffer,在使用时初始化buffer,并进行动态调整
// 主要是为了避免资源浪费
func NewInflights(size int) *Inflights {
return &Inflights{
size: size,
}
}
// Clone returns an *Inflights that is identical to but shares no memory with
// the receiver. 克隆的Inflight返回的和入参完全一样但是并不共享内存
func (in *Inflights) Clone() *Inflights {
ins := *in
ins.buffer = append([]uint64(nil), in.buffer...)
return &ins
}
2.2 Add()
func (in *Inflights) Add(inflight uint64) {
// 判断inflight是否已满, (size == count)
if in.Full() {
panic("cannot add into a Full inflights")
}
next := in.start + in.count
size := in.size
// 环,
if next >= size {
next -= size
}
// 如果当前next值大于buffer容量,扩容动态调整buffer大小
if next >= len(in.buffer) {
in.grow()
}
in.buffer[next] = inflight
in.count++
}
// 扩容
func (in *Inflights) grow() {
// 每次增大两倍
newSize := len(in.buffer) * 2
if newSize == 0 {
// 第一次初始化的时候
newSize = 1
} else if newSize > in.size {
newSize = in.size
}
newBuffer := make([]uint64, newSize)
// copy函数的newbuffer必须进行初始化容量大小
copy(newBuffer, in.buffer)
in.buffer = newBuffer
}
// 把小于等于 to 的元素释放掉
func (in *Inflights) FreeLE(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++ {
// 找到第一个大于 to 的值,把 start - to 之前的元素释放掉
if to < in.buffer[idx] {
break
}
// increase index and maybe rotate
size := in.size
if idx++; idx >= size {
idx -= size
}
}
// 释放掉i个元素,并进行环形数组的重置
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
}
}
3. 思考与想法
Inflights的实现还是很简单的。值得借鉴的是在创建Inflights时,只分配buffer的容量,并不对初始化buffer。buffer只有在使用到时才会进行初始化,避免了资源的浪费。