4个版本

0.1.3 2021年7月17日
0.1.2 2021年7月17日
0.1.1 2021年7月17日
0.1.0 2021年7月17日

#2064算法

MIT/Apache

43KB
862

raftmodel旨在提供raft共识算法逻辑模型的Rust实现。

整体架构

这是一个提供raft算法纯逻辑模型的crate。它旨在严格遵循raft正式的TLA+规范(raft.tla)。


lib.rs:

raft模型

raftmodel旨在提供raft共识算法逻辑模型的Rust实现。

整体架构

raftmodel是一个提供raft算法纯逻辑模型的crate。它旨在严格遵循raft正式的TLA+规范(raft.tla)。

要使用raftmodel,用户通过在RaftServer中调用handle_message方法与raft交互。`handle_message`的输入是`RaftMessage`,输出是`Vec`。例如,客户端可以使用以下代码将新条目添加到领导者的日志中,并将其复制到追随者。

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

然而,此crate仅实现了raft算法的纯逻辑。为了使其在实际环境中工作,用户需要实现I/O以在网络服务器之间传递消息,并将一些信息存储到持久存储(如磁盘)中。

快速入门

为了演示如何使用此crate,我们在以下代码中定义了模拟的run_message函数。它用于模拟网络中服务器之间传递的raft消息,从而驱动从领导者到追随者的日志条目复制。

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() }));


无运行时依赖