Dave Presotto | c549428 | 2016-01-29 14:46:52 -0800 | [diff] [blame] | 1 | // Copyright 2015 The Vanadium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | |
| 5 | package raft |
| 6 | |
| 7 | import ( |
| 8 | "io" |
| 9 | "time" |
| 10 | |
| 11 | "v.io/v23/context" |
| 12 | "v.io/v23/security/access" |
| 13 | ) |
| 14 | |
| 15 | // Raft provides a consistent log across multiple instances of a client. |
| 16 | |
| 17 | // RaftClient defines the call backs from the Raft library to the application. |
| 18 | type RaftClient interface { |
| 19 | // Apply appies a logged command, 'cmd', to the client. The commands will |
| 20 | // be delivered in the same order and with the same 'index' to all clients. |
| 21 | // 'index' is a monotonically increasing number and is just an index into the |
| 22 | // common log. |
| 23 | // |
| 24 | // Whenever a client restarts (after a crash perhaps) or falls too far behind |
| 25 | // (as in a partitioned network) it will be reinitialized with a RestoreFomSnapshot |
| 26 | // and then replayed all subsequent logged commands. |
| 27 | // |
| 28 | // A client that wishes to may return empty snapshots, i.e., just close the error |
| 29 | // channel without writing anything and worry about reliably storing its database |
| 30 | // itself. It that case it must remember the highest index it has seen if it wishes |
| 31 | // to avoid replays. Hence the index is supplied with the Apply(). |
| 32 | Apply(cmd []byte, index Index) error |
| 33 | |
| 34 | // SaveToSnapshot requests the application to write a snapshot to 'wr'. |
| 35 | // Until SaveToSnapshot returns, no commands will be Apply()ed. Closing |
| 36 | // the response channel signals that the snapshot is finished. Any |
| 37 | // error written to the response channel will be logged by the library |
| 38 | // and the library will discard the snapshot if any error is returned. |
| 39 | SaveToSnapshot(ctx *context.T, wr io.Writer, response chan<- error) error |
| 40 | |
| 41 | // RestoreFromSnapshot requests the application to rebuild its database from the snapshot |
| 42 | // it must read from 'rd'. 'index' is the last index applied to the snapshot. No Apply()s |
| 43 | // will be performed until RestoreFromSnapshot() returns. 'index' can be ignored |
| 44 | // or used for debugging. |
| 45 | RestoreFromSnapshot(ctx *context.T, index Index, rd io.Reader) error |
| 46 | } |
| 47 | |
| 48 | const ( |
| 49 | RoleCandidate = iota // Requesting to be voted leader. |
| 50 | RoleFollower |
| 51 | RoleLeader |
| 52 | RoleStopped |
| 53 | ) |
| 54 | |
| 55 | type Raft interface { |
| 56 | // AddMember adds a new member to the server set. "id" is actually a network address for the member, |
| 57 | // currently host:port. This has to be done before starting the server. |
| 58 | AddMember(ctx *context.T, id string) error |
| 59 | |
| 60 | // Id returns the id of this member. |
| 61 | Id() string |
| 62 | |
| 63 | // Start starts the local server communicating with other members. |
| 64 | Start() |
| 65 | |
| 66 | // Stop terminates the server. It cannot be Start'ed again. |
| 67 | Stop() |
| 68 | |
| 69 | // Append appends a new command to the replicated log. The command will be Apply()ed at each member |
| 70 | // once a quorum has logged it. The Append() will terminate once a quorum has logged it and at least |
| 71 | // the leader has Apply()ed the command. 'applyError' is the error returned by the Apply() while |
| 72 | // 'raftError' is returned by the raft library itself reporting that the Append could not be |
| 73 | // performed. |
| 74 | Append(ctx *context.T, cmd []byte) (applyError, raftError error) |
| 75 | |
| 76 | // Status returns the state of the raft. |
| 77 | Status() (myId string, role int, leader string) |
| 78 | |
| 79 | // StartElection forces an election. Normally just used for debugging. |
| 80 | StartElection() |
| 81 | } |
| 82 | |
| 83 | // RaftConfig is passed to NewRaft to avoid lots of parameters. |
| 84 | type RaftConfig struct { |
Benjamin Prosnitz | e14a595 | 2016-02-02 16:37:49 -0800 | [diff] [blame] | 85 | LogDir string // Directory in which to put log and snapshot files. |
| 86 | HostPort string // For RPCs from other members. |
| 87 | ServerName string // Where to mount if not empty. |
| 88 | Heartbeat time.Duration // Time between heartbeats. |
| 89 | SnapshotThreshold int64 // Approximate number of log entries between snapshots. |
| 90 | Acl access.AccessList // For sending RPC to the members. |
Dave Presotto | c549428 | 2016-01-29 14:46:52 -0800 | [diff] [blame] | 91 | } |
| 92 | |
| 93 | // NewRaft creates a new raft server. |
| 94 | func NewRaft(ctx *context.T, config *RaftConfig, client RaftClient) (Raft, error) { |
| 95 | return newRaft(ctx, config, client) |
| 96 | } |