forked from influxdata/influxdb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
config.go
189 lines (161 loc) · 4.36 KB
/
config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
package raft
import (
"encoding/json"
"io"
"net/url"
)
// Config represents the configuration for the log.
type Config struct {
// Cluster identifier. Used to prevent separate clusters from
// accidentally communicating with one another.
ClusterID uint64
// Index is the last log index when the configuration was updated.
Index uint64
// MaxNodeID is the largest node identifier generated for this config.
MaxNodeID uint64
// List of nodes in the cluster.
Nodes []*ConfigNode
}
// NodeByID returns a node by identifier.
func (c *Config) NodeByID(id uint64) *ConfigNode {
for _, n := range c.Nodes {
if n.ID == id {
return n
}
}
return nil
}
// NodeByURL returns a node by URL.
func (c *Config) NodeByURL(u url.URL) *ConfigNode {
for _, n := range c.Nodes {
if n.URL.String() == u.String() {
return n
}
}
return nil
}
// AddNode adds a new node to the config.
func (c *Config) AddNode(id uint64, u url.URL) error {
// Validate that the id is non-zero and the url exists.
if id == 0 {
return ErrInvalidNodeID
} else if u.Host == "" {
return ErrNodeURLRequired
}
// Validate that no other nodes in the config have the same id or URL.
for _, n := range c.Nodes {
if n.ID == id {
return ErrDuplicateNodeID
} else if n.URL.String() == u.String() {
return ErrDuplicateNodeURL
}
}
// Add the node to the config.
c.Nodes = append(c.Nodes, &ConfigNode{ID: id, URL: u})
return nil
}
// RemoveNode removes a node by id.
// Returns ErrNodeNotFound if the node does not exist.
func (c *Config) RemoveNode(id uint64) error {
for i, node := range c.Nodes {
if node.ID == id {
copy(c.Nodes[i:], c.Nodes[i+1:])
c.Nodes[len(c.Nodes)-1] = nil
c.Nodes = c.Nodes[:len(c.Nodes)-1]
return nil
}
}
return ErrNodeNotFound
}
// Clone returns a deep copy of the configuration.
func (c *Config) Clone() *Config {
other := &Config{
ClusterID: c.ClusterID,
Index: c.Index,
MaxNodeID: c.MaxNodeID,
}
other.Nodes = make([]*ConfigNode, len(c.Nodes))
for i, n := range c.Nodes {
other.Nodes[i] = n.clone()
}
return other
}
// ConfigNode represents a single machine in the raft configuration.
type ConfigNode struct {
ID uint64
URL url.URL
}
// clone returns a deep copy of the node.
func (n *ConfigNode) clone() *ConfigNode {
other := &ConfigNode{ID: n.ID}
other.URL = n.URL
return other
}
// ConfigEncoder encodes a config to a writer.
type ConfigEncoder struct {
w io.Writer
}
// NewConfigEncoder returns a new instance of ConfigEncoder attached to a writer.
func NewConfigEncoder(w io.Writer) *ConfigEncoder {
return &ConfigEncoder{w}
}
// Encode marshals the configuration to the encoder's writer.
func (enc *ConfigEncoder) Encode(c *Config) error {
// Copy properties to intermediate type.
var o configJSON
o.ClusterID = c.ClusterID
o.Index = c.Index
o.MaxNodeID = c.MaxNodeID
for _, n := range c.Nodes {
o.Nodes = append(o.Nodes, &configNodeJSON{ID: n.ID, URL: n.URL.String()})
}
// Encode intermediate type as JSON.
return json.NewEncoder(enc.w).Encode(&o)
}
// ConfigDecoder decodes a config from a reader.
type ConfigDecoder struct {
r io.Reader
}
// NewConfigDecoder returns a new instance of ConfigDecoder attached to a reader.
func NewConfigDecoder(r io.Reader) *ConfigDecoder {
return &ConfigDecoder{r}
}
// Decode marshals the configuration to the decoder's reader.
func (dec *ConfigDecoder) Decode(c *Config) error {
// Decode into intermediate type.
var o configJSON
if err := json.NewDecoder(dec.r).Decode(&o); err != nil {
return err
}
// Copy properties to config.
c.ClusterID = o.ClusterID
c.Index = o.Index
c.MaxNodeID = o.MaxNodeID
// Validate and append nodes.
for _, n := range o.Nodes {
// Parse node URL.
u, err := url.Parse(n.URL)
if err != nil {
return err
} else if n.URL == "" {
u = &url.URL{}
}
// Append node to config.
if err := c.AddNode(n.ID, *u); err != nil {
return err
}
}
return nil
}
// configJSON represents an intermediate struct used for JSON encoding.
type configJSON struct {
ClusterID uint64 `json:"clusterID,omitempty"`
Index uint64 `json:"index,omitempty"`
MaxNodeID uint64 `json:"maxNodeID,omitempty"`
Nodes []*configNodeJSON `json:"nodes,omitempty"`
}
// configNodeJSON represents the JSON serialized form of the ConfigNode type.
type configNodeJSON struct {
ID uint64 `json:"id"`
URL string `json:"url,omitempty"`
}