Merge pull request #1066 from philips/add-raft-doc

add-raft-doc
This commit is contained in:
Brandon Philips
2014-09-12 12:21:53 -07:00
3 changed files with 75 additions and 2 deletions

65
raft/doc.go Normal file
View File

@@ -0,0 +1,65 @@
// Copyright 2014 CoreOS Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
Package raft provides an implementation of the raft consensus algorithm.
The primary object in raft is a Node. You either start a Node from scratch
using raft.Start or start a Node from some initial state using raft.Restart.
n := raft.Start(0x01, []int64{0x02, 0x03}, 3, 1)
Now that you are holding onto a Node you have a few responsibilities:
First, you need to push messages that you receive from other machines into the
Node with n.Step().
func recvRaftRPC(ctx context.Context, m raftpb.Message) {
n.Step(ctx, m)
}
Second, you need to save log entries to storage, process committed log entries
through your application and then send pending messages to peers by reading the
channel returned by n.Ready(). It is important that the user persist any
entries that require stable storage before sending messages to other peers to
ensure fault-tolerance.
And finally you need to service timeouts with Tick(). Raft has two important
timeouts: heartbeat and the election timeout. However, internally to the raft
package time is represented by an abstract "tick". The user is responsible for
calling Tick() on their raft.Node on a regular interval in order to service
these timeouts.
The total state machine handling loop will look something like this:
for {
select {
case <-s.Ticker:
n.Tick()
case rd := <-s.Node.Ready():
saveToStable(rd.State, rd.Entries)
process(rd.CommittedEntries)
send(rd.Messages)
case <-s.done:
return
}
}
To propose changes to the state machine from your node take your application
data, serialize it into a byte slice and call:
n.Propose(ctx, data)
*/
package raft

View File

@@ -1,4 +1,3 @@
// Package raft implements raft.
package raft
import (
@@ -55,6 +54,8 @@ type Node struct {
done chan struct{}
}
// Start returns a new Node given a unique raft id, a list of raft peers, and
// the election and heartbeat timeouts in units of ticks.
func Start(id int64, peers []int64, election, heartbeat int) Node {
n := newNode()
r := newRaft(id, peers, election, heartbeat)
@@ -62,6 +63,9 @@ func Start(id int64, peers []int64, election, heartbeat int) Node {
return n
}
// Restart is identical to Start but takes an initial State and a slice of
// entries. Generally this is used when restarting from a stable storage
// log.
func Restart(id int64, peers []int64, election, heartbeat int, st pb.State, ents []pb.Entry) Node {
n := newNode()
r := newRaft(id, peers, election, heartbeat)
@@ -131,6 +135,8 @@ func (n *Node) run(r *raft) {
}
}
// Tick increments the internal logical clock for this Node. Election timeouts
// and heartbeat timeouts are in units of ticks.
func (n *Node) Tick() error {
select {
case n.tickc <- struct{}{}:

View File

@@ -108,7 +108,7 @@ type raft struct {
// the leader id
lead int64
elapsed int
elapsed int // number of ticks since the last msg
heartbeatTimeout int
electionTimeout int
tick func()
@@ -258,6 +258,7 @@ func (r *raft) appendEntry(e pb.Entry) {
r.maybeCommit()
}
// tickElection is ran by followers and candidates after r.electionTimeout.
func (r *raft) tickElection() {
r.elapsed++
// TODO (xiangli): elctionTimeout should be randomized.
@@ -267,6 +268,7 @@ func (r *raft) tickElection() {
}
}
// tickHeartbeat is ran by leaders to send a msgBeat after r.heartbeatTimeout.
func (r *raft) tickHeartbeat() {
r.elapsed++
if r.elapsed > r.heartbeatTimeout {