Skip to content

Commit

Permalink
Adding DisableBootstrapAfterElect config to disable bootstrap
Browse files Browse the repository at this point in the history
  • Loading branch information
armon committed Oct 18, 2014
1 parent f6bfeff commit 2132875
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 10 deletions.
28 changes: 18 additions & 10 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ type Config struct {
// we can become a leader of a cluster containing only this node.
ShutdownOnRemove bool

// DisableBootstrapAfterElect is used to turn off EnableSingleNode
// after the node is elected. This is used to prevent self-election
// if the node is removed from the Raft cluster via RemovePeer. Setting
// it to false will keep the bootstrap mode, allowing the node to self-elect
// and potentially bootstrap a seperate cluster.
DisableBootstrapAfterElect bool

// TrailingLogs controls how many logs we leave after a snapshot. This is
// used so that we can quickly replay logs on a follower instead of being
// forced to send an entire snapshot.
Expand Down Expand Up @@ -65,16 +72,17 @@ type Config struct {
// DefaultConfig returns a Config with usable defaults.
func DefaultConfig() *Config {
return &Config{
HeartbeatTimeout: 1000 * time.Millisecond,
ElectionTimeout: 1000 * time.Millisecond,
CommitTimeout: 50 * time.Millisecond,
MaxAppendEntries: 64,
ShutdownOnRemove: true,
TrailingLogs: 10240,
SnapshotInterval: 120 * time.Second,
SnapshotThreshold: 8192,
EnableSingleNode: false,
LeaderLeaseTimeout: 500 * time.Millisecond,
HeartbeatTimeout: 1000 * time.Millisecond,
ElectionTimeout: 1000 * time.Millisecond,
CommitTimeout: 50 * time.Millisecond,
MaxAppendEntries: 64,
ShutdownOnRemove: true,
DisableBootstrapAfterElect: true,
TrailingLogs: 10240,
SnapshotInterval: 120 * time.Second,
SnapshotThreshold: 8192,
EnableSingleNode: false,
LeaderLeaseTimeout: 500 * time.Millisecond,
}
}

Expand Down
8 changes: 8 additions & 0 deletions raft.go
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,14 @@ func (r *Raft) runLeader() {
}
r.dispatchLogs([]*logFuture{noop})

// Disable EnableSingleNode after we've been elected leader.
// This is to prevent a split brain in the future, if we are removed
// from the cluster and then elect ourself as leader.
if r.conf.DisableBootstrapAfterElect && r.conf.EnableSingleNode {
r.logger.Printf("[INFO] raft: Disabling EnableSingleNode (bootstrap)")
r.conf.EnableSingleNode = false
}

// Sit in the leader loop until we step down
r.leaderLoop()
}
Expand Down
50 changes: 50 additions & 0 deletions raft_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -841,11 +841,61 @@ func TestRaft_RemoveLeader(t *testing.T) {
}
}

func TestRaft_RemoveLeader_NoShutdown(t *testing.T) {
// Make a cluster
conf := inmemConfig()
conf.ShutdownOnRemove = false
c := MakeCluster(3, t, conf)
defer c.Close()

// Get the leader
leader := c.Leader()

// Wait until we have 2 followers
limit := time.Now().Add(200 * time.Millisecond)
var followers []*Raft
for time.Now().Before(limit) && len(followers) != 2 {
time.Sleep(10 * time.Millisecond)
followers = c.GetInState(Follower)
}
if len(followers) != 2 {
t.Fatalf("expected two followers: %v", followers)
}

// Remove the leader
leader.RemovePeer(leader.localAddr)

// Wait a while
time.Sleep(20 * time.Millisecond)

// Should have a new leader
newLeader := c.Leader()

// Wait a bit for log application
time.Sleep(20 * time.Millisecond)

// Other nodes should have fewer peers
if peers, _ := newLeader.peerStore.Peers(); len(peers) != 2 {
t.Fatalf("too many peers")
}

// Old leader should be a follower
if leader.State() != Follower {
t.Fatalf("leader should be shutdown")
}

// Old leader should have no peers
if peers, _ := leader.peerStore.Peers(); len(peers) != 1 {
t.Fatalf("leader should have no peers")
}
}

func TestRaft_RemoveLeader_SplitCluster(t *testing.T) {
// Enable operation after a remove
conf := inmemConfig()
conf.EnableSingleNode = true
conf.ShutdownOnRemove = false
conf.DisableBootstrapAfterElect = false

// Make a cluster
c := MakeCluster(3, t, conf)
Expand Down

0 comments on commit 2132875

Please sign in to comment.