欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[etcd]raftpd confstate.go

程序员文章站 2024-03-19 21:31:46
...

_________________看前须知__________________

message ConfState {
	// The voters in the incoming config. (If the configuration is not joint,
	// then the outgoing config is empty).
	repeated uint64 voters = 1;
	// The learners in the incoming config.
	repeated uint64 learners          = 2;
	// The voters in the outgoing config.
	repeated uint64 voters_outgoing   = 3;
	// The nodes that will become learners when the outgoing config is removed.
	// These nodes are necessarily currently in nodes_joint (or they would have
	// been added to the incoming config right away).
	repeated uint64 learners_next     = 4;
	// If set, the config is joint and Raft will automatically transition into
	// the final config (i.e. remove the outgoing config) when this is safe.
	optional bool   auto_leave        = 5 [(gogoproto.nullable) = false];
}

这个是raftpd的proto文件中对于ConfState的结构定义,包括集群中的配置状态,voter、learner有多少个,移除了多少个voter等等。

在paxos中,Learners可以看做是所有被确认消息的执行器,一旦有Client的消息请求被Acceptors确认之后,Learners会做相应的处理(如:执行消息内容,发送回复给Client)。Learner可以有多个。Acceptor (Voters)可以看做是消息请求的存储器。一般来说Acceptors是由一定数量的服务组成的,当消息被发送给Acceptor, 只有大部分Acceptor确认接收此消息,该消息才会被存储,否则该消息将被丢弃。

_________________________________________

在confstate.go文件中只有如下一个函数,Equivalent函数,它是ConfState这个接口的一种方法,这个函数字面上理解就是相等,用于判断当前的confstate cs和传入的cs2这个confstate状态参数是否相等。相等就给error类型返回一个nil,表示没有错误;如果不相等就给error返回错误显示不同的地方在哪。其中用到了sort.Slice这个方法,就是一种排序的工具,这里i<j,就是从小到大的方式排序。

// Equivalent returns a nil error if the inputs describe the same configuration.
// On mismatch, returns a descriptive error showing the differences.
func (cs ConfState) Equivalent(cs2 ConfState) error {
	cs1 := cs
	orig1, orig2 := cs1, cs2
	s := func(sl *[]uint64) {
		*sl = append([]uint64(nil), *sl...)
		sort.Slice(*sl, func(i, j int) bool { return (*sl)[i] < (*sl)[j] })
	}

	for _, cs := range []*ConfState{&cs1, &cs2} {
		s(&cs.Voters)
		s(&cs.Learners)
		s(&cs.VotersOutgoing)
		s(&cs.LearnersNext)
		cs.XXX_unrecognized = nil
	}

	if !reflect.DeepEqual(cs1, cs2) {
		return fmt.Errorf("ConfStates not equivalent after sorting:\n%+#v\n%+#v\nInputs were:\n%+#v\n%+#v", cs1, cs2, orig1, orig2)
	}
	return nil
}

下面我们来看看测试,首先定义一个测试案例的结构体, 包括两个参数,第一个是confstate状态参数,有2个state,第二个是是否相等的结果。

然后在测试案例中实例化一个testCases切片存储几种特殊的状态,看看那个Equivalent函数写的对不对,自己写了几种状态

case0:对于confstate中的值进行打乱顺序,但是值的相等的。

case1:对nil和empty的state不敏感

case2:不相等的voters

case3:不相等的learners

case4:对auto_leave  这个配置敏感

func TestConfState_Equivalent(t *testing.T) {
	type testCase struct {
		cs, cs2 ConfState
		ok      bool
	}

	testCases := []testCase{
		// Reordered voters and learners.
		{ConfState{
			Voters:         []uint64{1, 2, 3},
			Learners:       []uint64{5, 4, 6},
			VotersOutgoing: []uint64{9, 8, 7},
			LearnersNext:   []uint64{10, 20, 15},
		}, ConfState{
			Voters:         []uint64{1, 2, 3},
			Learners:       []uint64{4, 5, 6},
			VotersOutgoing: []uint64{7, 9, 8},
			LearnersNext:   []uint64{20, 10, 15},
		}, true},
		// Not sensitive to nil vs empty slice.
		{ConfState{Voters: []uint64{}}, ConfState{Voters: []uint64(nil)}, true},
		// Non-equivalent voters.
		{ConfState{Voters: []uint64{1, 2, 3, 4}}, ConfState{Voters: []uint64{2, 1, 3}}, false},
		{ConfState{Voters: []uint64{1, 4, 3}}, ConfState{Voters: []uint64{2, 1, 3}}, false},
		// Non-equivalent learners.
		{ConfState{Voters: []uint64{1, 2, 3, 4}}, ConfState{Voters: []uint64{2, 1, 3}}, false},
		// Sensitive to AutoLeave flag.
		{ConfState{AutoLeave: true}, ConfState{}, false},
	}

	for _, tc := range testCases {
		t.Run("", func(t *testing.T) {
			if err := tc.cs.Equivalent(tc.cs2); (err == nil) != tc.ok {
				t.Fatalf("wanted error: %t, got:\n%s", tc.ok, err)
			}
		})
	}
}

 

 

 

 

 

相关标签: raft