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