Crate raftmodel[][src]

Expand description

Raft Model

raftmodel aims to provide the rust implementations of logic model for the raft consensus algorithm.

The big picture

raftmodel is a crate to provide a pure logic model for the raft algorithm. It aims to strictly follow raft formal TLA+ specification (raft.tla).

To use raftmodel, user interacts with raft by calling handle_message method in RaftServer. The input of handle_message is RaftMessage and the output is Vec<RaftMessage>. For example, a client can use the following code to add a new entry to the log of the leader and replicate it to the followers.

let response = leader.handle_message(            
           RaftMessage::ClientRequest {
               dest: 1,
               value: "x",
           },
    );

However, this crate only implements the pure logic of the raft algorithm. In order for it to work in the real environment, user needs to implement the I/O in order to pass the messages between servers across the network and also store some information to the persistent storage such as disks.

Quick Start

To demonstrate how to use this crate, we define the mock up run_message function in the following code. It is used to simulate the raft messages being passed between servers in the network which drives the log entries replicated from the leader to the followers.

use crate::raftmodel::*;
use std::collections::{VecDeque, HashSet};
use std::fmt::Debug;
fn run_message<T>(initial_message: RaftMessage<T>, servers: &mut Vec<RaftServer<T>>)
where
    T: Sized + Clone + PartialEq + Eq + Debug + Default,
{
    let mut messages = VecDeque::new();
    messages.push_back(initial_message);
    while let Some(msg) = messages.pop_front() {
        let dest = match msg {
            RaftMessage::ClientRequest { dest, .. }
            | RaftMessage::BecomeLeader { dest, .. }
            | RaftMessage::AppendEntries { dest, .. }
            | RaftMessage::AppendEntriesRequest { dest, .. }
            | RaftMessage::AppendEntriesResponse { dest, .. }
            | RaftMessage::RequestVoteRequest { dest, .. }
            | RaftMessage::RequestVoteResponse { dest, .. }
            | RaftMessage::TimeOut { dest, .. } => dest,
        };
        let server = &mut servers[dest as usize];
        let responses = server.handle_message(msg);
        messages.append(&mut responses.into_iter().collect());
    }
}



let log = create_empty_log();

let mut servers = vec![
   RaftServer::new(log.clone()),
   RaftServer::new(log.clone()),
   RaftServer::new(log.clone()),
   RaftServer::new(log.clone()),
   RaftServer::new(log.clone()),
   RaftServer::new(log.clone()),
];

// Let server 1 time out to become a candidate. It should win the election with all votes
run_message(
    RaftMessage::TimeOut {
        dest: 1,
        followers: (2..6).collect(),
    },
    &mut servers,
);
assert_eq!(*servers[1].server_state(), ServerState::Leader);

// Client append a new entry to the leader's log
run_message(
   RaftMessage::ClientRequest{
       dest:1,
       value: "x".to_string(),
   },
   &mut servers,
);

// The first AppendEntries will update leader commit_index
run_message(
    RaftMessage::AppendEntries {
        dest: 1,
        followers: (2..6).collect(),
    },
    &mut servers,
);

// The second AppendEntries will update all followers commit_index
run_message(
    RaftMessage::AppendEntries {
        dest: 1,
        followers: (2..6).collect(),
    },
    &mut servers,
);

assert!(servers.iter().skip(1).all(|x| { servers[1].log() == x.log() }));

Structs

Each log entry consists of a term number and an item

A single Raft server. A server only communicates via messages

Enums

The message which Raft server used to communicate between each other

The server states

Functions

Adds one or more entries to the log and returns a true/false value to indicate success. The log starts from index 1. The entry at index 0 is meaningless. The term starts from 1.

Create an empty log and returns to the caller Because the log index starts with 1, the value at index 0 of the log is prefilled with a default value of T