AI智能
改变未来

[etcd]raftpd confchange.go

______________________看前须知_________________

在状态改变的程序中需要使用如下接口定义。首先有2个ConfChange,一个是ConfChange,另外一个是ConfChangeV2,这两个接口需要统一化,但是在proto中定义有差异,所以后面的go文件对这两个接口统一化写了一些函数来处理。所以这里要看清楚这两个接口到底有哪些不一样的地方。

[code]message ConfChange {optional ConfChangeType  type    = 2 [(gogoproto.nullable) = false];optional uint64          node_id = 3 [(gogoproto.nullable) = false, (gogoproto.customname) = \"NodeID\" ];optional bytes           context = 4;// NB: this is used only by etcd to thread through a unique identifier.// Ideally it should really use the Context instead. No counterpart to// this field exists in ConfChangeV2.optional uint64          id      = 1 [(gogoproto.nullable) = false, (gogoproto.customname) = \"ID\" ];}enum ConfChangeType {ConfChangeAddNode        = 0;ConfChangeRemoveNode     = 1;ConfChangeUpdateNode     = 2;ConfChangeAddLearnerNode = 3;}_________________________________________________________________________________________message ConfChangeV2 {optional ConfChangeTransition transition = 1 [(gogoproto.nullable) = false];repeated ConfChangeSingle     changes =    2 [(gogoproto.nullable) = false];optional bytes                context =    3;}// ConfChangeSingle is an individual configuration change operation. Multiple// such operations can be carried out atomically via a ConfChangeV2.message ConfChangeSingle {optional ConfChangeType  type    = 1 [(gogoproto.nullable) = false];optional uint64          node_id = 2 [(gogoproto.nullable) = false, (gogoproto.customname) = \"NodeID\"];}// ConfChangeTransition specifies the behavior of a configuration change with// respect to joint consensus.enum ConfChangeTransition {// Automatically use the simple protocol if possible, otherwise fall back// to ConfChangeJointImplicit. Most applications will want to use this.ConfChangeTransitionAuto          = 0;// Use joint consensus unconditionally, and transition out of them// automatically (by proposing a zero configuration change).//// This option is suitable for applications that want to minimize the time// spent in the joint configuration and do not store the joint configuration// in the state machine (outside of InitialState).ConfChangeTransitionJointImplicit = 1;// Use joint consensus and remain in the joint configuration until the// application proposes a no-op configuration change. This is suitable for// applications that want to explicitly control the transitions, for example// to use a custom payload (via the Context field).ConfChangeTransitionJointExplicit = 2;}

对于ConfChangeTransition的理解:ConfChangeTransition指定关于联合共识的配置更改的行为。自动、显式、隐式三种。

__________________________________________________

confchange.go文件中首先要看怎么把confchange和confchangeV2统一起来

首先confchange.AsV1(),confchange.AsV2(),confchangeV2.AsV1(),confchangeV2.AsV2()这四个函数就将V1和V2两个版本的接口可以随意转化。

然后对于ConfChangeV2有V2.EnterJoint()和V2.LeaveJoint()方法, 这个对应Raft论文里面的cluster joint consensus。

V2.ConfChangesFromString()是将空格分隔的操作序列解析为ConfChangeSingle的切片,这样可以将一串字符串按照格式解析成单个confchangge。V2.ConfChangesToString()是反过来操作,将单个ConfChange连成字符串。

最后,主要的MarshalConfChange()函数,marshal 会将 []byte 代表的 json 数据转换为我们想要的结构体

[code]// ConfChangeI abstracts over ConfChangeV2 and (legacy) ConfChange to allow// treating them in a unified manner.type ConfChangeI interface {AsV2() ConfChangeV2AsV1() (ConfChange, bool)}// MarshalConfChange calls Marshal on the underlying ConfChange or ConfChangeV2// and returns the result along with the corresponding EntryType.func MarshalConfChange(c ConfChangeI) (EntryType, []byte, error) {var typ EntryTypevar ccdata []bytevar err errorif ccv1, ok := c.AsV1(); ok {typ = EntryConfChangeccdata, err = ccv1.Marshal()} else {ccv2 := c.AsV2()typ = EntryConfChangeV2ccdata, err = ccv2.Marshal()}return typ, ccdata, err}// AsV2 returns a V2 configuration change carrying out the same operation.func (c ConfChange) AsV2() ConfChangeV2 {return ConfChangeV2{Changes: []ConfChangeSingle{{Type:   c.Type,NodeID: c.NodeID,}},Context: c.Context,}}// AsV1 returns the ConfChange and true.func (c ConfChange) AsV1() (ConfChange, bool) {return c, true}// AsV2 is the identity.func (c ConfChangeV2) AsV2() ConfChangeV2 { return c }// AsV1 returns ConfChange{} and false.func (c ConfChangeV2) AsV1() (ConfChange, bool) { return ConfChange{}, false }// EnterJoint returns two bools. The second bool is true if and only if this// config change will use Joint Consensus, which is the case if it contains more// than one change or if the use of Joint Consensus was requested explicitly.// The first bool can only be true if second one is, and indicates whether the// Joint State will be left automatically.func (c ConfChangeV2) EnterJoint() (autoLeave bool, ok bool) {// NB: in theory, more config changes could qualify for the \"simple\"// protocol but it depends on the config on top of which the changes apply.// For example, adding two learners is not OK if both nodes are part of the// base config (i.e. two voters are turned into learners in the process of// applying the conf change). In practice, these distinctions should not// matter, so we keep it simple and use Joint Consensus liberally.if c.Transition != ConfChangeTransitionAuto || len(c.Changes) > 1 {// Use Joint Consensus.var autoLeave boolswitch c.Transition {case ConfChangeTransitionAuto:autoLeave = truecase ConfChangeTransitionJointImplicit:autoLeave = truecase ConfChangeTransitionJointExplicit:default:panic(fmt.Sprintf(\"unknown transition: %+v\", c))}return autoLeave, true}return false, false}// LeaveJoint is true if the configuration change leaves a joint configuration.// This is the case if the ConfChangeV2 is zero, with the possible exception of// the Context field.func (c ConfChangeV2) LeaveJoint() bool {// NB: c is already a copy.c.Context = nilreturn proto.Equal(&c, &ConfChangeV2{})}// ConfChangesFromString parses a Space-delimited sequence of operations into a// slice of ConfChangeSingle. The supported operations are:// - vn: make n a voter,// - ln: make n a learner,// - rn: remove n, and// - un: update n.func ConfChangesFromString(s string) ([]ConfChangeSingle, error) {var ccs []ConfChangeSingletoks := strings.Split(strings.TrimSpace(s), \" \")if toks[0] == \"\" {toks = nil}for _, tok := range toks {if len(tok) < 2 {return nil, fmt.Errorf(\"unknown token %s\", tok)}var cc ConfChangeSingleswitch tok[0] {case \'v\':cc.Type = ConfChangeAddNodecase \'l\':cc.Type = ConfChangeAddLearnerNodecase \'r\':cc.Type = ConfChangeRemoveNodecase \'u\':cc.Type = ConfChangeUpdateNodedefault:return nil, fmt.Errorf(\"unknown input: %s\", tok)}id, err := strconv.ParseUint(tok[1:], 10, 64)if err != nil {return nil, err}cc.NodeID = idccs = append(ccs, cc)}return ccs, nil}// ConfChangesToString is the inverse to ConfChangesFromString.func ConfChangesToString(ccs []ConfChangeSingle) string {var buf strings.Builderfor i, cc := range ccs {if i > 0 {buf.WriteByte(\' \')}switch cc.Type {case ConfChangeAddNode:buf.WriteByte(\'v\')case ConfChangeAddLearnerNode:buf.WriteByte(\'l\')case ConfChangeRemoveNode:buf.WriteByte(\'r\')case ConfChangeUpdateNode:buf.WriteByte(\'u\')default:buf.WriteString(\"unknown\")}fmt.Fprintf(&buf, \"%d\", cc.NodeID)}return buf.String()}

 

 

 

 

 

 

 

 

 

 

 

 

 

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » [etcd]raftpd confchange.go