forked from ExploratoryEngineering/clusterfunk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
raft_node.go
144 lines (116 loc) · 4.83 KB
/
raft_node.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
package funk
import (
"fmt"
"github.com/lab5e/clusterfunk/pkg/toolbox"
)
// RaftEventType is the event type for events emitted by the RaftNode type
type RaftEventType int
const (
//RaftClusterSizeChanged is emitted when a new node is added
RaftClusterSizeChanged RaftEventType = iota
// RaftLeaderLost is emitted when the leader is lost, ie the node enters the candidate state
RaftLeaderLost
// RaftBecameLeader is emitted when the leader becomes the leader
RaftBecameLeader
// RaftBecameFollower is emitted when the node becomes a follower
RaftBecameFollower
// RaftReceivedLog is emitted when a log entry is receievd
RaftReceivedLog
// RaftShutdown is emitted when the node is shutting down
RaftShutdown
// RaftUndefinedEvent is the undefined event type
RaftUndefinedEvent
)
// String is the string representation of the event
func (r RaftEventType) String() string {
switch r {
case RaftClusterSizeChanged:
return "RaftClusterSizeChanged"
case RaftLeaderLost:
return "RaftLeaderLost"
case RaftBecameLeader:
return "RaftBecameLeader"
case RaftBecameFollower:
return "RaftBecameFollower"
case RaftReceivedLog:
return "RaftReceivedLog"
case RaftShutdown:
return "RaftShutdown"
default:
panic(fmt.Sprintf("Unknown raft event type: %d", r))
}
}
// RaftNode is a (local) Raft node implementation
type RaftNode interface {
// Start launches the node. The return value is set to true if the cluster
// is bootstrapped
Start(nodeID string, cfg RaftParameters) (bool, error)
// Stop stops the node. If the removeWhenStopping flag is set and the server is
// the leader it will remove itself.
Stop(removeWhenStopping bool) error
// LocalNodeID returns the local node ID
LocalNodeID() string
// AddClusterNode adds a new node to the cluster. Must be leader to perform this operation.
AddClusterNode(nodeID string, endpoint string) error
// RemoveClusterNode removes a node from the cluster. Must be leader to perform this
// operation.
RemoveClusterNode(nodeID string, endpoint string) error
// Endpoint returns the Raft endpoint (aka bind address)
Endpoint() string
// Leader returns true if this node is the leader. This will verify the
// leadership with the Raft library.
Leader() bool
// AppendLogEntry appends a log entry to the log. The function returns when
// there's a quorum in the cluster
AppendLogEntry(data []byte) (uint64, error)
// LastLogIndex returns the last log index received
LastLogIndex() uint64
// Events returns the event channel. There is only one
// event channel so use multiple listeners at your own peril.
// You will get NodeAdded, NodeRemoved, LeaderLost and LeaderChanged
// events on this channel.
Events() <-chan RaftEventType
// GetLogMessages returns the replicated log message with the
// specified type ID
GetLogMessages(startingIndex uint64) []LogMessage
// StepDown steps down as a leader if this is the leader node
StepDown() error
// RefreshNodes refreshes the node list by reading the Raft configuration.
// If any events are skipped by the Raft library we'll get the appropriate
// events and an updated node list after this call.
RefreshNodes()
// EnableNode enables a node that has been disabled. The node might be a part of the
// cluster but not available.
EnableNode(id string)
// DisableNode disables a node (in reality removing it from the local node list
// but it is still a member of the Raft cluster)
DisableNode(id string)
// LeaderNodeID returns the Node ID for the leader
LeaderNodeID() string
// Nodes returns a list of nodes
Nodes() *toolbox.StringSet
MemberList() ([]Node, error)
}
// NewRaftNode creates a new RaftNode instance
func NewRaftNode() RaftNode {
return newHashcorpRaftNode()
}
// TimingType is the timing for the Raft cluster. Aggressive mode works well on the loopback adapter and on
// nodes connected directly by a switch. Default mode is the default values in the Raft library and might work
// better on nodes with high load (and possibly on burstable AWS instances).
type TimingType string
// Timing modes for the Raft cluster
const (
AggressiveMode = TimingType("aggressive") // Aggressive mode, 5 ms commit timeout
DefaultMode = TimingType("default") // Default timeout, 250 ms commit timeout
MediumMode = TimingType("medium") // Medium, 50 ms commit timeout
)
// RaftParameters is the configuration for the Raft cluster
type RaftParameters struct {
Endpoint string `kong:"help='Endpoint for Raft',default=''"`
DiskStore string `kong:"help='Disk-based store',default=''"`
Bootstrap bool `kong:"help='Bootstrap a new Raft cluster',default='true'"`
Verbose bool `kong:"help='Verbose Raft logging',default='false'"`
TimingMode TimingType `kong:"help='Timing mode',default='default',enum='aggressive,medium,default'"`
DebugLog bool `kong:"help='Show debug log messages for Raft',default='false'"`
}