...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package raftpb
16
17 import (
18 "fmt"
19 "strconv"
20 "strings"
21
22 "github.com/gogo/protobuf/proto"
23 )
24
25
26
27 type ConfChangeI interface {
28 AsV2() ConfChangeV2
29 AsV1() (ConfChange, bool)
30 }
31
32
33
34 func MarshalConfChange(c ConfChangeI) (EntryType, []byte, error) {
35 var typ EntryType
36 var ccdata []byte
37 var err error
38 if ccv1, ok := c.AsV1(); ok {
39 typ = EntryConfChange
40 ccdata, err = ccv1.Marshal()
41 } else {
42 ccv2 := c.AsV2()
43 typ = EntryConfChangeV2
44 ccdata, err = ccv2.Marshal()
45 }
46 return typ, ccdata, err
47 }
48
49
50 func (c ConfChange) AsV2() ConfChangeV2 {
51 return ConfChangeV2{
52 Changes: []ConfChangeSingle{{
53 Type: c.Type,
54 NodeID: c.NodeID,
55 }},
56 Context: c.Context,
57 }
58 }
59
60
61 func (c ConfChange) AsV1() (ConfChange, bool) {
62 return c, true
63 }
64
65
66 func (c ConfChangeV2) AsV2() ConfChangeV2 { return c }
67
68
69 func (c ConfChangeV2) AsV1() (ConfChange, bool) { return ConfChange{}, false }
70
71
72
73
74
75
76 func (c ConfChangeV2) EnterJoint() (autoLeave bool, ok bool) {
77
78
79
80
81
82
83 if c.Transition != ConfChangeTransitionAuto || len(c.Changes) > 1 {
84
85 var autoLeave bool
86 switch c.Transition {
87 case ConfChangeTransitionAuto:
88 autoLeave = true
89 case ConfChangeTransitionJointImplicit:
90 autoLeave = true
91 case ConfChangeTransitionJointExplicit:
92 default:
93 panic(fmt.Sprintf("unknown transition: %+v", c))
94 }
95 return autoLeave, true
96 }
97 return false, false
98 }
99
100
101
102
103 func (c ConfChangeV2) LeaveJoint() bool {
104
105 c.Context = nil
106 return proto.Equal(&c, &ConfChangeV2{})
107 }
108
109
110
111
112
113
114
115 func ConfChangesFromString(s string) ([]ConfChangeSingle, error) {
116 var ccs []ConfChangeSingle
117 toks := strings.Split(strings.TrimSpace(s), " ")
118 if toks[0] == "" {
119 toks = nil
120 }
121 for _, tok := range toks {
122 if len(tok) < 2 {
123 return nil, fmt.Errorf("unknown token %s", tok)
124 }
125 var cc ConfChangeSingle
126 switch tok[0] {
127 case 'v':
128 cc.Type = ConfChangeAddNode
129 case 'l':
130 cc.Type = ConfChangeAddLearnerNode
131 case 'r':
132 cc.Type = ConfChangeRemoveNode
133 case 'u':
134 cc.Type = ConfChangeUpdateNode
135 default:
136 return nil, fmt.Errorf("unknown input: %s", tok)
137 }
138 id, err := strconv.ParseUint(tok[1:], 10, 64)
139 if err != nil {
140 return nil, err
141 }
142 cc.NodeID = id
143 ccs = append(ccs, cc)
144 }
145 return ccs, nil
146 }
147
148
149 func ConfChangesToString(ccs []ConfChangeSingle) string {
150 var buf strings.Builder
151 for i, cc := range ccs {
152 if i > 0 {
153 buf.WriteByte(' ')
154 }
155 switch cc.Type {
156 case ConfChangeAddNode:
157 buf.WriteByte('v')
158 case ConfChangeAddLearnerNode:
159 buf.WriteByte('l')
160 case ConfChangeRemoveNode:
161 buf.WriteByte('r')
162 case ConfChangeUpdateNode:
163 buf.WriteByte('u')
164 default:
165 buf.WriteString("unknown")
166 }
167 fmt.Fprintf(&buf, "%d", cc.NodeID)
168 }
169 return buf.String()
170 }
171
View as plain text