[etcd]raftpd confstate.go

_________________看前须知__________________

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)
			}
		})
	}
}

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值