diff --git a/.gitignore b/.gitignore index c4f2457f7..1184afb45 100644 --- a/.gitignore +++ b/.gitignore @@ -28,5 +28,6 @@ tmp harness/target Cargo.lock +rust-toolchain *.rs.bk *.rs.fmt diff --git a/.travis.yml b/.travis.yml index 487bf79c0..9c079f1dc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,40 +1,30 @@ -branches: - only: - # This is where pull requests from "bors r+" are built. - - staging - # This is where pull requests from "bors try" are built. - - trying - # Enable building pull requests. - - master +sudo: false language: rust -sudo: false +os: + - linux + - windows + - osx +rust: + - stable + - nightly + # First Rust 2018 Stable. Officially the oldest compiler we support. + - 1.31.0 env: global: - RUST_BACKTRACE=1 - RUSTFLAGS="-D warnings" cache: cargo -rust: - -matrix: - include: - # This build uses stable and checks rustfmt and clippy. - # We don't check them on nightly since their lints and formatting may differ. - - rust: stable - install: - - rustup component add rustfmt-preview - - rustup component add clippy-preview - before_script: - - cargo fmt --all -- --check - - cargo clippy --all -- -D clippy - # Since many users will use nightlies, also test that. - - rust: nightly - +install: + - if [[ $TRAVIS_RUST_VERSION == "stable" && $TRAVIS_OS_NAME == "linux" ]]; then rustup component add rustfmt; fi + - if [[ $TRAVIS_RUST_VERSION == "stable" && $TRAVIS_OS_NAME == "linux" ]]; then rustup component add clippy; fi script: + - if [[ $TRAVIS_RUST_VERSION == "stable" && $TRAVIS_OS_NAME == "linux" ]]; then cargo fmt -- --check; fi + - if [[ $TRAVIS_RUST_VERSION == "stable" && $TRAVIS_OS_NAME == "linux" ]]; then cargo clippy -- -D clippy::all; fi - cargo test --all -- --nocapture # Validate benches still work. - cargo bench --all -- --test # Because failpoints inject failure in code path, which will affect all concurrently running tests, Hence they need to be synchronized, which make tests slow. - - cargo test --tests --features failpoint -- --nocapture + - cargo test --tests --features failpoint -- --nocapture \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 2d850bd04..bbd9b8a79 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,16 +10,26 @@ homepage = "https://github.com/pingcap/raft-rs" documentation = "https://docs.rs/raft" description = "The rust language implementation of Raft algorithm." categories = ["algorithms", "database-implementations"] +edition = "2018" +build = "build.rs" + +[build-dependencies] +protobuf-build = "0.4.1" [features] default = [] +gen = [] # Enable failpoints failpoint = ["fail"] # Make sure to synchronize updates with Harness. [dependencies] log = ">0.2" -protobuf = "~2.0-2.2" +protobuf = "~2.1-2.2" +lazy_static = "1.3.0" +prost = "0.5" +prost-derive = "0.5" +bytes = "0.4.11" quick-error = "1.2.2" rand = "0.5.4" hashbrown = "0.1" diff --git a/README.md b/README.md index 86710effc..0138d8b75 100644 --- a/README.md +++ b/README.md @@ -31,20 +31,20 @@ A complete Raft model contains 4 essential parts: ## Developing the Raft crate -`raft` is intended to track the latest `stable`, though you'll need to use `nightly` to simulate a full CI build with `clippy`. +`Raft` is built using the latest version of `stable` Rust, using [the 2018 edition](https://doc.rust-lang.org/edition-guide/rust-2018/). Using `rustup` you can get started this way: ```bash -rustup component add clippy-preview -rustup component add rustfmt-preview +rustup component add clippy +rustup component add rustfmt ``` In order to have your PR merged running the following must finish without error: ```bash cargo test --all && \ -cargo clippy --all -- -D clippy && \ +cargo clippy --all -- -D clippy::all && \ cargo fmt --all -- --check ``` diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 9f9bfcb3c..000000000 --- a/appveyor.yml +++ /dev/null @@ -1,32 +0,0 @@ -branches: - only: - # This is where pull requests from "bors r+" are built. - - staging - # This is where pull requests from "bors try" are built. - - trying - # Enable building pull requests. - - master - -environment: - matrix: - - TARGET: x86_64-pc-windows-gnu - RUST_VERSION: stable - - TARGET: x86_64-pc-windows-gnu - RUST_VERSION: nightly - -install: - - curl -sSf -o rustup-init.exe https://win.rustup.rs/ - - rustup-init.exe -y --default-host %TARGET% --default-toolchain %RUST_VERSION% - - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin - - rustc -Vv - - cargo -V - -# Building is done in the test phase, so we disable Appveyor's build phase. -build: false - -cache: - - C:\Users\appveyor\.cargo\registry - - target - -test_script: - - cargo test diff --git a/benches/benches.rs b/benches/benches.rs index ea2be50a0..b21fba329 100644 --- a/benches/benches.rs +++ b/benches/benches.rs @@ -1,10 +1,6 @@ #![allow(dead_code)] // Due to criterion we need this to avoid warnings. #![cfg_attr(feature = "cargo-clippy", allow(clippy::let_and_return))] // Benches often artificially return values. Allow it. -extern crate criterion; -extern crate env_logger; -extern crate raft; - use criterion::Criterion; use std::time::Duration; diff --git a/benches/suites/progress_set.rs b/benches/suites/progress_set.rs index 3c7b4bcc0..bf310a63a 100644 --- a/benches/suites/progress_set.rs +++ b/benches/suites/progress_set.rs @@ -1,6 +1,6 @@ +use crate::DEFAULT_RAFT_SETS; use criterion::{Bencher, Criterion}; use raft::{Progress, ProgressSet}; -use DEFAULT_RAFT_SETS; pub fn bench_progress_set(c: &mut Criterion) { bench_progress_set_new(c); diff --git a/benches/suites/raft.rs b/benches/suites/raft.rs index 67214f30e..e72ecaef5 100644 --- a/benches/suites/raft.rs +++ b/benches/suites/raft.rs @@ -1,6 +1,6 @@ +use crate::DEFAULT_RAFT_SETS; use criterion::{Bencher, Criterion}; use raft::{storage::MemStorage, Config, Raft}; -use DEFAULT_RAFT_SETS; pub fn bench_raft(c: &mut Criterion) { bench_raft_new(c); diff --git a/benches/suites/raw_node.rs b/benches/suites/raw_node.rs index 917e0ed79..816b26d44 100644 --- a/benches/suites/raw_node.rs +++ b/benches/suites/raw_node.rs @@ -7,10 +7,9 @@ pub fn bench_raw_node(c: &mut Criterion) { fn quick_raw_node() -> RawNode { let id = 1; - let peers = vec![]; let storage = MemStorage::default(); let config = Config::new(id); - RawNode::new(&config, storage, peers).unwrap() + RawNode::new(&config, storage).unwrap() } pub fn bench_raw_node_new(c: &mut Criterion) { diff --git a/build.rs b/build.rs new file mode 100644 index 000000000..a3aa205ae --- /dev/null +++ b/build.rs @@ -0,0 +1,82 @@ +// Copyright 2019 PingCAP, 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, +// See the License for the specific language governing permissions and +// limitations under the License. + +use protobuf_build::*; +use std::fs::{read_dir, File}; +use std::io::Write; + +fn main() { + // This build script creates files in the `src` directory. Since that is + // outside Cargo's OUT_DIR it will cause an error when this crate is used + // as a dependency. Therefore, the user must opt-in to regenerating the + // Rust files. + if !cfg!(feature = "gen") { + println!("cargo:rerun-if-changed=build.rs"); + return; + } + + check_protoc_version(); + + let file_names: Vec<_> = read_dir("proto") + .expect("Couldn't read proto directory") + .filter_map(|e| { + let e = e.expect("Couldn't list file"); + if e.file_type().expect("File broken").is_dir() { + None + } else { + Some(format!("proto/{}", e.file_name().to_string_lossy())) + } + }) + .collect(); + + for f in &file_names { + println!("cargo:rerun-if-changed={}", f); + } + + // Generate Prost files. + generate_prost_files(&file_names, "src/prost"); + let mod_names = module_names_for_dir("src/prost"); + generate_wrappers( + &mod_names + .iter() + .map(|m| format!("src/prost/{}.rs", m)) + .collect::>(), + "src/prost", + GenOpt::All, + ); + generate_prost_rs(&mod_names); +} + +fn generate_prost_rs(mod_names: &[String]) { + let mut text = "#![allow(dead_code)]\n\ + #![allow(missing_docs)]\n\ + #![allow(clippy::all)]\n\n" + .to_owned(); + + for mod_name in mod_names { + text.push_str("pub mod "); + text.push_str(mod_name); + text.push_str("{\n"); + text.push_str("include!(\"prost/"); + text.push_str(mod_name); + text.push_str(".rs\");"); + text.push_str("include!(\"prost/wrapper_"); + text.push_str(mod_name); + text.push_str(".rs\");"); + text.push_str("}\n\n"); + } + + let mut lib = File::create("src/prost.rs").expect("Could not create prost.rs"); + lib.write_all(text.as_bytes()) + .expect("Could not write prost.rs"); +} diff --git a/examples/five_mem_node/main.rs b/examples/five_mem_node/main.rs index 34530da86..78f28372d 100644 --- a/examples/five_mem_node/main.rs +++ b/examples/five_mem_node/main.rs @@ -13,7 +13,7 @@ #[macro_use] extern crate log; extern crate env_logger; -extern crate protobuf; +extern crate prost; extern crate raft; extern crate regex; @@ -23,7 +23,8 @@ use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; use std::{str, thread}; -use protobuf::Message as PbMessage; +use prost::Message as ProstMsg; +use raft::eraftpb::ConfState; use raft::storage::MemStorage; use raft::{prelude::*, StateRole}; use regex::Regex; @@ -102,6 +103,7 @@ fn main() { add_all_followers(proposals.as_ref()); // Put 100 key-value pairs. + println!("We get a 5 nodes Raft cluster now, now propose 100 proposals"); (0..100u16) .filter(|i| { let (proposal, rx) = Proposal::normal(*i, "hello, world".to_owned()); @@ -112,6 +114,9 @@ fn main() { }) .count(); + println!("Propose 100 proposals success!"); + + // FIXME: the program will be blocked here forever. Need to exit gracefully. for th in handles { th.join().unwrap(); } @@ -136,11 +141,10 @@ impl Node { ) -> Self { let mut cfg = example_config(); cfg.id = id; - cfg.peers = vec![id]; cfg.tag = format!("peer_{}", id); - let storage = MemStorage::new(); - let raft_group = Some(RawNode::new(&cfg, storage, vec![]).unwrap()); + let storage = MemStorage::new_with_conf_state(ConfState::from((vec![id], vec![]))); + let raft_group = Some(RawNode::new(&cfg, storage).unwrap()); Node { raft_group, my_mailbox, @@ -169,8 +173,9 @@ impl Node { } let mut cfg = example_config(); cfg.id = msg.get_to(); + cfg.tag = format!("peer_{}", msg.get_to()); let storage = MemStorage::new(); - self.raft_group = Some(RawNode::new(&cfg, storage, vec![]).unwrap()); + self.raft_group = Some(RawNode::new(&cfg, storage).unwrap()); } // Step a raft message, initialize the raft if need. @@ -196,16 +201,27 @@ fn on_ready( if !raft_group.has_ready() { return; } + let store = raft_group.raft.raft_log.store.clone(); + // Get the `Ready` with `RawNode::ready` interface. let mut ready = raft_group.ready(); // Persistent raft logs. It's necessary because in `RawNode::advance` we stabilize // raft logs to the latest position. - if let Err(e) = raft_group.raft.raft_log.store.wl().append(ready.entries()) { + if let Err(e) = store.wl().append(ready.entries()) { error!("persist raft log fail: {:?}, need to retry or panic", e); return; } + // Apply the snapshot. It's necessary because in `RawNode::advance` we stabilize the snapshot. + if *ready.snapshot() != Snapshot::new_() { + let s = ready.snapshot().clone(); + if let Err(e) = store.wl().apply_snapshot(s) { + error!("apply snapshot fail: {:?}, need to retry or panic", e); + return; + } + } + // Send out the messages come from the node. for msg in ready.messages.drain(..) { let to = msg.get_to(); @@ -216,15 +232,15 @@ fn on_ready( // Apply all committed proposals. if let Some(committed_entries) = ready.committed_entries.take() { - for entry in committed_entries { + for entry in &committed_entries { if entry.get_data().is_empty() { // From new elected leaders. continue; } if let EntryType::EntryConfChange = entry.get_entry_type() { // For conf change messages, make them effective. - let mut cc = ConfChange::new(); - cc.merge_from_bytes(entry.get_data()).unwrap(); + let mut cc = ConfChange::new_(); + ProstMsg::merge(&mut cc, entry.get_data()).unwrap(); let node_id = cc.get_node_id(); match cc.get_change_type() { ConfChangeType::AddNode => raft_group.raft.add_node(node_id).unwrap(), @@ -233,6 +249,8 @@ fn on_ready( ConfChangeType::BeginMembershipChange | ConfChangeType::FinalizeMembershipChange => unimplemented!(), } + let cs = ConfState::from(raft_group.raft.prs().configuration().clone()); + store.wl().set_conf_state(cs, None); } else { // For normal proposals, extract the key-value pair and then // insert them into the kv engine. @@ -249,6 +267,11 @@ fn on_ready( proposal.propose_success.send(true).unwrap(); } } + if let Some(last_committed) = committed_entries.last() { + let mut s = store.wl(); + s.mut_hard_state().set_commit(last_committed.get_index()); + s.mut_hard_state().set_term(last_committed.get_term()); + } } // Call `RawNode::advance` interface to update position flags in the raft. raft_group.advance(ready); diff --git a/examples/single_mem_node/main.rs b/examples/single_mem_node/main.rs index 2dc002f11..2d7e1201c 100644 --- a/examples/single_mem_node/main.rs +++ b/examples/single_mem_node/main.rs @@ -11,17 +11,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -extern crate raft; +use raft; use std::collections::HashMap; use std::sync::mpsc::{self, RecvTimeoutError}; use std::thread; use std::time::{Duration, Instant}; +use raft::eraftpb::ConfState; use raft::prelude::*; use raft::storage::MemStorage; -type ProposeCallback = Box; +type ProposeCallback = Box; enum Msg { Propose { @@ -39,17 +40,12 @@ fn main() { // Create a storage for Raft, and here we just use a simple memory storage. // You need to build your own persistent storage in your production. // Please check the Storage trait in src/storage.rs to see how to implement one. - let storage = MemStorage::new(); + let storage = MemStorage::new_with_conf_state(ConfState::from((vec![1], vec![]))); // Create the configuration for the Raft node. let cfg = Config { // The unique ID for the Raft node. id: 1, - // The Raft node list. - // Mostly, the peers need to be saved in the storage - // and we can get them from the Storage::initial_state function, so here - // you need to set it empty. - peers: vec![1], // Election tick is for how long the follower may campaign again after // it doesn't receive any message from the leader. election_tick: 10, @@ -70,7 +66,7 @@ fn main() { }; // Create the Raft node. - let mut r = RawNode::new(&cfg, storage, vec![]).unwrap(); + let mut r = RawNode::new(&cfg, storage).unwrap(); let (sender, receiver) = mpsc::channel(); diff --git a/generate-proto.sh b/generate-proto.sh deleted file mode 100755 index ebe10c8cc..000000000 --- a/generate-proto.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash -protoc proto/eraftpb.proto --rust_out=src/ -# TODO: remove this once stepancheg/rust-protobuf#233 is resolved. -python < vec![], } } - - /// Initialize a raft with the given ID and peer set. - pub fn initial(&mut self, id: u64, ids: &[u64]) { - if self.raft.is_some() { - self.id = id; - let prs = self.take_prs(); - self.set_prs(ProgressSet::with_capacity( - ids.len(), - prs.learner_ids().len(), - )); - for id in ids { - let progress = Progress::new(0, 256); - if prs.learner_ids().contains(id) { - if let Err(e) = self.mut_prs().insert_learner(*id, progress) { - panic!("{}", e); - } - } else if let Err(e) = self.mut_prs().insert_voter(*id, progress) { - panic!("{}", e); - } - } - let term = self.term; - self.reset(term); - } - } } impl From>> for Interface { diff --git a/harness/src/lib.rs b/harness/src/lib.rs index 9d005e0c8..09b94cd61 100644 --- a/harness/src/lib.rs +++ b/harness/src/lib.rs @@ -33,10 +33,6 @@ This module contains various testing harness utilities for Raft. */ -extern crate env_logger; -extern crate raft; -extern crate rand; - mod interface; mod network; diff --git a/harness/src/network.rs b/harness/src/network.rs index 095a194ad..434ed247e 100644 --- a/harness/src/network.rs +++ b/harness/src/network.rs @@ -27,15 +27,18 @@ use super::interface::Interface; use raft::{ - eraftpb::{Message, MessageType}, + eraftpb::{Message, MessageType, ConfState}, storage::MemStorage, Config, Raft, Result, NO_LIMIT, }; use rand; use std::collections::HashMap; +/// A connection from one node to another. +/// +/// Used in by `Network` for determnining drop rates on messages. #[derive(Default, Debug, PartialEq, Eq, Hash)] -struct Connem { +struct Connection { from: u64, to: u64, } @@ -51,53 +54,58 @@ pub struct Network { pub peers: HashMap, /// The storage of the raft peers. pub storage: HashMap, - dropm: HashMap, + /// Drop messages from `from` to `to` at a rate of `f64`. + dropm: HashMap, + /// Drop messages of type `MessageType`. ignorem: HashMap, } impl Network { - /// Initializes a network from peers. + /// Get a base config. Calling `Network::new` will initialize peers with this config. + pub fn default_config() -> Config { + Config { + election_tick: 10, + heartbeat_tick: 1, + max_size_per_msg: NO_LIMIT, + max_inflight_msgs: 256, + ..Default::default() + } + } + + /// Initializes a network from `peers`. /// /// Nodes will recieve their ID based on their index in the vector, starting with 1. /// - /// A `None` node will be replaced with a new Raft node. + /// A `None` node will be replaced with a new Raft node, and its configuration will + /// be `peers`. pub fn new(peers: Vec>) -> Network { - Network::new_with_config(peers, false) + let config = Network::default_config(); + Network::new_with_config(peers, &config) } - /// Explicitly set the pre_vote option on newly created rafts. - /// - /// **TODO:** Make this accept any config. - pub fn new_with_config(mut peers: Vec>, pre_vote: bool) -> Network { - let size = peers.len(); - let peer_addrs: Vec = (1..=size as u64).collect(); + /// Initialize a network from `peers` with explicitly specified `config`. + pub fn new_with_config(mut peers: Vec>, config: &Config) -> Network { let mut nstorage = HashMap::new(); let mut npeers = HashMap::new(); - for (p, id) in peers.drain(..).zip(peer_addrs.clone()) { + + let peer_addrs: Vec = (1..=peers.len() as u64).collect(); + for (p, id) in peers.drain(..).zip(&peer_addrs) { match p { None => { - nstorage.insert(id, MemStorage::default()); - let r = Interface::new( - Raft::new( - &Config { - id, - peers: peer_addrs.clone(), - election_tick: 10, - heartbeat_tick: 1, - max_size_per_msg: NO_LIMIT, - max_inflight_msgs: 256, - pre_vote, - ..Default::default() - }, - nstorage[&id].clone(), - ) - .unwrap(), - ); - npeers.insert(id, r); + let conf_state = ConfState::from((peer_addrs.clone(), vec![])); + let store = MemStorage::new_with_conf_state(conf_state); + nstorage.insert(*id, store.clone()); + let mut config = config.clone(); + config.id = *id; + config.tag = format!("{}", id); + let r = Raft::new(&config, store).unwrap().into(); + npeers.insert(*id, r); } - Some(mut p) => { - p.initial(id, &peer_addrs); - npeers.insert(id, p); + Some(r) => { + if r.raft.as_ref().map_or(false, |r| r.id != *id) { + panic!("peer {} in peers has a wrong position", r.id); + } + npeers.insert(*id, r); } } } @@ -129,7 +137,7 @@ impl Network { assert_ne!(m.get_msg_type(), MessageType::MsgHup, "unexpected msgHup"); let perc = self .dropm - .get(&Connem { + .get(&Connection { from: m.get_from(), to: m.get_to(), }) @@ -180,7 +188,7 @@ impl Network { /// /// `perc` set to `1f64` is a 100% chance, `0f64` is a 0% chance. pub fn drop(&mut self, from: u64, to: u64, perc: f64) { - self.dropm.insert(Connem { from, to }, perc); + self.dropm.insert(Connection { from, to }, perc); } /// Cut the communication between the two given nodes. diff --git a/rust-toolchain b/rust-toolchain deleted file mode 100644 index 870bbe4e5..000000000 --- a/rust-toolchain +++ /dev/null @@ -1 +0,0 @@ -stable \ No newline at end of file diff --git a/src/config.rs b/src/config.rs index c5aea3399..835fb27fc 100644 --- a/src/config.rs +++ b/src/config.rs @@ -32,24 +32,11 @@ use super::{ }; /// Config contains the parameters to start a raft. +#[derive(Clone)] pub struct Config { /// The identity of the local raft. It cannot be 0, and must be unique in the group. pub id: u64, - /// The IDs of all nodes (including self) in - /// the raft cluster. It should only be set when starting a new - /// raft cluster. - /// Restarting raft from previous configuration will panic if - /// peers is set. - /// peer is private and only used for testing right now. - pub peers: Vec, - - /// The IDs of all learner nodes (maybe include self if - /// the local node is a learner) in the raft cluster. - /// learners only receives entries from the leader node. It does not vote - /// or promote itself. - pub learners: Vec, - /// The number of node.tick invocations that must pass between /// elections. That is, if a follower does not receive any message from the /// leader of current term before ElectionTick has elapsed, it will become @@ -111,6 +98,9 @@ pub struct Config { /// A human-friendly tag used for logging. pub tag: String, + + /// Batches every append msg if any append msg already exists + pub batch_append: bool, } impl Default for Config { @@ -118,8 +108,6 @@ impl Default for Config { const HEARTBEAT_TICK: usize = 2; Self { id: 0, - peers: vec![], - learners: vec![], election_tick: HEARTBEAT_TICK * 10, heartbeat_tick: HEARTBEAT_TICK, applied: 0, @@ -132,6 +120,7 @@ impl Default for Config { read_only_option: ReadOnlyOption::Safe, skip_bcast_commit: false, tag: "".into(), + batch_append: false, } } } diff --git a/src/eraftpb.rs b/src/eraftpb.rs deleted file mode 100644 index dd3008ccc..000000000 --- a/src/eraftpb.rs +++ /dev/null @@ -1,2786 +0,0 @@ -// This file is generated by rust-protobuf 2.2.2. Do not edit -// @generated - -// https://github.com/Manishearth/rust-clippy/issues/702 -#![allow(unknown_lints)] -#![allow(clippy::all)] - -#![cfg_attr(rustfmt, rustfmt_skip)] - -#![allow(box_pointers)] -#![allow(dead_code)] -#![allow(missing_docs)] -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] -#![allow(non_upper_case_globals)] -#![allow(trivial_casts)] -#![allow(unsafe_code)] -#![allow(unused_imports)] -#![allow(unused_results)] - -use protobuf::Message as Message_imported_for_functions; -use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; - -#[derive(PartialEq,Clone,Default)] -pub struct Entry { - // message fields - pub entry_type: EntryType, - pub term: u64, - pub index: u64, - pub data: ::std::vec::Vec, - pub context: ::std::vec::Vec, - pub sync_log: bool, - // special fields - pub unknown_fields: ::protobuf::UnknownFields, - pub cached_size: ::protobuf::CachedSize, -} - -impl Entry { - pub fn new() -> Entry { - ::std::default::Default::default() - } - - // .eraftpb.EntryType entry_type = 1; - - pub fn clear_entry_type(&mut self) { - self.entry_type = EntryType::EntryNormal; - } - - // Param is passed by value, moved - pub fn set_entry_type(&mut self, v: EntryType) { - self.entry_type = v; - } - - pub fn get_entry_type(&self) -> EntryType { - self.entry_type - } - - // uint64 term = 2; - - pub fn clear_term(&mut self) { - self.term = 0; - } - - // Param is passed by value, moved - pub fn set_term(&mut self, v: u64) { - self.term = v; - } - - pub fn get_term(&self) -> u64 { - self.term - } - - // uint64 index = 3; - - pub fn clear_index(&mut self) { - self.index = 0; - } - - // Param is passed by value, moved - pub fn set_index(&mut self, v: u64) { - self.index = v; - } - - pub fn get_index(&self) -> u64 { - self.index - } - - // bytes data = 4; - - pub fn clear_data(&mut self) { - self.data.clear(); - } - - // Param is passed by value, moved - pub fn set_data(&mut self, v: ::std::vec::Vec) { - self.data = v; - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_data(&mut self) -> &mut ::std::vec::Vec { - &mut self.data - } - - // Take field - pub fn take_data(&mut self) -> ::std::vec::Vec { - ::std::mem::replace(&mut self.data, ::std::vec::Vec::new()) - } - - pub fn get_data(&self) -> &[u8] { - &self.data - } - - // bytes context = 6; - - pub fn clear_context(&mut self) { - self.context.clear(); - } - - // Param is passed by value, moved - pub fn set_context(&mut self, v: ::std::vec::Vec) { - self.context = v; - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_context(&mut self) -> &mut ::std::vec::Vec { - &mut self.context - } - - // Take field - pub fn take_context(&mut self) -> ::std::vec::Vec { - ::std::mem::replace(&mut self.context, ::std::vec::Vec::new()) - } - - pub fn get_context(&self) -> &[u8] { - &self.context - } - - // bool sync_log = 5; - - pub fn clear_sync_log(&mut self) { - self.sync_log = false; - } - - // Param is passed by value, moved - pub fn set_sync_log(&mut self, v: bool) { - self.sync_log = v; - } - - pub fn get_sync_log(&self) -> bool { - self.sync_log - } -} - -impl ::protobuf::Message for Entry { - fn is_initialized(&self) -> bool { - true - } - - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { - while !is.eof()? { - let (field_number, wire_type) = is.read_tag_unpack()?; - match field_number { - 1 => { - if wire_type == ::protobuf::wire_format::WireTypeVarint {self.entry_type = is.read_enum()?;} else { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); } - }, - 2 => { - if wire_type != ::protobuf::wire_format::WireTypeVarint { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - let tmp = is.read_uint64()?; - self.term = tmp; - }, - 3 => { - if wire_type != ::protobuf::wire_format::WireTypeVarint { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - let tmp = is.read_uint64()?; - self.index = tmp; - }, - 4 => { - ::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.data)?; - }, - 6 => { - ::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.context)?; - }, - 5 => { - if wire_type != ::protobuf::wire_format::WireTypeVarint { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - let tmp = is.read_bool()?; - self.sync_log = tmp; - }, - _ => { - ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; - }, - }; - } - ::std::result::Result::Ok(()) - } - - // Compute sizes of nested messages - #[allow(unused_variables)] - fn compute_size(&self) -> u32 { - let mut my_size = 0; - if self.entry_type != EntryType::EntryNormal { - my_size += ::protobuf::rt::enum_size(1, self.entry_type); - } - if self.term != 0 { - my_size += ::protobuf::rt::value_size(2, self.term, ::protobuf::wire_format::WireTypeVarint); - } - if self.index != 0 { - my_size += ::protobuf::rt::value_size(3, self.index, ::protobuf::wire_format::WireTypeVarint); - } - if !self.data.is_empty() { - my_size += ::protobuf::rt::bytes_size(4, &self.data); - } - if !self.context.is_empty() { - my_size += ::protobuf::rt::bytes_size(6, &self.context); - } - if self.sync_log != false { - my_size += 2; - } - my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); - self.cached_size.set(my_size); - my_size - } - - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { - if self.entry_type != EntryType::EntryNormal { - os.write_enum(1, self.entry_type.value())?; - } - if self.term != 0 { - os.write_uint64(2, self.term)?; - } - if self.index != 0 { - os.write_uint64(3, self.index)?; - } - if !self.data.is_empty() { - os.write_bytes(4, &self.data)?; - } - if !self.context.is_empty() { - os.write_bytes(6, &self.context)?; - } - if self.sync_log != false { - os.write_bool(5, self.sync_log)?; - } - os.write_unknown_fields(self.get_unknown_fields())?; - ::std::result::Result::Ok(()) - } - - fn get_cached_size(&self) -> u32 { - self.cached_size.get() - } - - fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { - &self.unknown_fields - } - - fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { - &mut self.unknown_fields - } - - fn as_any(&self) -> &::std::any::Any { - self as &::std::any::Any - } - fn as_any_mut(&mut self) -> &mut ::std::any::Any { - self as &mut ::std::any::Any - } - fn into_any(self: Box) -> ::std::boxed::Box<::std::any::Any> { - self - } - - fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { - Self::descriptor_static() - } - - fn new() -> Entry { - Entry::new() - } - - fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { - static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, - }; - unsafe { - descriptor.get(|| { - let mut fields = ::std::vec::Vec::new(); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( - "entry_type", - |m: &Entry| { &m.entry_type }, - |m: &mut Entry| { &mut m.entry_type }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "term", - |m: &Entry| { &m.term }, - |m: &mut Entry| { &mut m.term }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "index", - |m: &Entry| { &m.index }, - |m: &mut Entry| { &mut m.index }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( - "data", - |m: &Entry| { &m.data }, - |m: &mut Entry| { &mut m.data }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( - "context", - |m: &Entry| { &m.context }, - |m: &mut Entry| { &mut m.context }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBool>( - "sync_log", - |m: &Entry| { &m.sync_log }, - |m: &mut Entry| { &mut m.sync_log }, - )); - ::protobuf::reflect::MessageDescriptor::new::( - "Entry", - fields, - file_descriptor_proto() - ) - }) - } - } - - fn default_instance() -> &'static Entry { - static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const Entry, - }; - unsafe { - instance.get(Entry::new) - } - } -} - -impl ::protobuf::Clear for Entry { - fn clear(&mut self) { - self.clear_entry_type(); - self.clear_term(); - self.clear_index(); - self.clear_data(); - self.clear_context(); - self.clear_sync_log(); - self.unknown_fields.clear(); - } -} - -impl ::std::fmt::Debug for Entry { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - ::protobuf::text_format::fmt(self, f) - } -} - -impl ::protobuf::reflect::ProtobufValue for Entry { - fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { - ::protobuf::reflect::ProtobufValueRef::Message(self) - } -} - -#[derive(PartialEq,Clone,Default)] -pub struct SnapshotMetadata { - // message fields - pub conf_state: ::protobuf::SingularPtrField, - pub pending_membership_change: ::protobuf::SingularPtrField, - pub pending_membership_change_index: u64, - pub index: u64, - pub term: u64, - // special fields - pub unknown_fields: ::protobuf::UnknownFields, - pub cached_size: ::protobuf::CachedSize, -} - -impl SnapshotMetadata { - pub fn new() -> SnapshotMetadata { - ::std::default::Default::default() - } - - // .eraftpb.ConfState conf_state = 1; - - pub fn clear_conf_state(&mut self) { - self.conf_state.clear(); - } - - pub fn has_conf_state(&self) -> bool { - self.conf_state.is_some() - } - - // Param is passed by value, moved - pub fn set_conf_state(&mut self, v: ConfState) { - self.conf_state = ::protobuf::SingularPtrField::some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_conf_state(&mut self) -> &mut ConfState { - if self.conf_state.is_none() { - self.conf_state.set_default(); - } - self.conf_state.as_mut().unwrap() - } - - // Take field - pub fn take_conf_state(&mut self) -> ConfState { - self.conf_state.take().unwrap_or_else(|| ConfState::new()) - } - - pub fn get_conf_state(&self) -> &ConfState { - self.conf_state.as_ref().unwrap_or_else(|| ConfState::default_instance()) - } - - // .eraftpb.ConfState pending_membership_change = 4; - - pub fn clear_pending_membership_change(&mut self) { - self.pending_membership_change.clear(); - } - - pub fn has_pending_membership_change(&self) -> bool { - self.pending_membership_change.is_some() - } - - // Param is passed by value, moved - pub fn set_pending_membership_change(&mut self, v: ConfState) { - self.pending_membership_change = ::protobuf::SingularPtrField::some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_pending_membership_change(&mut self) -> &mut ConfState { - if self.pending_membership_change.is_none() { - self.pending_membership_change.set_default(); - } - self.pending_membership_change.as_mut().unwrap() - } - - // Take field - pub fn take_pending_membership_change(&mut self) -> ConfState { - self.pending_membership_change.take().unwrap_or_else(|| ConfState::new()) - } - - pub fn get_pending_membership_change(&self) -> &ConfState { - self.pending_membership_change.as_ref().unwrap_or_else(|| ConfState::default_instance()) - } - - // uint64 pending_membership_change_index = 5; - - pub fn clear_pending_membership_change_index(&mut self) { - self.pending_membership_change_index = 0; - } - - // Param is passed by value, moved - pub fn set_pending_membership_change_index(&mut self, v: u64) { - self.pending_membership_change_index = v; - } - - pub fn get_pending_membership_change_index(&self) -> u64 { - self.pending_membership_change_index - } - - // uint64 index = 2; - - pub fn clear_index(&mut self) { - self.index = 0; - } - - // Param is passed by value, moved - pub fn set_index(&mut self, v: u64) { - self.index = v; - } - - pub fn get_index(&self) -> u64 { - self.index - } - - // uint64 term = 3; - - pub fn clear_term(&mut self) { - self.term = 0; - } - - // Param is passed by value, moved - pub fn set_term(&mut self, v: u64) { - self.term = v; - } - - pub fn get_term(&self) -> u64 { - self.term - } -} - -impl ::protobuf::Message for SnapshotMetadata { - fn is_initialized(&self) -> bool { - for v in &self.conf_state { - if !v.is_initialized() { - return false; - } - }; - for v in &self.pending_membership_change { - if !v.is_initialized() { - return false; - } - }; - true - } - - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { - while !is.eof()? { - let (field_number, wire_type) = is.read_tag_unpack()?; - match field_number { - 1 => { - ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.conf_state)?; - }, - 4 => { - ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.pending_membership_change)?; - }, - 5 => { - if wire_type != ::protobuf::wire_format::WireTypeVarint { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - let tmp = is.read_uint64()?; - self.pending_membership_change_index = tmp; - }, - 2 => { - if wire_type != ::protobuf::wire_format::WireTypeVarint { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - let tmp = is.read_uint64()?; - self.index = tmp; - }, - 3 => { - if wire_type != ::protobuf::wire_format::WireTypeVarint { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - let tmp = is.read_uint64()?; - self.term = tmp; - }, - _ => { - ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; - }, - }; - } - ::std::result::Result::Ok(()) - } - - // Compute sizes of nested messages - #[allow(unused_variables)] - fn compute_size(&self) -> u32 { - let mut my_size = 0; - if let Some(ref v) = self.conf_state.as_ref() { - let len = v.compute_size(); - my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; - } - if let Some(ref v) = self.pending_membership_change.as_ref() { - let len = v.compute_size(); - my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; - } - if self.pending_membership_change_index != 0 { - my_size += ::protobuf::rt::value_size(5, self.pending_membership_change_index, ::protobuf::wire_format::WireTypeVarint); - } - if self.index != 0 { - my_size += ::protobuf::rt::value_size(2, self.index, ::protobuf::wire_format::WireTypeVarint); - } - if self.term != 0 { - my_size += ::protobuf::rt::value_size(3, self.term, ::protobuf::wire_format::WireTypeVarint); - } - my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); - self.cached_size.set(my_size); - my_size - } - - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { - if let Some(ref v) = self.conf_state.as_ref() { - os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?; - os.write_raw_varint32(v.get_cached_size())?; - v.write_to_with_cached_sizes(os)?; - } - if let Some(ref v) = self.pending_membership_change.as_ref() { - os.write_tag(4, ::protobuf::wire_format::WireTypeLengthDelimited)?; - os.write_raw_varint32(v.get_cached_size())?; - v.write_to_with_cached_sizes(os)?; - } - if self.pending_membership_change_index != 0 { - os.write_uint64(5, self.pending_membership_change_index)?; - } - if self.index != 0 { - os.write_uint64(2, self.index)?; - } - if self.term != 0 { - os.write_uint64(3, self.term)?; - } - os.write_unknown_fields(self.get_unknown_fields())?; - ::std::result::Result::Ok(()) - } - - fn get_cached_size(&self) -> u32 { - self.cached_size.get() - } - - fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { - &self.unknown_fields - } - - fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { - &mut self.unknown_fields - } - - fn as_any(&self) -> &::std::any::Any { - self as &::std::any::Any - } - fn as_any_mut(&mut self) -> &mut ::std::any::Any { - self as &mut ::std::any::Any - } - fn into_any(self: Box) -> ::std::boxed::Box<::std::any::Any> { - self - } - - fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { - Self::descriptor_static() - } - - fn new() -> SnapshotMetadata { - SnapshotMetadata::new() - } - - fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { - static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, - }; - unsafe { - descriptor.get(|| { - let mut fields = ::std::vec::Vec::new(); - fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( - "conf_state", - |m: &SnapshotMetadata| { &m.conf_state }, - |m: &mut SnapshotMetadata| { &mut m.conf_state }, - )); - fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( - "pending_membership_change", - |m: &SnapshotMetadata| { &m.pending_membership_change }, - |m: &mut SnapshotMetadata| { &mut m.pending_membership_change }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "pending_membership_change_index", - |m: &SnapshotMetadata| { &m.pending_membership_change_index }, - |m: &mut SnapshotMetadata| { &mut m.pending_membership_change_index }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "index", - |m: &SnapshotMetadata| { &m.index }, - |m: &mut SnapshotMetadata| { &mut m.index }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "term", - |m: &SnapshotMetadata| { &m.term }, - |m: &mut SnapshotMetadata| { &mut m.term }, - )); - ::protobuf::reflect::MessageDescriptor::new::( - "SnapshotMetadata", - fields, - file_descriptor_proto() - ) - }) - } - } - - fn default_instance() -> &'static SnapshotMetadata { - static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const SnapshotMetadata, - }; - unsafe { - instance.get(SnapshotMetadata::new) - } - } -} - -impl ::protobuf::Clear for SnapshotMetadata { - fn clear(&mut self) { - self.clear_conf_state(); - self.clear_pending_membership_change(); - self.clear_pending_membership_change_index(); - self.clear_index(); - self.clear_term(); - self.unknown_fields.clear(); - } -} - -impl ::std::fmt::Debug for SnapshotMetadata { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - ::protobuf::text_format::fmt(self, f) - } -} - -impl ::protobuf::reflect::ProtobufValue for SnapshotMetadata { - fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { - ::protobuf::reflect::ProtobufValueRef::Message(self) - } -} - -#[derive(PartialEq,Clone,Default)] -pub struct Snapshot { - // message fields - pub data: ::std::vec::Vec, - pub metadata: ::protobuf::SingularPtrField, - // special fields - pub unknown_fields: ::protobuf::UnknownFields, - pub cached_size: ::protobuf::CachedSize, -} - -impl Snapshot { - pub fn new() -> Snapshot { - ::std::default::Default::default() - } - - // bytes data = 1; - - pub fn clear_data(&mut self) { - self.data.clear(); - } - - // Param is passed by value, moved - pub fn set_data(&mut self, v: ::std::vec::Vec) { - self.data = v; - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_data(&mut self) -> &mut ::std::vec::Vec { - &mut self.data - } - - // Take field - pub fn take_data(&mut self) -> ::std::vec::Vec { - ::std::mem::replace(&mut self.data, ::std::vec::Vec::new()) - } - - pub fn get_data(&self) -> &[u8] { - &self.data - } - - // .eraftpb.SnapshotMetadata metadata = 2; - - pub fn clear_metadata(&mut self) { - self.metadata.clear(); - } - - pub fn has_metadata(&self) -> bool { - self.metadata.is_some() - } - - // Param is passed by value, moved - pub fn set_metadata(&mut self, v: SnapshotMetadata) { - self.metadata = ::protobuf::SingularPtrField::some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_metadata(&mut self) -> &mut SnapshotMetadata { - if self.metadata.is_none() { - self.metadata.set_default(); - } - self.metadata.as_mut().unwrap() - } - - // Take field - pub fn take_metadata(&mut self) -> SnapshotMetadata { - self.metadata.take().unwrap_or_else(|| SnapshotMetadata::new()) - } - - pub fn get_metadata(&self) -> &SnapshotMetadata { - self.metadata.as_ref().unwrap_or_else(|| SnapshotMetadata::default_instance()) - } -} - -impl ::protobuf::Message for Snapshot { - fn is_initialized(&self) -> bool { - for v in &self.metadata { - if !v.is_initialized() { - return false; - } - }; - true - } - - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { - while !is.eof()? { - let (field_number, wire_type) = is.read_tag_unpack()?; - match field_number { - 1 => { - ::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.data)?; - }, - 2 => { - ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.metadata)?; - }, - _ => { - ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; - }, - }; - } - ::std::result::Result::Ok(()) - } - - // Compute sizes of nested messages - #[allow(unused_variables)] - fn compute_size(&self) -> u32 { - let mut my_size = 0; - if !self.data.is_empty() { - my_size += ::protobuf::rt::bytes_size(1, &self.data); - } - if let Some(ref v) = self.metadata.as_ref() { - let len = v.compute_size(); - my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; - } - my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); - self.cached_size.set(my_size); - my_size - } - - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { - if !self.data.is_empty() { - os.write_bytes(1, &self.data)?; - } - if let Some(ref v) = self.metadata.as_ref() { - os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?; - os.write_raw_varint32(v.get_cached_size())?; - v.write_to_with_cached_sizes(os)?; - } - os.write_unknown_fields(self.get_unknown_fields())?; - ::std::result::Result::Ok(()) - } - - fn get_cached_size(&self) -> u32 { - self.cached_size.get() - } - - fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { - &self.unknown_fields - } - - fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { - &mut self.unknown_fields - } - - fn as_any(&self) -> &::std::any::Any { - self as &::std::any::Any - } - fn as_any_mut(&mut self) -> &mut ::std::any::Any { - self as &mut ::std::any::Any - } - fn into_any(self: Box) -> ::std::boxed::Box<::std::any::Any> { - self - } - - fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { - Self::descriptor_static() - } - - fn new() -> Snapshot { - Snapshot::new() - } - - fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { - static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, - }; - unsafe { - descriptor.get(|| { - let mut fields = ::std::vec::Vec::new(); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( - "data", - |m: &Snapshot| { &m.data }, - |m: &mut Snapshot| { &mut m.data }, - )); - fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( - "metadata", - |m: &Snapshot| { &m.metadata }, - |m: &mut Snapshot| { &mut m.metadata }, - )); - ::protobuf::reflect::MessageDescriptor::new::( - "Snapshot", - fields, - file_descriptor_proto() - ) - }) - } - } - - fn default_instance() -> &'static Snapshot { - static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const Snapshot, - }; - unsafe { - instance.get(Snapshot::new) - } - } -} - -impl ::protobuf::Clear for Snapshot { - fn clear(&mut self) { - self.clear_data(); - self.clear_metadata(); - self.unknown_fields.clear(); - } -} - -impl ::std::fmt::Debug for Snapshot { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - ::protobuf::text_format::fmt(self, f) - } -} - -impl ::protobuf::reflect::ProtobufValue for Snapshot { - fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { - ::protobuf::reflect::ProtobufValueRef::Message(self) - } -} - -#[derive(PartialEq,Clone,Default)] -pub struct Message { - // message fields - pub msg_type: MessageType, - pub to: u64, - pub from: u64, - pub term: u64, - pub log_term: u64, - pub index: u64, - pub entries: ::protobuf::RepeatedField, - pub commit: u64, - pub snapshot: ::protobuf::SingularPtrField, - pub reject: bool, - pub reject_hint: u64, - pub context: ::std::vec::Vec, - // special fields - pub unknown_fields: ::protobuf::UnknownFields, - pub cached_size: ::protobuf::CachedSize, -} - -impl Message { - pub fn new() -> Message { - ::std::default::Default::default() - } - - // .eraftpb.MessageType msg_type = 1; - - pub fn clear_msg_type(&mut self) { - self.msg_type = MessageType::MsgHup; - } - - // Param is passed by value, moved - pub fn set_msg_type(&mut self, v: MessageType) { - self.msg_type = v; - } - - pub fn get_msg_type(&self) -> MessageType { - self.msg_type - } - - // uint64 to = 2; - - pub fn clear_to(&mut self) { - self.to = 0; - } - - // Param is passed by value, moved - pub fn set_to(&mut self, v: u64) { - self.to = v; - } - - pub fn get_to(&self) -> u64 { - self.to - } - - // uint64 from = 3; - - pub fn clear_from(&mut self) { - self.from = 0; - } - - // Param is passed by value, moved - pub fn set_from(&mut self, v: u64) { - self.from = v; - } - - pub fn get_from(&self) -> u64 { - self.from - } - - // uint64 term = 4; - - pub fn clear_term(&mut self) { - self.term = 0; - } - - // Param is passed by value, moved - pub fn set_term(&mut self, v: u64) { - self.term = v; - } - - pub fn get_term(&self) -> u64 { - self.term - } - - // uint64 log_term = 5; - - pub fn clear_log_term(&mut self) { - self.log_term = 0; - } - - // Param is passed by value, moved - pub fn set_log_term(&mut self, v: u64) { - self.log_term = v; - } - - pub fn get_log_term(&self) -> u64 { - self.log_term - } - - // uint64 index = 6; - - pub fn clear_index(&mut self) { - self.index = 0; - } - - // Param is passed by value, moved - pub fn set_index(&mut self, v: u64) { - self.index = v; - } - - pub fn get_index(&self) -> u64 { - self.index - } - - // repeated .eraftpb.Entry entries = 7; - - pub fn clear_entries(&mut self) { - self.entries.clear(); - } - - // Param is passed by value, moved - pub fn set_entries(&mut self, v: ::protobuf::RepeatedField) { - self.entries = v; - } - - // Mutable pointer to the field. - pub fn mut_entries(&mut self) -> &mut ::protobuf::RepeatedField { - &mut self.entries - } - - // Take field - pub fn take_entries(&mut self) -> ::protobuf::RepeatedField { - ::std::mem::replace(&mut self.entries, ::protobuf::RepeatedField::new()) - } - - pub fn get_entries(&self) -> &[Entry] { - &self.entries - } - - // uint64 commit = 8; - - pub fn clear_commit(&mut self) { - self.commit = 0; - } - - // Param is passed by value, moved - pub fn set_commit(&mut self, v: u64) { - self.commit = v; - } - - pub fn get_commit(&self) -> u64 { - self.commit - } - - // .eraftpb.Snapshot snapshot = 9; - - pub fn clear_snapshot(&mut self) { - self.snapshot.clear(); - } - - pub fn has_snapshot(&self) -> bool { - self.snapshot.is_some() - } - - // Param is passed by value, moved - pub fn set_snapshot(&mut self, v: Snapshot) { - self.snapshot = ::protobuf::SingularPtrField::some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_snapshot(&mut self) -> &mut Snapshot { - if self.snapshot.is_none() { - self.snapshot.set_default(); - } - self.snapshot.as_mut().unwrap() - } - - // Take field - pub fn take_snapshot(&mut self) -> Snapshot { - self.snapshot.take().unwrap_or_else(|| Snapshot::new()) - } - - pub fn get_snapshot(&self) -> &Snapshot { - self.snapshot.as_ref().unwrap_or_else(|| Snapshot::default_instance()) - } - - // bool reject = 10; - - pub fn clear_reject(&mut self) { - self.reject = false; - } - - // Param is passed by value, moved - pub fn set_reject(&mut self, v: bool) { - self.reject = v; - } - - pub fn get_reject(&self) -> bool { - self.reject - } - - // uint64 reject_hint = 11; - - pub fn clear_reject_hint(&mut self) { - self.reject_hint = 0; - } - - // Param is passed by value, moved - pub fn set_reject_hint(&mut self, v: u64) { - self.reject_hint = v; - } - - pub fn get_reject_hint(&self) -> u64 { - self.reject_hint - } - - // bytes context = 12; - - pub fn clear_context(&mut self) { - self.context.clear(); - } - - // Param is passed by value, moved - pub fn set_context(&mut self, v: ::std::vec::Vec) { - self.context = v; - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_context(&mut self) -> &mut ::std::vec::Vec { - &mut self.context - } - - // Take field - pub fn take_context(&mut self) -> ::std::vec::Vec { - ::std::mem::replace(&mut self.context, ::std::vec::Vec::new()) - } - - pub fn get_context(&self) -> &[u8] { - &self.context - } -} - -impl ::protobuf::Message for Message { - fn is_initialized(&self) -> bool { - for v in &self.entries { - if !v.is_initialized() { - return false; - } - }; - for v in &self.snapshot { - if !v.is_initialized() { - return false; - } - }; - true - } - - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { - while !is.eof()? { - let (field_number, wire_type) = is.read_tag_unpack()?; - match field_number { - 1 => { - if wire_type == ::protobuf::wire_format::WireTypeVarint {self.msg_type = is.read_enum()?;} else { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); } - }, - 2 => { - if wire_type != ::protobuf::wire_format::WireTypeVarint { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - let tmp = is.read_uint64()?; - self.to = tmp; - }, - 3 => { - if wire_type != ::protobuf::wire_format::WireTypeVarint { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - let tmp = is.read_uint64()?; - self.from = tmp; - }, - 4 => { - if wire_type != ::protobuf::wire_format::WireTypeVarint { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - let tmp = is.read_uint64()?; - self.term = tmp; - }, - 5 => { - if wire_type != ::protobuf::wire_format::WireTypeVarint { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - let tmp = is.read_uint64()?; - self.log_term = tmp; - }, - 6 => { - if wire_type != ::protobuf::wire_format::WireTypeVarint { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - let tmp = is.read_uint64()?; - self.index = tmp; - }, - 7 => { - ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.entries)?; - }, - 8 => { - if wire_type != ::protobuf::wire_format::WireTypeVarint { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - let tmp = is.read_uint64()?; - self.commit = tmp; - }, - 9 => { - ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.snapshot)?; - }, - 10 => { - if wire_type != ::protobuf::wire_format::WireTypeVarint { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - let tmp = is.read_bool()?; - self.reject = tmp; - }, - 11 => { - if wire_type != ::protobuf::wire_format::WireTypeVarint { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - let tmp = is.read_uint64()?; - self.reject_hint = tmp; - }, - 12 => { - ::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.context)?; - }, - _ => { - ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; - }, - }; - } - ::std::result::Result::Ok(()) - } - - // Compute sizes of nested messages - #[allow(unused_variables)] - fn compute_size(&self) -> u32 { - let mut my_size = 0; - if self.msg_type != MessageType::MsgHup { - my_size += ::protobuf::rt::enum_size(1, self.msg_type); - } - if self.to != 0 { - my_size += ::protobuf::rt::value_size(2, self.to, ::protobuf::wire_format::WireTypeVarint); - } - if self.from != 0 { - my_size += ::protobuf::rt::value_size(3, self.from, ::protobuf::wire_format::WireTypeVarint); - } - if self.term != 0 { - my_size += ::protobuf::rt::value_size(4, self.term, ::protobuf::wire_format::WireTypeVarint); - } - if self.log_term != 0 { - my_size += ::protobuf::rt::value_size(5, self.log_term, ::protobuf::wire_format::WireTypeVarint); - } - if self.index != 0 { - my_size += ::protobuf::rt::value_size(6, self.index, ::protobuf::wire_format::WireTypeVarint); - } - for value in &self.entries { - let len = value.compute_size(); - my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; - }; - if self.commit != 0 { - my_size += ::protobuf::rt::value_size(8, self.commit, ::protobuf::wire_format::WireTypeVarint); - } - if let Some(ref v) = self.snapshot.as_ref() { - let len = v.compute_size(); - my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; - } - if self.reject != false { - my_size += 2; - } - if self.reject_hint != 0 { - my_size += ::protobuf::rt::value_size(11, self.reject_hint, ::protobuf::wire_format::WireTypeVarint); - } - if !self.context.is_empty() { - my_size += ::protobuf::rt::bytes_size(12, &self.context); - } - my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); - self.cached_size.set(my_size); - my_size - } - - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { - if self.msg_type != MessageType::MsgHup { - os.write_enum(1, self.msg_type.value())?; - } - if self.to != 0 { - os.write_uint64(2, self.to)?; - } - if self.from != 0 { - os.write_uint64(3, self.from)?; - } - if self.term != 0 { - os.write_uint64(4, self.term)?; - } - if self.log_term != 0 { - os.write_uint64(5, self.log_term)?; - } - if self.index != 0 { - os.write_uint64(6, self.index)?; - } - for v in &self.entries { - os.write_tag(7, ::protobuf::wire_format::WireTypeLengthDelimited)?; - os.write_raw_varint32(v.get_cached_size())?; - v.write_to_with_cached_sizes(os)?; - }; - if self.commit != 0 { - os.write_uint64(8, self.commit)?; - } - if let Some(ref v) = self.snapshot.as_ref() { - os.write_tag(9, ::protobuf::wire_format::WireTypeLengthDelimited)?; - os.write_raw_varint32(v.get_cached_size())?; - v.write_to_with_cached_sizes(os)?; - } - if self.reject != false { - os.write_bool(10, self.reject)?; - } - if self.reject_hint != 0 { - os.write_uint64(11, self.reject_hint)?; - } - if !self.context.is_empty() { - os.write_bytes(12, &self.context)?; - } - os.write_unknown_fields(self.get_unknown_fields())?; - ::std::result::Result::Ok(()) - } - - fn get_cached_size(&self) -> u32 { - self.cached_size.get() - } - - fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { - &self.unknown_fields - } - - fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { - &mut self.unknown_fields - } - - fn as_any(&self) -> &::std::any::Any { - self as &::std::any::Any - } - fn as_any_mut(&mut self) -> &mut ::std::any::Any { - self as &mut ::std::any::Any - } - fn into_any(self: Box) -> ::std::boxed::Box<::std::any::Any> { - self - } - - fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { - Self::descriptor_static() - } - - fn new() -> Message { - Message::new() - } - - fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { - static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, - }; - unsafe { - descriptor.get(|| { - let mut fields = ::std::vec::Vec::new(); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( - "msg_type", - |m: &Message| { &m.msg_type }, - |m: &mut Message| { &mut m.msg_type }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "to", - |m: &Message| { &m.to }, - |m: &mut Message| { &mut m.to }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "from", - |m: &Message| { &m.from }, - |m: &mut Message| { &mut m.from }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "term", - |m: &Message| { &m.term }, - |m: &mut Message| { &mut m.term }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "log_term", - |m: &Message| { &m.log_term }, - |m: &mut Message| { &mut m.log_term }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "index", - |m: &Message| { &m.index }, - |m: &mut Message| { &mut m.index }, - )); - fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( - "entries", - |m: &Message| { &m.entries }, - |m: &mut Message| { &mut m.entries }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "commit", - |m: &Message| { &m.commit }, - |m: &mut Message| { &mut m.commit }, - )); - fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( - "snapshot", - |m: &Message| { &m.snapshot }, - |m: &mut Message| { &mut m.snapshot }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBool>( - "reject", - |m: &Message| { &m.reject }, - |m: &mut Message| { &mut m.reject }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "reject_hint", - |m: &Message| { &m.reject_hint }, - |m: &mut Message| { &mut m.reject_hint }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( - "context", - |m: &Message| { &m.context }, - |m: &mut Message| { &mut m.context }, - )); - ::protobuf::reflect::MessageDescriptor::new::( - "Message", - fields, - file_descriptor_proto() - ) - }) - } - } - - fn default_instance() -> &'static Message { - static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const Message, - }; - unsafe { - instance.get(Message::new) - } - } -} - -impl ::protobuf::Clear for Message { - fn clear(&mut self) { - self.clear_msg_type(); - self.clear_to(); - self.clear_from(); - self.clear_term(); - self.clear_log_term(); - self.clear_index(); - self.clear_entries(); - self.clear_commit(); - self.clear_snapshot(); - self.clear_reject(); - self.clear_reject_hint(); - self.clear_context(); - self.unknown_fields.clear(); - } -} - -impl ::std::fmt::Debug for Message { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - ::protobuf::text_format::fmt(self, f) - } -} - -impl ::protobuf::reflect::ProtobufValue for Message { - fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { - ::protobuf::reflect::ProtobufValueRef::Message(self) - } -} - -#[derive(PartialEq,Clone,Default)] -pub struct HardState { - // message fields - pub term: u64, - pub vote: u64, - pub commit: u64, - // special fields - pub unknown_fields: ::protobuf::UnknownFields, - pub cached_size: ::protobuf::CachedSize, -} - -impl HardState { - pub fn new() -> HardState { - ::std::default::Default::default() - } - - // uint64 term = 1; - - pub fn clear_term(&mut self) { - self.term = 0; - } - - // Param is passed by value, moved - pub fn set_term(&mut self, v: u64) { - self.term = v; - } - - pub fn get_term(&self) -> u64 { - self.term - } - - // uint64 vote = 2; - - pub fn clear_vote(&mut self) { - self.vote = 0; - } - - // Param is passed by value, moved - pub fn set_vote(&mut self, v: u64) { - self.vote = v; - } - - pub fn get_vote(&self) -> u64 { - self.vote - } - - // uint64 commit = 3; - - pub fn clear_commit(&mut self) { - self.commit = 0; - } - - // Param is passed by value, moved - pub fn set_commit(&mut self, v: u64) { - self.commit = v; - } - - pub fn get_commit(&self) -> u64 { - self.commit - } -} - -impl ::protobuf::Message for HardState { - fn is_initialized(&self) -> bool { - true - } - - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { - while !is.eof()? { - let (field_number, wire_type) = is.read_tag_unpack()?; - match field_number { - 1 => { - if wire_type != ::protobuf::wire_format::WireTypeVarint { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - let tmp = is.read_uint64()?; - self.term = tmp; - }, - 2 => { - if wire_type != ::protobuf::wire_format::WireTypeVarint { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - let tmp = is.read_uint64()?; - self.vote = tmp; - }, - 3 => { - if wire_type != ::protobuf::wire_format::WireTypeVarint { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - let tmp = is.read_uint64()?; - self.commit = tmp; - }, - _ => { - ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; - }, - }; - } - ::std::result::Result::Ok(()) - } - - // Compute sizes of nested messages - #[allow(unused_variables)] - fn compute_size(&self) -> u32 { - let mut my_size = 0; - if self.term != 0 { - my_size += ::protobuf::rt::value_size(1, self.term, ::protobuf::wire_format::WireTypeVarint); - } - if self.vote != 0 { - my_size += ::protobuf::rt::value_size(2, self.vote, ::protobuf::wire_format::WireTypeVarint); - } - if self.commit != 0 { - my_size += ::protobuf::rt::value_size(3, self.commit, ::protobuf::wire_format::WireTypeVarint); - } - my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); - self.cached_size.set(my_size); - my_size - } - - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { - if self.term != 0 { - os.write_uint64(1, self.term)?; - } - if self.vote != 0 { - os.write_uint64(2, self.vote)?; - } - if self.commit != 0 { - os.write_uint64(3, self.commit)?; - } - os.write_unknown_fields(self.get_unknown_fields())?; - ::std::result::Result::Ok(()) - } - - fn get_cached_size(&self) -> u32 { - self.cached_size.get() - } - - fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { - &self.unknown_fields - } - - fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { - &mut self.unknown_fields - } - - fn as_any(&self) -> &::std::any::Any { - self as &::std::any::Any - } - fn as_any_mut(&mut self) -> &mut ::std::any::Any { - self as &mut ::std::any::Any - } - fn into_any(self: Box) -> ::std::boxed::Box<::std::any::Any> { - self - } - - fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { - Self::descriptor_static() - } - - fn new() -> HardState { - HardState::new() - } - - fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { - static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, - }; - unsafe { - descriptor.get(|| { - let mut fields = ::std::vec::Vec::new(); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "term", - |m: &HardState| { &m.term }, - |m: &mut HardState| { &mut m.term }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "vote", - |m: &HardState| { &m.vote }, - |m: &mut HardState| { &mut m.vote }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "commit", - |m: &HardState| { &m.commit }, - |m: &mut HardState| { &mut m.commit }, - )); - ::protobuf::reflect::MessageDescriptor::new::( - "HardState", - fields, - file_descriptor_proto() - ) - }) - } - } - - fn default_instance() -> &'static HardState { - static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const HardState, - }; - unsafe { - instance.get(HardState::new) - } - } -} - -impl ::protobuf::Clear for HardState { - fn clear(&mut self) { - self.clear_term(); - self.clear_vote(); - self.clear_commit(); - self.unknown_fields.clear(); - } -} - -impl ::std::fmt::Debug for HardState { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - ::protobuf::text_format::fmt(self, f) - } -} - -impl ::protobuf::reflect::ProtobufValue for HardState { - fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { - ::protobuf::reflect::ProtobufValueRef::Message(self) - } -} - -#[derive(PartialEq,Clone,Default)] -pub struct ConfState { - // message fields - pub nodes: ::std::vec::Vec, - pub learners: ::std::vec::Vec, - // special fields - pub unknown_fields: ::protobuf::UnknownFields, - pub cached_size: ::protobuf::CachedSize, -} - -impl ConfState { - pub fn new() -> ConfState { - ::std::default::Default::default() - } - - // repeated uint64 nodes = 1; - - pub fn clear_nodes(&mut self) { - self.nodes.clear(); - } - - // Param is passed by value, moved - pub fn set_nodes(&mut self, v: ::std::vec::Vec) { - self.nodes = v; - } - - // Mutable pointer to the field. - pub fn mut_nodes(&mut self) -> &mut ::std::vec::Vec { - &mut self.nodes - } - - // Take field - pub fn take_nodes(&mut self) -> ::std::vec::Vec { - ::std::mem::replace(&mut self.nodes, ::std::vec::Vec::new()) - } - - pub fn get_nodes(&self) -> &[u64] { - &self.nodes - } - - // repeated uint64 learners = 2; - - pub fn clear_learners(&mut self) { - self.learners.clear(); - } - - // Param is passed by value, moved - pub fn set_learners(&mut self, v: ::std::vec::Vec) { - self.learners = v; - } - - // Mutable pointer to the field. - pub fn mut_learners(&mut self) -> &mut ::std::vec::Vec { - &mut self.learners - } - - // Take field - pub fn take_learners(&mut self) -> ::std::vec::Vec { - ::std::mem::replace(&mut self.learners, ::std::vec::Vec::new()) - } - - pub fn get_learners(&self) -> &[u64] { - &self.learners - } -} - -impl ::protobuf::Message for ConfState { - fn is_initialized(&self) -> bool { - true - } - - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { - while !is.eof()? { - let (field_number, wire_type) = is.read_tag_unpack()?; - match field_number { - 1 => { - ::protobuf::rt::read_repeated_uint64_into(wire_type, is, &mut self.nodes)?; - }, - 2 => { - ::protobuf::rt::read_repeated_uint64_into(wire_type, is, &mut self.learners)?; - }, - _ => { - ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; - }, - }; - } - ::std::result::Result::Ok(()) - } - - // Compute sizes of nested messages - #[allow(unused_variables)] - fn compute_size(&self) -> u32 { - let mut my_size = 0; - for value in &self.nodes { - my_size += ::protobuf::rt::value_size(1, *value, ::protobuf::wire_format::WireTypeVarint); - }; - for value in &self.learners { - my_size += ::protobuf::rt::value_size(2, *value, ::protobuf::wire_format::WireTypeVarint); - }; - my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); - self.cached_size.set(my_size); - my_size - } - - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { - for v in &self.nodes { - os.write_uint64(1, *v)?; - }; - for v in &self.learners { - os.write_uint64(2, *v)?; - }; - os.write_unknown_fields(self.get_unknown_fields())?; - ::std::result::Result::Ok(()) - } - - fn get_cached_size(&self) -> u32 { - self.cached_size.get() - } - - fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { - &self.unknown_fields - } - - fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { - &mut self.unknown_fields - } - - fn as_any(&self) -> &::std::any::Any { - self as &::std::any::Any - } - fn as_any_mut(&mut self) -> &mut ::std::any::Any { - self as &mut ::std::any::Any - } - fn into_any(self: Box) -> ::std::boxed::Box<::std::any::Any> { - self - } - - fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { - Self::descriptor_static() - } - - fn new() -> ConfState { - ConfState::new() - } - - fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { - static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, - }; - unsafe { - descriptor.get(|| { - let mut fields = ::std::vec::Vec::new(); - fields.push(::protobuf::reflect::accessor::make_vec_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "nodes", - |m: &ConfState| { &m.nodes }, - |m: &mut ConfState| { &mut m.nodes }, - )); - fields.push(::protobuf::reflect::accessor::make_vec_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "learners", - |m: &ConfState| { &m.learners }, - |m: &mut ConfState| { &mut m.learners }, - )); - ::protobuf::reflect::MessageDescriptor::new::( - "ConfState", - fields, - file_descriptor_proto() - ) - }) - } - } - - fn default_instance() -> &'static ConfState { - static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ConfState, - }; - unsafe { - instance.get(ConfState::new) - } - } -} - -impl ::protobuf::Clear for ConfState { - fn clear(&mut self) { - self.clear_nodes(); - self.clear_learners(); - self.unknown_fields.clear(); - } -} - -impl ::std::fmt::Debug for ConfState { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - ::protobuf::text_format::fmt(self, f) - } -} - -impl ::protobuf::reflect::ProtobufValue for ConfState { - fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { - ::protobuf::reflect::ProtobufValueRef::Message(self) - } -} - -#[derive(PartialEq,Clone,Default)] -pub struct ConfChange { - // message fields - pub id: u64, - pub change_type: ConfChangeType, - pub node_id: u64, - pub context: ::std::vec::Vec, - pub configuration: ::protobuf::SingularPtrField, - pub start_index: u64, - // special fields - pub unknown_fields: ::protobuf::UnknownFields, - pub cached_size: ::protobuf::CachedSize, -} - -impl ConfChange { - pub fn new() -> ConfChange { - ::std::default::Default::default() - } - - // uint64 id = 1; - - pub fn clear_id(&mut self) { - self.id = 0; - } - - // Param is passed by value, moved - pub fn set_id(&mut self, v: u64) { - self.id = v; - } - - pub fn get_id(&self) -> u64 { - self.id - } - - // .eraftpb.ConfChangeType change_type = 2; - - pub fn clear_change_type(&mut self) { - self.change_type = ConfChangeType::AddNode; - } - - // Param is passed by value, moved - pub fn set_change_type(&mut self, v: ConfChangeType) { - self.change_type = v; - } - - pub fn get_change_type(&self) -> ConfChangeType { - self.change_type - } - - // uint64 node_id = 3; - - pub fn clear_node_id(&mut self) { - self.node_id = 0; - } - - // Param is passed by value, moved - pub fn set_node_id(&mut self, v: u64) { - self.node_id = v; - } - - pub fn get_node_id(&self) -> u64 { - self.node_id - } - - // bytes context = 4; - - pub fn clear_context(&mut self) { - self.context.clear(); - } - - // Param is passed by value, moved - pub fn set_context(&mut self, v: ::std::vec::Vec) { - self.context = v; - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_context(&mut self) -> &mut ::std::vec::Vec { - &mut self.context - } - - // Take field - pub fn take_context(&mut self) -> ::std::vec::Vec { - ::std::mem::replace(&mut self.context, ::std::vec::Vec::new()) - } - - pub fn get_context(&self) -> &[u8] { - &self.context - } - - // .eraftpb.ConfState configuration = 5; - - pub fn clear_configuration(&mut self) { - self.configuration.clear(); - } - - pub fn has_configuration(&self) -> bool { - self.configuration.is_some() - } - - // Param is passed by value, moved - pub fn set_configuration(&mut self, v: ConfState) { - self.configuration = ::protobuf::SingularPtrField::some(v); - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_configuration(&mut self) -> &mut ConfState { - if self.configuration.is_none() { - self.configuration.set_default(); - } - self.configuration.as_mut().unwrap() - } - - // Take field - pub fn take_configuration(&mut self) -> ConfState { - self.configuration.take().unwrap_or_else(|| ConfState::new()) - } - - pub fn get_configuration(&self) -> &ConfState { - self.configuration.as_ref().unwrap_or_else(|| ConfState::default_instance()) - } - - // uint64 start_index = 6; - - pub fn clear_start_index(&mut self) { - self.start_index = 0; - } - - // Param is passed by value, moved - pub fn set_start_index(&mut self, v: u64) { - self.start_index = v; - } - - pub fn get_start_index(&self) -> u64 { - self.start_index - } -} - -impl ::protobuf::Message for ConfChange { - fn is_initialized(&self) -> bool { - for v in &self.configuration { - if !v.is_initialized() { - return false; - } - }; - true - } - - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { - while !is.eof()? { - let (field_number, wire_type) = is.read_tag_unpack()?; - match field_number { - 1 => { - if wire_type != ::protobuf::wire_format::WireTypeVarint { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - let tmp = is.read_uint64()?; - self.id = tmp; - }, - 2 => { - if wire_type == ::protobuf::wire_format::WireTypeVarint {self.change_type = is.read_enum()?;} else { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); } - }, - 3 => { - if wire_type != ::protobuf::wire_format::WireTypeVarint { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - let tmp = is.read_uint64()?; - self.node_id = tmp; - }, - 4 => { - ::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.context)?; - }, - 5 => { - ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.configuration)?; - }, - 6 => { - if wire_type != ::protobuf::wire_format::WireTypeVarint { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - let tmp = is.read_uint64()?; - self.start_index = tmp; - }, - _ => { - ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; - }, - }; - } - ::std::result::Result::Ok(()) - } - - // Compute sizes of nested messages - #[allow(unused_variables)] - fn compute_size(&self) -> u32 { - let mut my_size = 0; - if self.id != 0 { - my_size += ::protobuf::rt::value_size(1, self.id, ::protobuf::wire_format::WireTypeVarint); - } - if self.change_type != ConfChangeType::AddNode { - my_size += ::protobuf::rt::enum_size(2, self.change_type); - } - if self.node_id != 0 { - my_size += ::protobuf::rt::value_size(3, self.node_id, ::protobuf::wire_format::WireTypeVarint); - } - if !self.context.is_empty() { - my_size += ::protobuf::rt::bytes_size(4, &self.context); - } - if let Some(ref v) = self.configuration.as_ref() { - let len = v.compute_size(); - my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; - } - if self.start_index != 0 { - my_size += ::protobuf::rt::value_size(6, self.start_index, ::protobuf::wire_format::WireTypeVarint); - } - my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); - self.cached_size.set(my_size); - my_size - } - - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { - if self.id != 0 { - os.write_uint64(1, self.id)?; - } - if self.change_type != ConfChangeType::AddNode { - os.write_enum(2, self.change_type.value())?; - } - if self.node_id != 0 { - os.write_uint64(3, self.node_id)?; - } - if !self.context.is_empty() { - os.write_bytes(4, &self.context)?; - } - if let Some(ref v) = self.configuration.as_ref() { - os.write_tag(5, ::protobuf::wire_format::WireTypeLengthDelimited)?; - os.write_raw_varint32(v.get_cached_size())?; - v.write_to_with_cached_sizes(os)?; - } - if self.start_index != 0 { - os.write_uint64(6, self.start_index)?; - } - os.write_unknown_fields(self.get_unknown_fields())?; - ::std::result::Result::Ok(()) - } - - fn get_cached_size(&self) -> u32 { - self.cached_size.get() - } - - fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { - &self.unknown_fields - } - - fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { - &mut self.unknown_fields - } - - fn as_any(&self) -> &::std::any::Any { - self as &::std::any::Any - } - fn as_any_mut(&mut self) -> &mut ::std::any::Any { - self as &mut ::std::any::Any - } - fn into_any(self: Box) -> ::std::boxed::Box<::std::any::Any> { - self - } - - fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { - Self::descriptor_static() - } - - fn new() -> ConfChange { - ConfChange::new() - } - - fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { - static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, - }; - unsafe { - descriptor.get(|| { - let mut fields = ::std::vec::Vec::new(); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "id", - |m: &ConfChange| { &m.id }, - |m: &mut ConfChange| { &mut m.id }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( - "change_type", - |m: &ConfChange| { &m.change_type }, - |m: &mut ConfChange| { &mut m.change_type }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "node_id", - |m: &ConfChange| { &m.node_id }, - |m: &mut ConfChange| { &mut m.node_id }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( - "context", - |m: &ConfChange| { &m.context }, - |m: &mut ConfChange| { &mut m.context }, - )); - fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( - "configuration", - |m: &ConfChange| { &m.configuration }, - |m: &mut ConfChange| { &mut m.configuration }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "start_index", - |m: &ConfChange| { &m.start_index }, - |m: &mut ConfChange| { &mut m.start_index }, - )); - ::protobuf::reflect::MessageDescriptor::new::( - "ConfChange", - fields, - file_descriptor_proto() - ) - }) - } - } - - fn default_instance() -> &'static ConfChange { - static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ConfChange, - }; - unsafe { - instance.get(ConfChange::new) - } - } -} - -impl ::protobuf::Clear for ConfChange { - fn clear(&mut self) { - self.clear_id(); - self.clear_change_type(); - self.clear_node_id(); - self.clear_context(); - self.clear_configuration(); - self.clear_start_index(); - self.unknown_fields.clear(); - } -} - -impl ::std::fmt::Debug for ConfChange { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - ::protobuf::text_format::fmt(self, f) - } -} - -impl ::protobuf::reflect::ProtobufValue for ConfChange { - fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { - ::protobuf::reflect::ProtobufValueRef::Message(self) - } -} - -#[derive(Clone,PartialEq,Eq,Debug,Hash)] -pub enum EntryType { - EntryNormal = 0, - EntryConfChange = 1, -} - -impl ::protobuf::ProtobufEnum for EntryType { - fn value(&self) -> i32 { - *self as i32 - } - - fn from_i32(value: i32) -> ::std::option::Option { - match value { - 0 => ::std::option::Option::Some(EntryType::EntryNormal), - 1 => ::std::option::Option::Some(EntryType::EntryConfChange), - _ => ::std::option::Option::None - } - } - - fn values() -> &'static [Self] { - static values: &'static [EntryType] = &[ - EntryType::EntryNormal, - EntryType::EntryConfChange, - ]; - values - } - - fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor { - static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::EnumDescriptor> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::reflect::EnumDescriptor, - }; - unsafe { - descriptor.get(|| { - ::protobuf::reflect::EnumDescriptor::new("EntryType", file_descriptor_proto()) - }) - } - } -} - -impl ::std::marker::Copy for EntryType { -} - -impl ::std::default::Default for EntryType { - fn default() -> Self { - EntryType::EntryNormal - } -} - -impl ::protobuf::reflect::ProtobufValue for EntryType { - fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { - ::protobuf::reflect::ProtobufValueRef::Enum(self.descriptor()) - } -} - -#[derive(Clone,PartialEq,Eq,Debug,Hash)] -pub enum MessageType { - MsgHup = 0, - MsgBeat = 1, - MsgPropose = 2, - MsgAppend = 3, - MsgAppendResponse = 4, - MsgRequestVote = 5, - MsgRequestVoteResponse = 6, - MsgSnapshot = 7, - MsgHeartbeat = 8, - MsgHeartbeatResponse = 9, - MsgUnreachable = 10, - MsgSnapStatus = 11, - MsgCheckQuorum = 12, - MsgTransferLeader = 13, - MsgTimeoutNow = 14, - MsgReadIndex = 15, - MsgReadIndexResp = 16, - MsgRequestPreVote = 17, - MsgRequestPreVoteResponse = 18, -} - -impl ::protobuf::ProtobufEnum for MessageType { - fn value(&self) -> i32 { - *self as i32 - } - - fn from_i32(value: i32) -> ::std::option::Option { - match value { - 0 => ::std::option::Option::Some(MessageType::MsgHup), - 1 => ::std::option::Option::Some(MessageType::MsgBeat), - 2 => ::std::option::Option::Some(MessageType::MsgPropose), - 3 => ::std::option::Option::Some(MessageType::MsgAppend), - 4 => ::std::option::Option::Some(MessageType::MsgAppendResponse), - 5 => ::std::option::Option::Some(MessageType::MsgRequestVote), - 6 => ::std::option::Option::Some(MessageType::MsgRequestVoteResponse), - 7 => ::std::option::Option::Some(MessageType::MsgSnapshot), - 8 => ::std::option::Option::Some(MessageType::MsgHeartbeat), - 9 => ::std::option::Option::Some(MessageType::MsgHeartbeatResponse), - 10 => ::std::option::Option::Some(MessageType::MsgUnreachable), - 11 => ::std::option::Option::Some(MessageType::MsgSnapStatus), - 12 => ::std::option::Option::Some(MessageType::MsgCheckQuorum), - 13 => ::std::option::Option::Some(MessageType::MsgTransferLeader), - 14 => ::std::option::Option::Some(MessageType::MsgTimeoutNow), - 15 => ::std::option::Option::Some(MessageType::MsgReadIndex), - 16 => ::std::option::Option::Some(MessageType::MsgReadIndexResp), - 17 => ::std::option::Option::Some(MessageType::MsgRequestPreVote), - 18 => ::std::option::Option::Some(MessageType::MsgRequestPreVoteResponse), - _ => ::std::option::Option::None - } - } - - fn values() -> &'static [Self] { - static values: &'static [MessageType] = &[ - MessageType::MsgHup, - MessageType::MsgBeat, - MessageType::MsgPropose, - MessageType::MsgAppend, - MessageType::MsgAppendResponse, - MessageType::MsgRequestVote, - MessageType::MsgRequestVoteResponse, - MessageType::MsgSnapshot, - MessageType::MsgHeartbeat, - MessageType::MsgHeartbeatResponse, - MessageType::MsgUnreachable, - MessageType::MsgSnapStatus, - MessageType::MsgCheckQuorum, - MessageType::MsgTransferLeader, - MessageType::MsgTimeoutNow, - MessageType::MsgReadIndex, - MessageType::MsgReadIndexResp, - MessageType::MsgRequestPreVote, - MessageType::MsgRequestPreVoteResponse, - ]; - values - } - - fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor { - static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::EnumDescriptor> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::reflect::EnumDescriptor, - }; - unsafe { - descriptor.get(|| { - ::protobuf::reflect::EnumDescriptor::new("MessageType", file_descriptor_proto()) - }) - } - } -} - -impl ::std::marker::Copy for MessageType { -} - -impl ::std::default::Default for MessageType { - fn default() -> Self { - MessageType::MsgHup - } -} - -impl ::protobuf::reflect::ProtobufValue for MessageType { - fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { - ::protobuf::reflect::ProtobufValueRef::Enum(self.descriptor()) - } -} - -#[derive(Clone,PartialEq,Eq,Debug,Hash)] -pub enum ConfChangeType { - AddNode = 0, - RemoveNode = 1, - AddLearnerNode = 2, - BeginMembershipChange = 3, - FinalizeMembershipChange = 4, -} - -impl ::protobuf::ProtobufEnum for ConfChangeType { - fn value(&self) -> i32 { - *self as i32 - } - - fn from_i32(value: i32) -> ::std::option::Option { - match value { - 0 => ::std::option::Option::Some(ConfChangeType::AddNode), - 1 => ::std::option::Option::Some(ConfChangeType::RemoveNode), - 2 => ::std::option::Option::Some(ConfChangeType::AddLearnerNode), - 3 => ::std::option::Option::Some(ConfChangeType::BeginMembershipChange), - 4 => ::std::option::Option::Some(ConfChangeType::FinalizeMembershipChange), - _ => ::std::option::Option::None - } - } - - fn values() -> &'static [Self] { - static values: &'static [ConfChangeType] = &[ - ConfChangeType::AddNode, - ConfChangeType::RemoveNode, - ConfChangeType::AddLearnerNode, - ConfChangeType::BeginMembershipChange, - ConfChangeType::FinalizeMembershipChange, - ]; - values - } - - fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor { - static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::EnumDescriptor> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::reflect::EnumDescriptor, - }; - unsafe { - descriptor.get(|| { - ::protobuf::reflect::EnumDescriptor::new("ConfChangeType", file_descriptor_proto()) - }) - } - } -} - -impl ::std::marker::Copy for ConfChangeType { -} - -impl ::std::default::Default for ConfChangeType { - fn default() -> Self { - ConfChangeType::AddNode - } -} - -impl ::protobuf::reflect::ProtobufValue for ConfChangeType { - fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { - ::protobuf::reflect::ProtobufValueRef::Enum(self.descriptor()) - } -} - -static file_descriptor_proto_data: &'static [u8] = b"\ - \n\x13proto/eraftpb.proto\x12\x07eraftpb\"\xad\x01\n\x05Entry\x121\n\nen\ - try_type\x18\x01\x20\x01(\x0e2\x12.eraftpb.EntryTypeR\tentryType\x12\x12\ - \n\x04term\x18\x02\x20\x01(\x04R\x04term\x12\x14\n\x05index\x18\x03\x20\ - \x01(\x04R\x05index\x12\x12\n\x04data\x18\x04\x20\x01(\x0cR\x04data\x12\ - \x18\n\x07context\x18\x06\x20\x01(\x0cR\x07context\x12\x19\n\x08sync_log\ - \x18\x05\x20\x01(\x08R\x07syncLog\"\x86\x02\n\x10SnapshotMetadata\x121\n\ - \nconf_state\x18\x01\x20\x01(\x0b2\x12.eraftpb.ConfStateR\tconfState\x12\ - N\n\x19pending_membership_change\x18\x04\x20\x01(\x0b2\x12.eraftpb.ConfS\ - tateR\x17pendingMembershipChange\x12E\n\x1fpending_membership_change_ind\ - ex\x18\x05\x20\x01(\x04R\x1cpendingMembershipChangeIndex\x12\x14\n\x05in\ - dex\x18\x02\x20\x01(\x04R\x05index\x12\x12\n\x04term\x18\x03\x20\x01(\ - \x04R\x04term\"U\n\x08Snapshot\x12\x12\n\x04data\x18\x01\x20\x01(\x0cR\ - \x04data\x125\n\x08metadata\x18\x02\x20\x01(\x0b2\x19.eraftpb.SnapshotMe\ - tadataR\x08metadata\"\xe7\x02\n\x07Message\x12/\n\x08msg_type\x18\x01\ - \x20\x01(\x0e2\x14.eraftpb.MessageTypeR\x07msgType\x12\x0e\n\x02to\x18\ - \x02\x20\x01(\x04R\x02to\x12\x12\n\x04from\x18\x03\x20\x01(\x04R\x04from\ - \x12\x12\n\x04term\x18\x04\x20\x01(\x04R\x04term\x12\x19\n\x08log_term\ - \x18\x05\x20\x01(\x04R\x07logTerm\x12\x14\n\x05index\x18\x06\x20\x01(\ - \x04R\x05index\x12(\n\x07entries\x18\x07\x20\x03(\x0b2\x0e.eraftpb.Entry\ - R\x07entries\x12\x16\n\x06commit\x18\x08\x20\x01(\x04R\x06commit\x12-\n\ - \x08snapshot\x18\t\x20\x01(\x0b2\x11.eraftpb.SnapshotR\x08snapshot\x12\ - \x16\n\x06reject\x18\n\x20\x01(\x08R\x06reject\x12\x1f\n\x0breject_hint\ - \x18\x0b\x20\x01(\x04R\nrejectHint\x12\x18\n\x07context\x18\x0c\x20\x01(\ - \x0cR\x07context\"K\n\tHardState\x12\x12\n\x04term\x18\x01\x20\x01(\x04R\ - \x04term\x12\x12\n\x04vote\x18\x02\x20\x01(\x04R\x04vote\x12\x16\n\x06co\ - mmit\x18\x03\x20\x01(\x04R\x06commit\"=\n\tConfState\x12\x14\n\x05nodes\ - \x18\x01\x20\x03(\x04R\x05nodes\x12\x1a\n\x08learners\x18\x02\x20\x03(\ - \x04R\x08learners\"\xe4\x01\n\nConfChange\x12\x0e\n\x02id\x18\x01\x20\ - \x01(\x04R\x02id\x128\n\x0bchange_type\x18\x02\x20\x01(\x0e2\x17.eraftpb\ - .ConfChangeTypeR\nchangeType\x12\x17\n\x07node_id\x18\x03\x20\x01(\x04R\ - \x06nodeId\x12\x18\n\x07context\x18\x04\x20\x01(\x0cR\x07context\x128\n\ - \rconfiguration\x18\x05\x20\x01(\x0b2\x12.eraftpb.ConfStateR\rconfigurat\ - ion\x12\x1f\n\x0bstart_index\x18\x06\x20\x01(\x04R\nstartIndex*1\n\tEntr\ - yType\x12\x0f\n\x0bEntryNormal\x10\0\x12\x13\n\x0fEntryConfChange\x10\ - \x01*\x8c\x03\n\x0bMessageType\x12\n\n\x06MsgHup\x10\0\x12\x0b\n\x07MsgB\ - eat\x10\x01\x12\x0e\n\nMsgPropose\x10\x02\x12\r\n\tMsgAppend\x10\x03\x12\ - \x15\n\x11MsgAppendResponse\x10\x04\x12\x12\n\x0eMsgRequestVote\x10\x05\ - \x12\x1a\n\x16MsgRequestVoteResponse\x10\x06\x12\x0f\n\x0bMsgSnapshot\ - \x10\x07\x12\x10\n\x0cMsgHeartbeat\x10\x08\x12\x18\n\x14MsgHeartbeatResp\ - onse\x10\t\x12\x12\n\x0eMsgUnreachable\x10\n\x12\x11\n\rMsgSnapStatus\ - \x10\x0b\x12\x12\n\x0eMsgCheckQuorum\x10\x0c\x12\x15\n\x11MsgTransferLea\ - der\x10\r\x12\x11\n\rMsgTimeoutNow\x10\x0e\x12\x10\n\x0cMsgReadIndex\x10\ - \x0f\x12\x14\n\x10MsgReadIndexResp\x10\x10\x12\x15\n\x11MsgRequestPreVot\ - e\x10\x11\x12\x1d\n\x19MsgRequestPreVoteResponse\x10\x12*z\n\x0eConfChan\ - geType\x12\x0b\n\x07AddNode\x10\0\x12\x0e\n\nRemoveNode\x10\x01\x12\x12\ - \n\x0eAddLearnerNode\x10\x02\x12\x19\n\x15BeginMembershipChange\x10\x03\ - \x12\x1c\n\x18FinalizeMembershipChange\x10\x04J\x84&\n\x06\x12\x04\0\0o\ - \x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\x08\n\x01\x02\x12\x03\x01\x08\x0f\ - \n\n\n\x02\x05\0\x12\x04\x03\0\x06\x01\n\n\n\x03\x05\0\x01\x12\x03\x03\ - \x05\x0e\n\x0b\n\x04\x05\0\x02\0\x12\x03\x04\x04\x14\n\x0c\n\x05\x05\0\ - \x02\0\x01\x12\x03\x04\x04\x0f\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x04\ - \x12\x13\n\x0b\n\x04\x05\0\x02\x01\x12\x03\x05\x04\x18\n\x0c\n\x05\x05\0\ - \x02\x01\x01\x12\x03\x05\x04\x13\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\ - \x05\x16\x17\n\xdd\x04\n\x02\x04\0\x12\x04\x12\0\x1c\x01\x1a\xd0\x04\x20\ - The\x20entry\x20is\x20a\x20type\x20of\x20change\x20that\x20needs\x20to\ - \x20be\x20applied.\x20It\x20contains\x20two\x20data\x20fields.\n\x20Whil\ - e\x20the\x20fields\x20are\x20built\x20into\x20the\x20model;\x20their\x20\ - usage\x20is\x20determined\x20by\x20the\x20entry_type.\n\n\x20For\x20norm\ - al\x20entries,\x20the\x20data\x20field\x20should\x20contain\x20the\x20da\ - ta\x20change\x20that\x20should\x20be\x20applied.\n\x20The\x20context\x20\ - field\x20can\x20be\x20used\x20for\x20any\x20contextual\x20data\x20that\ - \x20might\x20be\x20relevant\x20to\x20the\n\x20application\x20of\x20the\ - \x20data.\n\n\x20For\x20configuration\x20changes,\x20the\x20data\x20will\ - \x20contain\x20the\x20ConfChange\x20message\x20and\x20the\n\x20context\ - \x20will\x20provide\x20anything\x20needed\x20to\x20assist\x20the\x20conf\ - iguration\x20change.\x20The\x20context\n\x20if\x20for\x20the\x20user\x20\ - to\x20set\x20and\x20use\x20in\x20this\x20case.\n\n\n\n\x03\x04\0\x01\x12\ - \x03\x12\x08\r\n\x0b\n\x04\x04\0\x02\0\x12\x03\x13\x04\x1d\n\r\n\x05\x04\ - \0\x02\0\x04\x12\x04\x13\x04\x12\x0f\n\x0c\n\x05\x04\0\x02\0\x06\x12\x03\ - \x13\x04\r\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x13\x0e\x18\n\x0c\n\x05\ - \x04\0\x02\0\x03\x12\x03\x13\x1b\x1c\n\x0b\n\x04\x04\0\x02\x01\x12\x03\ - \x14\x04\x14\n\r\n\x05\x04\0\x02\x01\x04\x12\x04\x14\x04\x13\x1d\n\x0c\n\ - \x05\x04\0\x02\x01\x05\x12\x03\x14\x04\n\n\x0c\n\x05\x04\0\x02\x01\x01\ - \x12\x03\x14\x0b\x0f\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x14\x12\x13\n\ - \x0b\n\x04\x04\0\x02\x02\x12\x03\x15\x04\x15\n\r\n\x05\x04\0\x02\x02\x04\ - \x12\x04\x15\x04\x14\x14\n\x0c\n\x05\x04\0\x02\x02\x05\x12\x03\x15\x04\n\ - \n\x0c\n\x05\x04\0\x02\x02\x01\x12\x03\x15\x0b\x10\n\x0c\n\x05\x04\0\x02\ - \x02\x03\x12\x03\x15\x13\x14\n\x0b\n\x04\x04\0\x02\x03\x12\x03\x16\x04\ - \x13\n\r\n\x05\x04\0\x02\x03\x04\x12\x04\x16\x04\x15\x15\n\x0c\n\x05\x04\ - \0\x02\x03\x05\x12\x03\x16\x04\t\n\x0c\n\x05\x04\0\x02\x03\x01\x12\x03\ - \x16\n\x0e\n\x0c\n\x05\x04\0\x02\x03\x03\x12\x03\x16\x11\x12\n\x0b\n\x04\ - \x04\0\x02\x04\x12\x03\x17\x04\x16\n\r\n\x05\x04\0\x02\x04\x04\x12\x04\ - \x17\x04\x16\x13\n\x0c\n\x05\x04\0\x02\x04\x05\x12\x03\x17\x04\t\n\x0c\n\ - \x05\x04\0\x02\x04\x01\x12\x03\x17\n\x11\n\x0c\n\x05\x04\0\x02\x04\x03\ - \x12\x03\x17\x14\x15\nm\n\x04\x04\0\x02\x05\x12\x03\x1b\x04\x16\x1a`\x20\ - Deprecated!\x20It\x20is\x20kept\x20for\x20backward\x20compatibility.\n\ - \x20TODO:\x20remove\x20it\x20in\x20the\x20next\x20major\x20release.\n\n\ - \r\n\x05\x04\0\x02\x05\x04\x12\x04\x1b\x04\x17\x16\n\x0c\n\x05\x04\0\x02\ - \x05\x05\x12\x03\x1b\x04\x08\n\x0c\n\x05\x04\0\x02\x05\x01\x12\x03\x1b\t\ - \x11\n\x0c\n\x05\x04\0\x02\x05\x03\x12\x03\x1b\x14\x15\n\n\n\x02\x04\x01\ - \x12\x04\x1e\0$\x01\n\n\n\x03\x04\x01\x01\x12\x03\x1e\x08\x18\n\x0b\n\ - \x04\x04\x01\x02\0\x12\x03\x1f\x04\x1d\n\r\n\x05\x04\x01\x02\0\x04\x12\ - \x04\x1f\x04\x1e\x1a\n\x0c\n\x05\x04\x01\x02\0\x06\x12\x03\x1f\x04\r\n\ - \x0c\n\x05\x04\x01\x02\0\x01\x12\x03\x1f\x0e\x18\n\x0c\n\x05\x04\x01\x02\ - \0\x03\x12\x03\x1f\x1b\x1c\n\x0b\n\x04\x04\x01\x02\x01\x12\x03\x20\x04,\ - \n\r\n\x05\x04\x01\x02\x01\x04\x12\x04\x20\x04\x1f\x1d\n\x0c\n\x05\x04\ - \x01\x02\x01\x06\x12\x03\x20\x04\r\n\x0c\n\x05\x04\x01\x02\x01\x01\x12\ - \x03\x20\x0e'\n\x0c\n\x05\x04\x01\x02\x01\x03\x12\x03\x20*+\n\x0b\n\x04\ - \x04\x01\x02\x02\x12\x03!\x04/\n\r\n\x05\x04\x01\x02\x02\x04\x12\x04!\ - \x04\x20,\n\x0c\n\x05\x04\x01\x02\x02\x05\x12\x03!\x04\n\n\x0c\n\x05\x04\ - \x01\x02\x02\x01\x12\x03!\x0b*\n\x0c\n\x05\x04\x01\x02\x02\x03\x12\x03!-\ - .\n\x0b\n\x04\x04\x01\x02\x03\x12\x03\"\x04\x15\n\r\n\x05\x04\x01\x02\ - \x03\x04\x12\x04\"\x04!/\n\x0c\n\x05\x04\x01\x02\x03\x05\x12\x03\"\x04\n\ - \n\x0c\n\x05\x04\x01\x02\x03\x01\x12\x03\"\x0b\x10\n\x0c\n\x05\x04\x01\ - \x02\x03\x03\x12\x03\"\x13\x14\n\x0b\n\x04\x04\x01\x02\x04\x12\x03#\x04\ - \x14\n\r\n\x05\x04\x01\x02\x04\x04\x12\x04#\x04\"\x15\n\x0c\n\x05\x04\ - \x01\x02\x04\x05\x12\x03#\x04\n\n\x0c\n\x05\x04\x01\x02\x04\x01\x12\x03#\ - \x0b\x0f\n\x0c\n\x05\x04\x01\x02\x04\x03\x12\x03#\x12\x13\n\n\n\x02\x04\ - \x02\x12\x04&\0)\x01\n\n\n\x03\x04\x02\x01\x12\x03&\x08\x10\n\x0b\n\x04\ - \x04\x02\x02\0\x12\x03'\x04\x13\n\r\n\x05\x04\x02\x02\0\x04\x12\x04'\x04\ - &\x12\n\x0c\n\x05\x04\x02\x02\0\x05\x12\x03'\x04\t\n\x0c\n\x05\x04\x02\ - \x02\0\x01\x12\x03'\n\x0e\n\x0c\n\x05\x04\x02\x02\0\x03\x12\x03'\x11\x12\ - \n\x0b\n\x04\x04\x02\x02\x01\x12\x03(\x04\"\n\r\n\x05\x04\x02\x02\x01\ - \x04\x12\x04(\x04'\x13\n\x0c\n\x05\x04\x02\x02\x01\x06\x12\x03(\x04\x14\ - \n\x0c\n\x05\x04\x02\x02\x01\x01\x12\x03(\x15\x1d\n\x0c\n\x05\x04\x02\ - \x02\x01\x03\x12\x03(\x20!\n\n\n\x02\x05\x01\x12\x04+\0?\x01\n\n\n\x03\ - \x05\x01\x01\x12\x03+\x05\x10\n\x0b\n\x04\x05\x01\x02\0\x12\x03,\x04\x0f\ - \n\x0c\n\x05\x05\x01\x02\0\x01\x12\x03,\x04\n\n\x0c\n\x05\x05\x01\x02\0\ - \x02\x12\x03,\r\x0e\n\x0b\n\x04\x05\x01\x02\x01\x12\x03-\x04\x10\n\x0c\n\ - \x05\x05\x01\x02\x01\x01\x12\x03-\x04\x0b\n\x0c\n\x05\x05\x01\x02\x01\ - \x02\x12\x03-\x0e\x0f\n\x0b\n\x04\x05\x01\x02\x02\x12\x03.\x04\x13\n\x0c\ - \n\x05\x05\x01\x02\x02\x01\x12\x03.\x04\x0e\n\x0c\n\x05\x05\x01\x02\x02\ - \x02\x12\x03.\x11\x12\n\x0b\n\x04\x05\x01\x02\x03\x12\x03/\x04\x12\n\x0c\ - \n\x05\x05\x01\x02\x03\x01\x12\x03/\x04\r\n\x0c\n\x05\x05\x01\x02\x03\ - \x02\x12\x03/\x10\x11\n\x0b\n\x04\x05\x01\x02\x04\x12\x030\x04\x1a\n\x0c\ - \n\x05\x05\x01\x02\x04\x01\x12\x030\x04\x15\n\x0c\n\x05\x05\x01\x02\x04\ - \x02\x12\x030\x18\x19\n\x0b\n\x04\x05\x01\x02\x05\x12\x031\x04\x17\n\x0c\ - \n\x05\x05\x01\x02\x05\x01\x12\x031\x04\x12\n\x0c\n\x05\x05\x01\x02\x05\ - \x02\x12\x031\x15\x16\n\x0b\n\x04\x05\x01\x02\x06\x12\x032\x04\x1f\n\x0c\ - \n\x05\x05\x01\x02\x06\x01\x12\x032\x04\x1a\n\x0c\n\x05\x05\x01\x02\x06\ - \x02\x12\x032\x1d\x1e\n\x0b\n\x04\x05\x01\x02\x07\x12\x033\x04\x14\n\x0c\ - \n\x05\x05\x01\x02\x07\x01\x12\x033\x04\x0f\n\x0c\n\x05\x05\x01\x02\x07\ - \x02\x12\x033\x12\x13\n\x0b\n\x04\x05\x01\x02\x08\x12\x034\x04\x15\n\x0c\ - \n\x05\x05\x01\x02\x08\x01\x12\x034\x04\x10\n\x0c\n\x05\x05\x01\x02\x08\ - \x02\x12\x034\x13\x14\n\x0b\n\x04\x05\x01\x02\t\x12\x035\x04\x1d\n\x0c\n\ - \x05\x05\x01\x02\t\x01\x12\x035\x04\x18\n\x0c\n\x05\x05\x01\x02\t\x02\ - \x12\x035\x1b\x1c\n\x0b\n\x04\x05\x01\x02\n\x12\x036\x04\x18\n\x0c\n\x05\ - \x05\x01\x02\n\x01\x12\x036\x04\x12\n\x0c\n\x05\x05\x01\x02\n\x02\x12\ - \x036\x15\x17\n\x0b\n\x04\x05\x01\x02\x0b\x12\x037\x04\x17\n\x0c\n\x05\ - \x05\x01\x02\x0b\x01\x12\x037\x04\x11\n\x0c\n\x05\x05\x01\x02\x0b\x02\ - \x12\x037\x14\x16\n\x0b\n\x04\x05\x01\x02\x0c\x12\x038\x04\x18\n\x0c\n\ - \x05\x05\x01\x02\x0c\x01\x12\x038\x04\x12\n\x0c\n\x05\x05\x01\x02\x0c\ - \x02\x12\x038\x15\x17\n\x0b\n\x04\x05\x01\x02\r\x12\x039\x04\x1b\n\x0c\n\ - \x05\x05\x01\x02\r\x01\x12\x039\x04\x15\n\x0c\n\x05\x05\x01\x02\r\x02\ - \x12\x039\x18\x1a\n\x0b\n\x04\x05\x01\x02\x0e\x12\x03:\x04\x17\n\x0c\n\ - \x05\x05\x01\x02\x0e\x01\x12\x03:\x04\x11\n\x0c\n\x05\x05\x01\x02\x0e\ - \x02\x12\x03:\x14\x16\n\x0b\n\x04\x05\x01\x02\x0f\x12\x03;\x04\x16\n\x0c\ - \n\x05\x05\x01\x02\x0f\x01\x12\x03;\x04\x10\n\x0c\n\x05\x05\x01\x02\x0f\ - \x02\x12\x03;\x13\x15\n\x0b\n\x04\x05\x01\x02\x10\x12\x03<\x04\x1a\n\x0c\ - \n\x05\x05\x01\x02\x10\x01\x12\x03<\x04\x14\n\x0c\n\x05\x05\x01\x02\x10\ - \x02\x12\x03<\x17\x19\n\x0b\n\x04\x05\x01\x02\x11\x12\x03=\x04\x1b\n\x0c\ - \n\x05\x05\x01\x02\x11\x01\x12\x03=\x04\x15\n\x0c\n\x05\x05\x01\x02\x11\ - \x02\x12\x03=\x18\x1a\n\x0b\n\x04\x05\x01\x02\x12\x12\x03>\x04#\n\x0c\n\ - \x05\x05\x01\x02\x12\x01\x12\x03>\x04\x1d\n\x0c\n\x05\x05\x01\x02\x12\ - \x02\x12\x03>\x20\"\n\n\n\x02\x04\x03\x12\x04A\0N\x01\n\n\n\x03\x04\x03\ - \x01\x12\x03A\x08\x0f\n\x0b\n\x04\x04\x03\x02\0\x12\x03B\x04\x1d\n\r\n\ - \x05\x04\x03\x02\0\x04\x12\x04B\x04A\x11\n\x0c\n\x05\x04\x03\x02\0\x06\ - \x12\x03B\x04\x0f\n\x0c\n\x05\x04\x03\x02\0\x01\x12\x03B\x10\x18\n\x0c\n\ - \x05\x04\x03\x02\0\x03\x12\x03B\x1b\x1c\n\x0b\n\x04\x04\x03\x02\x01\x12\ - \x03C\x04\x12\n\r\n\x05\x04\x03\x02\x01\x04\x12\x04C\x04B\x1d\n\x0c\n\ - \x05\x04\x03\x02\x01\x05\x12\x03C\x04\n\n\x0c\n\x05\x04\x03\x02\x01\x01\ - \x12\x03C\x0b\r\n\x0c\n\x05\x04\x03\x02\x01\x03\x12\x03C\x10\x11\n\x0b\n\ - \x04\x04\x03\x02\x02\x12\x03D\x04\x14\n\r\n\x05\x04\x03\x02\x02\x04\x12\ - \x04D\x04C\x12\n\x0c\n\x05\x04\x03\x02\x02\x05\x12\x03D\x04\n\n\x0c\n\ - \x05\x04\x03\x02\x02\x01\x12\x03D\x0b\x0f\n\x0c\n\x05\x04\x03\x02\x02\ - \x03\x12\x03D\x12\x13\n\x0b\n\x04\x04\x03\x02\x03\x12\x03E\x04\x14\n\r\n\ - \x05\x04\x03\x02\x03\x04\x12\x04E\x04D\x14\n\x0c\n\x05\x04\x03\x02\x03\ - \x05\x12\x03E\x04\n\n\x0c\n\x05\x04\x03\x02\x03\x01\x12\x03E\x0b\x0f\n\ - \x0c\n\x05\x04\x03\x02\x03\x03\x12\x03E\x12\x13\n\x0b\n\x04\x04\x03\x02\ - \x04\x12\x03F\x04\x18\n\r\n\x05\x04\x03\x02\x04\x04\x12\x04F\x04E\x14\n\ - \x0c\n\x05\x04\x03\x02\x04\x05\x12\x03F\x04\n\n\x0c\n\x05\x04\x03\x02\ - \x04\x01\x12\x03F\x0b\x13\n\x0c\n\x05\x04\x03\x02\x04\x03\x12\x03F\x16\ - \x17\n\x0b\n\x04\x04\x03\x02\x05\x12\x03G\x04\x15\n\r\n\x05\x04\x03\x02\ - \x05\x04\x12\x04G\x04F\x18\n\x0c\n\x05\x04\x03\x02\x05\x05\x12\x03G\x04\ - \n\n\x0c\n\x05\x04\x03\x02\x05\x01\x12\x03G\x0b\x10\n\x0c\n\x05\x04\x03\ - \x02\x05\x03\x12\x03G\x13\x14\n\x0b\n\x04\x04\x03\x02\x06\x12\x03H\x04\ - \x1f\n\x0c\n\x05\x04\x03\x02\x06\x04\x12\x03H\x04\x0c\n\x0c\n\x05\x04\ - \x03\x02\x06\x06\x12\x03H\r\x12\n\x0c\n\x05\x04\x03\x02\x06\x01\x12\x03H\ - \x13\x1a\n\x0c\n\x05\x04\x03\x02\x06\x03\x12\x03H\x1d\x1e\n\x0b\n\x04\ - \x04\x03\x02\x07\x12\x03I\x04\x16\n\r\n\x05\x04\x03\x02\x07\x04\x12\x04I\ - \x04H\x1f\n\x0c\n\x05\x04\x03\x02\x07\x05\x12\x03I\x04\n\n\x0c\n\x05\x04\ - \x03\x02\x07\x01\x12\x03I\x0b\x11\n\x0c\n\x05\x04\x03\x02\x07\x03\x12\ - \x03I\x14\x15\n\x0b\n\x04\x04\x03\x02\x08\x12\x03J\x04\x1a\n\r\n\x05\x04\ - \x03\x02\x08\x04\x12\x04J\x04I\x16\n\x0c\n\x05\x04\x03\x02\x08\x06\x12\ - \x03J\x04\x0c\n\x0c\n\x05\x04\x03\x02\x08\x01\x12\x03J\r\x15\n\x0c\n\x05\ - \x04\x03\x02\x08\x03\x12\x03J\x18\x19\n\x0b\n\x04\x04\x03\x02\t\x12\x03K\ - \x04\x15\n\r\n\x05\x04\x03\x02\t\x04\x12\x04K\x04J\x1a\n\x0c\n\x05\x04\ - \x03\x02\t\x05\x12\x03K\x04\x08\n\x0c\n\x05\x04\x03\x02\t\x01\x12\x03K\t\ - \x0f\n\x0c\n\x05\x04\x03\x02\t\x03\x12\x03K\x12\x14\n\x0b\n\x04\x04\x03\ - \x02\n\x12\x03L\x04\x1c\n\r\n\x05\x04\x03\x02\n\x04\x12\x04L\x04K\x15\n\ - \x0c\n\x05\x04\x03\x02\n\x05\x12\x03L\x04\n\n\x0c\n\x05\x04\x03\x02\n\ - \x01\x12\x03L\x0b\x16\n\x0c\n\x05\x04\x03\x02\n\x03\x12\x03L\x19\x1b\n\ - \x0b\n\x04\x04\x03\x02\x0b\x12\x03M\x04\x17\n\r\n\x05\x04\x03\x02\x0b\ - \x04\x12\x04M\x04L\x1c\n\x0c\n\x05\x04\x03\x02\x0b\x05\x12\x03M\x04\t\n\ - \x0c\n\x05\x04\x03\x02\x0b\x01\x12\x03M\n\x11\n\x0c\n\x05\x04\x03\x02\ - \x0b\x03\x12\x03M\x14\x16\n\n\n\x02\x04\x04\x12\x04P\0T\x01\n\n\n\x03\ - \x04\x04\x01\x12\x03P\x08\x11\n\x0b\n\x04\x04\x04\x02\0\x12\x03Q\x04\x14\ - \n\r\n\x05\x04\x04\x02\0\x04\x12\x04Q\x04P\x13\n\x0c\n\x05\x04\x04\x02\0\ - \x05\x12\x03Q\x04\n\n\x0c\n\x05\x04\x04\x02\0\x01\x12\x03Q\x0b\x0f\n\x0c\ - \n\x05\x04\x04\x02\0\x03\x12\x03Q\x12\x13\n\x0b\n\x04\x04\x04\x02\x01\ - \x12\x03R\x04\x14\n\r\n\x05\x04\x04\x02\x01\x04\x12\x04R\x04Q\x14\n\x0c\ - \n\x05\x04\x04\x02\x01\x05\x12\x03R\x04\n\n\x0c\n\x05\x04\x04\x02\x01\ - \x01\x12\x03R\x0b\x0f\n\x0c\n\x05\x04\x04\x02\x01\x03\x12\x03R\x12\x13\n\ - \x0b\n\x04\x04\x04\x02\x02\x12\x03S\x04\x16\n\r\n\x05\x04\x04\x02\x02\ - \x04\x12\x04S\x04R\x14\n\x0c\n\x05\x04\x04\x02\x02\x05\x12\x03S\x04\n\n\ - \x0c\n\x05\x04\x04\x02\x02\x01\x12\x03S\x0b\x11\n\x0c\n\x05\x04\x04\x02\ - \x02\x03\x12\x03S\x14\x15\n\n\n\x02\x04\x05\x12\x04V\0Y\x01\n\n\n\x03\ - \x04\x05\x01\x12\x03V\x08\x11\n\x0b\n\x04\x04\x05\x02\0\x12\x03W\x04\x1e\ - \n\x0c\n\x05\x04\x05\x02\0\x04\x12\x03W\x04\x0c\n\x0c\n\x05\x04\x05\x02\ - \0\x05\x12\x03W\r\x13\n\x0c\n\x05\x04\x05\x02\0\x01\x12\x03W\x14\x19\n\ - \x0c\n\x05\x04\x05\x02\0\x03\x12\x03W\x1c\x1d\n\x0b\n\x04\x04\x05\x02\ - \x01\x12\x03X\x04!\n\x0c\n\x05\x04\x05\x02\x01\x04\x12\x03X\x04\x0c\n\ - \x0c\n\x05\x04\x05\x02\x01\x05\x12\x03X\r\x13\n\x0c\n\x05\x04\x05\x02\ - \x01\x01\x12\x03X\x14\x1c\n\x0c\n\x05\x04\x05\x02\x01\x03\x12\x03X\x1f\ - \x20\n\n\n\x02\x05\x02\x12\x04[\0a\x01\n\n\n\x03\x05\x02\x01\x12\x03[\ - \x05\x13\n\x0b\n\x04\x05\x02\x02\0\x12\x03\\\x04\x13\n\x0c\n\x05\x05\x02\ - \x02\0\x01\x12\x03\\\x04\x0b\n\x0c\n\x05\x05\x02\x02\0\x02\x12\x03\\\x11\ - \x12\n\x0b\n\x04\x05\x02\x02\x01\x12\x03]\x04\x13\n\x0c\n\x05\x05\x02\ - \x02\x01\x01\x12\x03]\x04\x0e\n\x0c\n\x05\x05\x02\x02\x01\x02\x12\x03]\ - \x11\x12\n\x0b\n\x04\x05\x02\x02\x02\x12\x03^\x04\x17\n\x0c\n\x05\x05\ - \x02\x02\x02\x01\x12\x03^\x04\x12\n\x0c\n\x05\x05\x02\x02\x02\x02\x12\ - \x03^\x15\x16\n\x0b\n\x04\x05\x02\x02\x03\x12\x03_\x04\x1e\n\x0c\n\x05\ - \x05\x02\x02\x03\x01\x12\x03_\x04\x19\n\x0c\n\x05\x05\x02\x02\x03\x02\ - \x12\x03_\x1c\x1d\n\x0b\n\x04\x05\x02\x02\x04\x12\x03`\x04!\n\x0c\n\x05\ - \x05\x02\x02\x04\x01\x12\x03`\x04\x1c\n\x0c\n\x05\x05\x02\x02\x04\x02\ - \x12\x03`\x1f\x20\n\n\n\x02\x04\x06\x12\x04c\0o\x01\n\n\n\x03\x04\x06\ - \x01\x12\x03c\x08\x12\n\x0b\n\x04\x04\x06\x02\0\x12\x03d\x04\x12\n\r\n\ - \x05\x04\x06\x02\0\x04\x12\x04d\x04c\x14\n\x0c\n\x05\x04\x06\x02\0\x05\ - \x12\x03d\x04\n\n\x0c\n\x05\x04\x06\x02\0\x01\x12\x03d\x0b\r\n\x0c\n\x05\ - \x04\x06\x02\0\x03\x12\x03d\x10\x11\n\x0b\n\x04\x04\x06\x02\x01\x12\x03e\ - \x04#\n\r\n\x05\x04\x06\x02\x01\x04\x12\x04e\x04d\x12\n\x0c\n\x05\x04\ - \x06\x02\x01\x06\x12\x03e\x04\x12\n\x0c\n\x05\x04\x06\x02\x01\x01\x12\ - \x03e\x13\x1e\n\x0c\n\x05\x04\x06\x02\x01\x03\x12\x03e!\"\nE\n\x04\x04\ - \x06\x02\x02\x12\x03g\x04\x17\x1a8\x20Used\x20in\x20`AddNode`,\x20`Remov\ - eNode`,\x20and\x20`AddLearnerNode`.\n\n\r\n\x05\x04\x06\x02\x02\x04\x12\ - \x04g\x04e#\n\x0c\n\x05\x04\x06\x02\x02\x05\x12\x03g\x04\n\n\x0c\n\x05\ - \x04\x06\x02\x02\x01\x12\x03g\x0b\x12\n\x0c\n\x05\x04\x06\x02\x02\x03\ - \x12\x03g\x15\x16\n\x0b\n\x04\x04\x06\x02\x03\x12\x03h\x04\x16\n\r\n\x05\ - \x04\x06\x02\x03\x04\x12\x04h\x04g\x17\n\x0c\n\x05\x04\x06\x02\x03\x05\ - \x12\x03h\x04\t\n\x0c\n\x05\x04\x06\x02\x03\x01\x12\x03h\n\x11\n\x0c\n\ - \x05\x04\x06\x02\x03\x03\x12\x03h\x14\x15\nN\n\x04\x04\x06\x02\x04\x12\ - \x03j\x04\x20\x1aA\x20Used\x20in\x20`BeginMembershipChange`\x20and\x20`F\ - inalizeMembershipChange`.\n\n\r\n\x05\x04\x06\x02\x04\x04\x12\x04j\x04h\ - \x16\n\x0c\n\x05\x04\x06\x02\x04\x06\x12\x03j\x04\r\n\x0c\n\x05\x04\x06\ - \x02\x04\x01\x12\x03j\x0e\x1b\n\x0c\n\x05\x04\x06\x02\x04\x03\x12\x03j\ - \x1e\x1f\n\xd0\x01\n\x04\x04\x06\x02\x05\x12\x03n\x04\x1b\x1a\xc2\x01\ - \x20Used\x20in\x20`BeginMembershipChange`\x20and\x20`FinalizeMembershipC\ - hange`.\n\x20Because\x20`RawNode::apply_conf_change`\x20takes\x20a\x20`C\ - onfChange`\x20instead\x20of\x20an\x20`Entry`\x20we\x20must\n\x20include\ - \x20this\x20index\x20so\x20it\x20can\x20be\x20known.\n\n\r\n\x05\x04\x06\ - \x02\x05\x04\x12\x04n\x04j\x20\n\x0c\n\x05\x04\x06\x02\x05\x05\x12\x03n\ - \x04\n\n\x0c\n\x05\x04\x06\x02\x05\x01\x12\x03n\x0b\x16\n\x0c\n\x05\x04\ - \x06\x02\x05\x03\x12\x03n\x19\x1ab\x06proto3\ -"; - -static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::descriptor::FileDescriptorProto, -}; - -fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { - ::protobuf::parse_from_bytes(file_descriptor_proto_data).unwrap() -} - -pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { - unsafe { - file_descriptor_proto_lazy.get(|| { - parse_descriptor_proto() - }) - } -} diff --git a/src/errors.rs b/src/errors.rs index 3d73dd26e..f8e8c3bad 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -11,11 +11,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +use crate::StateRole; use std::error; use std::{cmp, io, result}; -use StateRole; -use protobuf::ProtobufError; +use prost::{DecodeError, EncodeError}; quick_error! { /// The base error type for raft @@ -49,12 +49,19 @@ quick_error! { ConfigInvalid(desc: String) { description(desc) } - /// A Protobuf message failed in some manner. - Codec(err: ProtobufError) { + /// A Prost message encode failed in some manner. + ProstEncode(err: EncodeError) { from() cause(err) description(err.description()) - display("protobuf error {:?}", err) + display("prost encode error {:?}", err) + } + /// A Prost message decode failed in some manner. + ProstDecode(err: DecodeError) { + from() + cause(err) + description(err.description()) + display("prost decode error {:?}", err) } /// The node exists, but should not. Exists(id: u64, set: &'static str) { @@ -115,7 +122,7 @@ quick_error! { description("snapshot is temporarily unavailable") } /// Some other error occurred. - Other(err: Box) { + Other(err: Box) { from() cause(err.as_ref()) description(err.description()) @@ -182,10 +189,6 @@ mod tests { Error::StepPeerNotFound, Error::Store(StorageError::Compacted) ); - assert_ne!( - Error::Codec(ProtobufError::MessageNotInitialized { message: "" }), - Error::StepLocalMsg - ); } #[test] diff --git a/src/lib.rs b/src/lib.rs index 281844197..d28a0a665 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,16 +44,15 @@ use raft::{ // Select some defaults, then change what we need. let config = Config { id: 1, - peers: vec![1], ..Default::default() }; -let storage = MemStorage::default(); // ... Make any configuration changes. // After, make sure it's valid! config.validate().unwrap(); // We'll use the built-in `MemStorage`, but you will likely want your own. // Finally, create our Raft node! -let mut node = RawNode::new(&config, storage, vec![]).unwrap(); +let storage = MemStorage::new_with_conf_state((vec![1], vec![])); +let mut node = RawNode::new(&config, storage).unwrap(); // We will coax it into being the lead of a single node cluster for exploration. node.raft.become_candidate(); node.raft.become_leader(); @@ -67,8 +66,9 @@ channel `recv_timeout` to drive the Raft node at least every 100ms, calling ```rust # use raft::{Config, storage::MemStorage, raw_node::RawNode}; -# let config = Config { id: 1, peers: vec![1], ..Default::default() }; -# let mut node = RawNode::new(&config, MemStorage::default(), vec![]).unwrap(); +# let config = Config { id: 1, ..Default::default() }; +# let store = MemStorage::new_with_conf_state((vec![1], vec![])); +# let mut node = RawNode::new(&config, store).unwrap(); # node.raft.become_candidate(); # node.raft.become_leader(); use std::{sync::mpsc::{channel, RecvTimeoutError}, time::{Instant, Duration}}; @@ -131,8 +131,9 @@ Here is a simple example to use `propose` and `step`: # collections::HashMap # }; # -# let config = Config { id: 1, peers: vec![1], ..Default::default() }; -# let mut node = RawNode::new(&config, MemStorage::default(), vec![]).unwrap(); +# let config = Config { id: 1, ..Default::default() }; +# let store = MemStorage::new_with_conf_state((vec![1], vec![])); +# let mut node = RawNode::new(&config, store).unwrap(); # node.raft.become_candidate(); # node.raft.become_leader(); # @@ -315,9 +316,11 @@ This must be done as a two stage process for now. This means it's possible to do: ```rust -use raft::{Config, storage::MemStorage, raw_node::RawNode, eraftpb::{Message, ConfChange}}; -let config = Config { id: 1, peers: vec![1, 2], ..Default::default() }; -let mut node = RawNode::new(&config, MemStorage::default(), vec![]).unwrap(); +use raft::{Config, storage::MemStorage, raw_node::RawNode, eraftpb::*}; +use prost::Message as ProstMsg; +let mut config = Config { id: 1, ..Default::default() }; +let store = MemStorage::new_with_conf_state((vec![1, 2], vec![])); +let mut node = RawNode::new(&mut config, store).unwrap(); node.raft.become_candidate(); node.raft.become_leader(); @@ -329,11 +332,11 @@ node.raft.propose_membership_change(( // Learners vec![4,5,6], // Add 4, 5, 6. )).unwrap(); +# let idx = node.raft.raft_log.last_index(); -# let entry = &node.raft.raft_log.entries(2, 1).unwrap()[0]; +# let entry = &node.raft.raft_log.entries(idx, 1).unwrap()[0]; // ...Later when the begin entry is recieved from a `ready()` in the `entries` field... -let conf_change = protobuf::parse_from_bytes::(entry.get_data()) - .unwrap(); +let conf_change = ConfChange::decode(entry.get_data()).unwrap(); node.raft.begin_membership_change(&conf_change).unwrap(); assert!(node.raft.is_in_membership_change()); assert!(node.raft.prs().voter_ids().contains(&2)); @@ -341,13 +344,13 @@ assert!(node.raft.prs().voter_ids().contains(&3)); # # // We hide this since the user isn't really encouraged to blindly call this, but we'd like a short # // example. -# node.raft.raft_log.commit_to(2); -# node.raft.commit_apply(2); +# node.raft.raft_log.commit_to(idx); +# node.raft.commit_apply(idx); # -# let entry = &node.raft.raft_log.entries(3, 1).unwrap()[0]; +# let idx = node.raft.raft_log.last_index(); +# let entry = &node.raft.raft_log.entries(idx, 1).unwrap()[0]; // ...Later, when the finalize entry is recieved from a `ready()` in the `entries` field... -let conf_change = protobuf::parse_from_bytes::(entry.get_data()) - .unwrap(); +let conf_change = ConfChange::decode(entry.get_data()).unwrap(); node.raft.finalize_membership_change(&conf_change).unwrap(); assert!(!node.raft.prs().voter_ids().contains(&2)); assert!(node.raft.prs().voter_ids().contains(&3)); @@ -365,26 +368,24 @@ before taking old, removed peers offline. #![deny(clippy::all)] #![deny(missing_docs)] +#![recursion_limit = "128"] #[cfg(feature = "failpoint")] #[macro_use] extern crate fail; -#[cfg(test)] -extern crate harness; -extern crate hashbrown; + #[macro_use] extern crate log; -extern crate protobuf; #[macro_use] extern crate quick_error; -extern crate rand; #[macro_use] extern crate getset; mod config; +mod prost; /// This module supplies the needed message types. However, it is autogenerated and thus cannot be /// documented by field. -pub mod eraftpb; +pub use crate::prost::eraftpb; mod errors; mod log_unstable; mod progress; @@ -402,7 +403,9 @@ pub mod util; pub use self::config::Config; pub use self::errors::{Error, Result, StorageError}; pub use self::log_unstable::Unstable; -pub use self::progress::{Configuration, Inflights, Progress, ProgressSet, ProgressState}; +pub use self::progress::inflights::Inflights; +pub use self::progress::progress_set::{Configuration, ProgressSet}; +pub use self::progress::{Progress, ProgressState}; pub use self::raft::{vote_resp_msg_type, Raft, SoftState, StateRole, INVALID_ID, INVALID_INDEX}; pub use self::raft_log::{RaftLog, NO_LIMIT}; pub use self::raw_node::{is_empty_snap, Peer, RawNode, Ready, SnapshotStatus}; @@ -423,21 +426,21 @@ pub mod prelude { //! //! The prelude may grow over time as additional items see ubiquitous use. - pub use eraftpb::{ + pub use crate::eraftpb::{ ConfChange, ConfChangeType, ConfState, Entry, EntryType, HardState, Message, MessageType, Snapshot, SnapshotMetadata, }; - pub use config::Config; - pub use raft::Raft; + pub use crate::config::Config; + pub use crate::raft::Raft; - pub use storage::{RaftState, Storage}; + pub use crate::storage::{RaftState, Storage}; - pub use raw_node::{Peer, RawNode, Ready, SnapshotStatus}; + pub use crate::raw_node::{Peer, RawNode, Ready, SnapshotStatus}; - pub use progress::Progress; + pub use crate::progress::Progress; - pub use status::Status; + pub use crate::status::Status; - pub use read_only::{ReadOnlyOption, ReadState}; + pub use crate::read_only::{ReadOnlyOption, ReadState}; } diff --git a/src/log_unstable.rs b/src/log_unstable.rs index e4b93ca15..68a58d29c 100644 --- a/src/log_unstable.rs +++ b/src/log_unstable.rs @@ -27,7 +27,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use eraftpb::{Entry, Snapshot}; +use crate::eraftpb::{Entry, Snapshot}; /// The unstable.entries[i] has raft log position i+unstable.offset. /// Note that unstable.offset may be less than the highest log @@ -183,20 +183,20 @@ impl Unstable { #[cfg(test)] mod test { - use eraftpb::{Entry, Snapshot, SnapshotMetadata}; + use crate::eraftpb::{Entry, Snapshot, SnapshotMetadata}; + use crate::log_unstable::Unstable; use harness::setup_for_test; - use log_unstable::Unstable; fn new_entry(index: u64, term: u64) -> Entry { - let mut e = Entry::new(); + let mut e = Entry::new_(); e.set_term(term); e.set_index(index); e } fn new_snapshot(index: u64, term: u64) -> Snapshot { - let mut snap = Snapshot::new(); - let mut meta = SnapshotMetadata::new(); + let mut snap = Snapshot::new_(); + let mut meta = SnapshotMetadata::new_(); meta.set_index(index); meta.set_term(term); snap.set_metadata(meta); diff --git a/src/progress/inflights.rs b/src/progress/inflights.rs new file mode 100644 index 000000000..ecb8cecc6 --- /dev/null +++ b/src/progress/inflights.rs @@ -0,0 +1,271 @@ +// Copyright 2016 PingCAP, 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, +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2015 The etcd Authors +// +// 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. + +/// A buffer of inflight messages. +#[derive(Debug, PartialEq)] +pub struct Inflights { + // the starting index in the buffer + start: usize, + // number of inflights in the buffer + count: usize, + + // ring buffer + buffer: Vec, +} + +// The `buffer` must have it's capacity set correctly on clone, normally it does not. +impl Clone for Inflights { + fn clone(&self) -> Self { + let mut buffer = self.buffer.clone(); + buffer.reserve(self.buffer.capacity() - self.buffer.len()); + Inflights { + start: self.start, + count: self.count, + buffer, + } + } +} + +impl Inflights { + /// Creates a new buffer for inflight messages. + pub fn new(cap: usize) -> Inflights { + Inflights { + buffer: Vec::with_capacity(cap), + start: 0, + count: 0, + } + } + + /// Returns true if the inflights is full. + #[inline] + pub fn full(&self) -> bool { + self.count == self.cap() + } + + /// The buffer capacity. + #[inline] + pub fn cap(&self) -> usize { + self.buffer.capacity() + } + + /// Adds an inflight into inflights + pub fn add(&mut self, inflight: u64) { + if self.full() { + panic!("cannot add into a full inflights") + } + + let mut next = self.start + self.count; + if next >= self.cap() { + next -= self.cap(); + } + assert!(next <= self.buffer.len()); + if next == self.buffer.len() { + self.buffer.push(inflight); + } else { + self.buffer[next] = inflight; + } + self.count += 1; + } + + /// Frees the inflights smaller or equal to the given `to` flight. + pub fn free_to(&mut self, to: u64) { + if self.count == 0 || to < self.buffer[self.start] { + // out of the left side of the window + return; + } + + let mut i = 0usize; + let mut idx = self.start; + while i < self.count { + if to < self.buffer[idx] { + // found the first large inflight + break; + } + + // increase index and maybe rotate + idx += 1; + if idx >= self.cap() { + idx -= self.cap(); + } + + i += 1; + } + + // free i inflights and set new start index + self.count -= i; + self.start = idx; + } + + /// Frees the first buffer entry. + #[inline] + pub fn free_first_one(&mut self) { + let start = self.buffer[self.start]; + self.free_to(start); + } + + /// Frees all inflights. + #[inline] + pub fn reset(&mut self) { + self.count = 0; + self.start = 0; + } +} + +#[cfg(test)] +mod tests { + use super::Inflights; + use harness::setup_for_test; + + #[test] + fn test_inflight_add() { + setup_for_test(); + let mut inflight = Inflights::new(10); + for i in 0..5 { + inflight.add(i); + } + + let wantin = Inflights { + start: 0, + count: 5, + buffer: vec![0, 1, 2, 3, 4], + }; + + assert_eq!(inflight, wantin); + + for i in 5..10 { + inflight.add(i); + } + + let wantin2 = Inflights { + start: 0, + count: 10, + buffer: vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + }; + + assert_eq!(inflight, wantin2); + + let mut inflight2 = Inflights::new(10); + inflight2.start = 5; + inflight2.buffer.extend_from_slice(&[0, 0, 0, 0, 0]); + + for i in 0..5 { + inflight2.add(i); + } + + let wantin21 = Inflights { + start: 5, + count: 5, + buffer: vec![0, 0, 0, 0, 0, 0, 1, 2, 3, 4], + }; + + assert_eq!(inflight2, wantin21); + + for i in 5..10 { + inflight2.add(i); + } + + let wantin22 = Inflights { + start: 5, + count: 10, + buffer: vec![5, 6, 7, 8, 9, 0, 1, 2, 3, 4], + }; + + assert_eq!(inflight2, wantin22); + } + + #[test] + fn test_inflight_free_to() { + setup_for_test(); + let mut inflight = Inflights::new(10); + for i in 0..10 { + inflight.add(i); + } + + inflight.free_to(4); + + let wantin = Inflights { + start: 5, + count: 5, + buffer: vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + }; + + assert_eq!(inflight, wantin); + + inflight.free_to(8); + + let wantin2 = Inflights { + start: 9, + count: 1, + buffer: vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + }; + + assert_eq!(inflight, wantin2); + + for i in 10..15 { + inflight.add(i); + } + + inflight.free_to(12); + + let wantin3 = Inflights { + start: 3, + count: 2, + buffer: vec![10, 11, 12, 13, 14, 5, 6, 7, 8, 9], + }; + + assert_eq!(inflight, wantin3); + + inflight.free_to(14); + + let wantin4 = Inflights { + start: 5, + count: 0, + buffer: vec![10, 11, 12, 13, 14, 5, 6, 7, 8, 9], + }; + + assert_eq!(inflight, wantin4); + } + + #[test] + fn test_inflight_free_first_one() { + setup_for_test(); + let mut inflight = Inflights::new(10); + for i in 0..10 { + inflight.add(i); + } + + inflight.free_first_one(); + + let wantin = Inflights { + start: 1, + count: 9, + buffer: vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + }; + + assert_eq!(inflight, wantin); + } +} diff --git a/src/progress/mod.rs b/src/progress/mod.rs new file mode 100644 index 000000000..8c3716fb1 --- /dev/null +++ b/src/progress/mod.rs @@ -0,0 +1,251 @@ +// Copyright 2016 PingCAP, 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, +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2015 The etcd Authors +// +// 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. + +use self::inflights::Inflights; +use std::cmp; +pub mod inflights; +pub mod progress_set; + +/// The state of the progress. +#[derive(Debug, PartialEq, Clone, Copy)] +pub enum ProgressState { + /// Whether it's probing. + Probe, + /// Whether it's replicating. + Replicate, + /// Whethers it's a snapshot. + Snapshot, +} + +impl Default for ProgressState { + fn default() -> ProgressState { + ProgressState::Probe + } +} + +/// The progress of catching up from a restart. +#[derive(Debug, Clone, PartialEq)] +pub struct Progress { + /// How much state is matched. + pub matched: u64, + /// The next index to apply + pub next_idx: u64, + /// When in ProgressStateProbe, leader sends at most one replication message + /// per heartbeat interval. It also probes actual progress of the follower. + /// + /// When in ProgressStateReplicate, leader optimistically increases next + /// to the latest entry sent after sending replication message. This is + /// an optimized state for fast replicating log entries to the follower. + /// + /// When in ProgressStateSnapshot, leader should have sent out snapshot + /// before and stop sending any replication message. + pub state: ProgressState, + /// Paused is used in ProgressStateProbe. + /// When Paused is true, raft should pause sending replication message to this peer. + pub paused: bool, + /// This field is used in ProgressStateSnapshot. + /// If there is a pending snapshot, the pendingSnapshot will be set to the + /// index of the snapshot. If pendingSnapshot is set, the replication process of + /// this Progress will be paused. raft will not resend snapshot until the pending one + /// is reported to be failed. + pub pending_snapshot: u64, + + /// This is true if the progress is recently active. Receiving any messages + /// from the corresponding follower indicates the progress is active. + /// RecentActive can be reset to false after an election timeout. + pub recent_active: bool, + + /// Inflights is a sliding window for the inflight messages. + /// When inflights is full, no more message should be sent. + /// When a leader sends out a message, the index of the last + /// entry should be added to inflights. The index MUST be added + /// into inflights in order. + /// When a leader receives a reply, the previous inflights should + /// be freed by calling inflights.freeTo. + pub ins: Inflights, +} + +impl Progress { + /// Creates a new progress with the given settings. + pub fn new(next_idx: u64, ins_size: usize) -> Self { + Progress { + matched: 0, + next_idx, + state: ProgressState::default(), + paused: false, + pending_snapshot: 0, + recent_active: false, + ins: Inflights::new(ins_size), + } + } + + fn reset_state(&mut self, state: ProgressState) { + self.paused = false; + self.pending_snapshot = 0; + self.state = state; + self.ins.reset(); + } + + pub(crate) fn reset(&mut self, next_idx: u64) { + self.matched = 0; + self.next_idx = next_idx; + self.state = ProgressState::default(); + self.paused = false; + self.pending_snapshot = 0; + self.recent_active = false; + debug_assert!(self.ins.cap() != 0); + self.ins.reset(); + } + + /// Changes the progress to a probe. + pub fn become_probe(&mut self) { + // If the original state is ProgressStateSnapshot, progress knows that + // the pending snapshot has been sent to this peer successfully, then + // probes from pendingSnapshot + 1. + if self.state == ProgressState::Snapshot { + let pending_snapshot = self.pending_snapshot; + self.reset_state(ProgressState::Probe); + self.next_idx = cmp::max(self.matched + 1, pending_snapshot + 1); + } else { + self.reset_state(ProgressState::Probe); + self.next_idx = self.matched + 1; + } + } + + /// Changes the progress to a Replicate. + #[inline] + pub fn become_replicate(&mut self) { + self.reset_state(ProgressState::Replicate); + self.next_idx = self.matched + 1; + } + + /// Changes the progress to a snapshot. + #[inline] + pub fn become_snapshot(&mut self, snapshot_idx: u64) { + self.reset_state(ProgressState::Snapshot); + self.pending_snapshot = snapshot_idx; + } + + /// Sets the snapshot to failure. + #[inline] + pub fn snapshot_failure(&mut self) { + self.pending_snapshot = 0; + } + + /// Unsets pendingSnapshot if Match is equal or higher than + /// the pendingSnapshot + #[inline] + pub fn maybe_snapshot_abort(&self) -> bool { + self.state == ProgressState::Snapshot && self.matched >= self.pending_snapshot + } + + /// Returns false if the given n index comes from an outdated message. + /// Otherwise it updates the progress and returns true. + pub fn maybe_update(&mut self, n: u64) -> bool { + let need_update = self.matched < n; + if need_update { + self.matched = n; + self.resume(); + }; + + if self.next_idx < n + 1 { + self.next_idx = n + 1 + } + + need_update + } + + /// Optimistically advance the index + #[inline] + pub fn optimistic_update(&mut self, n: u64) { + self.next_idx = n + 1; + } + + /// Returns false if the given index comes from an out of order message. + /// Otherwise it decreases the progress next index to min(rejected, last) + /// and returns true. + pub fn maybe_decr_to(&mut self, rejected: u64, last: u64) -> bool { + if self.state == ProgressState::Replicate { + // the rejection must be stale if the progress has matched and "rejected" + // is smaller than "match". + if rejected <= self.matched { + return false; + } + self.next_idx = self.matched + 1; + return true; + } + + // the rejection must be stale if "rejected" does not match next - 1 + if self.next_idx == 0 || self.next_idx - 1 != rejected { + return false; + } + + self.next_idx = cmp::min(rejected, last + 1); + if self.next_idx < 1 { + self.next_idx = 1; + } + self.resume(); + true + } + + /// Determine whether progress is paused. + #[inline] + pub fn is_paused(&self) -> bool { + match self.state { + ProgressState::Probe => self.paused, + ProgressState::Replicate => self.ins.full(), + ProgressState::Snapshot => true, + } + } + + /// Resume progress + #[inline] + pub fn resume(&mut self) { + self.paused = false; + } + + /// Pause progress. + #[inline] + pub fn pause(&mut self) { + self.paused = true; + } + + /// Update inflight msgs and next_idx + pub fn update_state(&mut self, last: u64) { + match self.state { + ProgressState::Replicate => { + self.optimistic_update(last); + self.ins.add(last); + } + ProgressState::Probe => self.pause(), + ProgressState::Snapshot => panic!( + "updating progress state in unhandled state {:?}", + self.state + ), + } + } +} diff --git a/src/progress.rs b/src/progress/progress_set.rs similarity index 70% rename from src/progress.rs rename to src/progress/progress_set.rs index b2626fa48..38a48ec88 100644 --- a/src/progress.rs +++ b/src/progress/progress_set.rs @@ -25,12 +25,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -use eraftpb::{ConfState, SnapshotMetadata}; -use errors::{Error, Result}; +use crate::eraftpb::{ConfState, SnapshotMetadata}; +use crate::errors::{Error, Result}; +use crate::progress::Progress; use hashbrown::hash_map::DefaultHashBuilder; use hashbrown::{HashMap, HashSet}; use std::cell::RefCell; -use std::cmp; // Since it's an integer, it rounds for us. #[inline] @@ -38,23 +38,6 @@ fn majority(total: usize) -> usize { (total / 2) + 1 } -/// The state of the progress. -#[derive(Debug, PartialEq, Clone, Copy)] -pub enum ProgressState { - /// Whether it's probing. - Probe, - /// Whether it's replicating. - Replicate, - /// Whethers it's a snapshot. - Snapshot, -} - -impl Default for ProgressState { - fn default() -> ProgressState { - ProgressState::Probe - } -} - /// A Raft internal representation of a Configuration. /// /// This is corollary to a ConfState, but optimized for `contains` calls. @@ -141,6 +124,7 @@ impl Configuration { } /// Returns whether or not the given `id` is a member of this configuration. + #[inline] pub fn contains(&self, id: u64) -> bool { self.voters.contains(&id) || self.learners.contains(&id) } @@ -670,435 +654,12 @@ impl ProgressSet { } } -/// The progress of catching up from a restart. -#[derive(Debug, Clone, PartialEq)] -pub struct Progress { - /// How much state is matched. - pub matched: u64, - /// The next index to apply - pub next_idx: u64, - /// When in ProgressStateProbe, leader sends at most one replication message - /// per heartbeat interval. It also probes actual progress of the follower. - /// - /// When in ProgressStateReplicate, leader optimistically increases next - /// to the latest entry sent after sending replication message. This is - /// an optimized state for fast replicating log entries to the follower. - /// - /// When in ProgressStateSnapshot, leader should have sent out snapshot - /// before and stop sending any replication message. - pub state: ProgressState, - /// Paused is used in ProgressStateProbe. - /// When Paused is true, raft should pause sending replication message to this peer. - pub paused: bool, - /// This field is used in ProgressStateSnapshot. - /// If there is a pending snapshot, the pendingSnapshot will be set to the - /// index of the snapshot. If pendingSnapshot is set, the replication process of - /// this Progress will be paused. raft will not resend snapshot until the pending one - /// is reported to be failed. - pub pending_snapshot: u64, - - /// This is true if the progress is recently active. Receiving any messages - /// from the corresponding follower indicates the progress is active. - /// RecentActive can be reset to false after an election timeout. - pub recent_active: bool, - - /// Inflights is a sliding window for the inflight messages. - /// When inflights is full, no more message should be sent. - /// When a leader sends out a message, the index of the last - /// entry should be added to inflights. The index MUST be added - /// into inflights in order. - /// When a leader receives a reply, the previous inflights should - /// be freed by calling inflights.freeTo. - pub ins: Inflights, -} - -impl Progress { - /// Creates a new progress with the given settings. - pub fn new(next_idx: u64, ins_size: usize) -> Self { - Progress { - matched: 0, - next_idx, - state: ProgressState::default(), - paused: false, - pending_snapshot: 0, - recent_active: false, - ins: Inflights::new(ins_size), - } - } - - fn reset_state(&mut self, state: ProgressState) { - self.paused = false; - self.pending_snapshot = 0; - self.state = state; - self.ins.reset(); - } - - pub(crate) fn reset(&mut self, next_idx: u64) { - self.matched = 0; - self.next_idx = next_idx; - self.state = ProgressState::default(); - self.paused = false; - self.pending_snapshot = 0; - self.recent_active = false; - debug_assert!(self.ins.cap() != 0); - self.ins.reset(); - } - - /// Changes the progress to a probe. - pub fn become_probe(&mut self) { - // If the original state is ProgressStateSnapshot, progress knows that - // the pending snapshot has been sent to this peer successfully, then - // probes from pendingSnapshot + 1. - if self.state == ProgressState::Snapshot { - let pending_snapshot = self.pending_snapshot; - self.reset_state(ProgressState::Probe); - self.next_idx = cmp::max(self.matched + 1, pending_snapshot + 1); - } else { - self.reset_state(ProgressState::Probe); - self.next_idx = self.matched + 1; - } - } - - /// Changes the progress to a Replicate. - pub fn become_replicate(&mut self) { - self.reset_state(ProgressState::Replicate); - self.next_idx = self.matched + 1; - } - - /// Changes the progress to a snapshot. - pub fn become_snapshot(&mut self, snapshot_idx: u64) { - self.reset_state(ProgressState::Snapshot); - self.pending_snapshot = snapshot_idx; - } - - /// Sets the snapshot to failure. - pub fn snapshot_failure(&mut self) { - self.pending_snapshot = 0; - } - - /// Unsets pendingSnapshot if Match is equal or higher than - /// the pendingSnapshot - pub fn maybe_snapshot_abort(&self) -> bool { - self.state == ProgressState::Snapshot && self.matched >= self.pending_snapshot - } - - /// Returns false if the given n index comes from an outdated message. - /// Otherwise it updates the progress and returns true. - pub fn maybe_update(&mut self, n: u64) -> bool { - let need_update = self.matched < n; - if need_update { - self.matched = n; - self.resume(); - }; - - if self.next_idx < n + 1 { - self.next_idx = n + 1 - } - - need_update - } - - /// Optimistically advance the index - pub fn optimistic_update(&mut self, n: u64) { - self.next_idx = n + 1; - } - - /// Returns false if the given index comes from an out of order message. - /// Otherwise it decreases the progress next index to min(rejected, last) - /// and returns true. - pub fn maybe_decr_to(&mut self, rejected: u64, last: u64) -> bool { - if self.state == ProgressState::Replicate { - // the rejection must be stale if the progress has matched and "rejected" - // is smaller than "match". - if rejected <= self.matched { - return false; - } - self.next_idx = self.matched + 1; - return true; - } - - // the rejection must be stale if "rejected" does not match next - 1 - if self.next_idx == 0 || self.next_idx - 1 != rejected { - return false; - } - - self.next_idx = cmp::min(rejected, last + 1); - if self.next_idx < 1 { - self.next_idx = 1; - } - self.resume(); - true - } - - /// Determine whether progress is paused. - pub fn is_paused(&self) -> bool { - match self.state { - ProgressState::Probe => self.paused, - ProgressState::Replicate => self.ins.full(), - ProgressState::Snapshot => true, - } - } - - /// Resume progress - pub fn resume(&mut self) { - self.paused = false; - } - - /// Pause progress. - pub fn pause(&mut self) { - self.paused = true; - } -} - -/// A buffer of inflight messages. -#[derive(Debug, PartialEq)] -pub struct Inflights { - // the starting index in the buffer - start: usize, - // number of inflights in the buffer - count: usize, - - // ring buffer - buffer: Vec, -} - -// The `buffer` must have it's capacity set correctly on clone, normally it does not. -impl Clone for Inflights { - fn clone(&self) -> Self { - let mut buffer = self.buffer.clone(); - buffer.reserve(self.buffer.capacity() - self.buffer.len()); - Inflights { - start: self.start, - count: self.count, - buffer, - } - } -} - -impl Inflights { - /// Creates a new buffer for inflight messages. - pub fn new(cap: usize) -> Inflights { - Inflights { - buffer: Vec::with_capacity(cap), - start: 0, - count: 0, - } - } - - /// Returns true if the inflights is full. - pub fn full(&self) -> bool { - self.count == self.cap() - } - - /// The buffer capacity. - pub fn cap(&self) -> usize { - self.buffer.capacity() - } - - /// Adds an inflight into inflights - pub fn add(&mut self, inflight: u64) { - if self.full() { - panic!("cannot add into a full inflights") - } - - let mut next = self.start + self.count; - if next >= self.cap() { - next -= self.cap(); - } - assert!(next <= self.buffer.len()); - if next == self.buffer.len() { - self.buffer.push(inflight); - } else { - self.buffer[next] = inflight; - } - self.count += 1; - } - - /// Frees the inflights smaller or equal to the given `to` flight. - pub fn free_to(&mut self, to: u64) { - if self.count == 0 || to < self.buffer[self.start] { - // out of the left side of the window - return; - } - - let mut i = 0usize; - let mut idx = self.start; - while i < self.count { - if to < self.buffer[idx] { - // found the first large inflight - break; - } - - // increase index and maybe rotate - idx += 1; - if idx >= self.cap() { - idx -= self.cap(); - } - - i += 1; - } - - // free i inflights and set new start index - self.count -= i; - self.start = idx; - } - - /// Frees the first buffer entry. - pub fn free_first_one(&mut self) { - let start = self.buffer[self.start]; - self.free_to(start); - } - - /// Frees all inflights. - pub fn reset(&mut self) { - self.count = 0; - self.start = 0; - } -} - -#[cfg(test)] -mod test { - use harness::setup_for_test; - use progress::Inflights; - - #[test] - fn test_inflight_add() { - setup_for_test(); - let mut inflight = Inflights::new(10); - for i in 0..5 { - inflight.add(i); - } - - let wantin = Inflights { - start: 0, - count: 5, - buffer: vec![0, 1, 2, 3, 4], - }; - - assert_eq!(inflight, wantin); - - for i in 5..10 { - inflight.add(i); - } - - let wantin2 = Inflights { - start: 0, - count: 10, - buffer: vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - }; - - assert_eq!(inflight, wantin2); - - let mut inflight2 = Inflights::new(10); - inflight2.start = 5; - inflight2.buffer.extend_from_slice(&[0, 0, 0, 0, 0]); - - for i in 0..5 { - inflight2.add(i); - } - - let wantin21 = Inflights { - start: 5, - count: 5, - buffer: vec![0, 0, 0, 0, 0, 0, 1, 2, 3, 4], - }; - - assert_eq!(inflight2, wantin21); - - for i in 5..10 { - inflight2.add(i); - } - - let wantin22 = Inflights { - start: 5, - count: 10, - buffer: vec![5, 6, 7, 8, 9, 0, 1, 2, 3, 4], - }; - - assert_eq!(inflight2, wantin22); - } - - #[test] - fn test_inflight_free_to() { - setup_for_test(); - let mut inflight = Inflights::new(10); - for i in 0..10 { - inflight.add(i); - } - - inflight.free_to(4); - - let wantin = Inflights { - start: 5, - count: 5, - buffer: vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - }; - - assert_eq!(inflight, wantin); - - inflight.free_to(8); - - let wantin2 = Inflights { - start: 9, - count: 1, - buffer: vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - }; - - assert_eq!(inflight, wantin2); - - for i in 10..15 { - inflight.add(i); - } - - inflight.free_to(12); - - let wantin3 = Inflights { - start: 3, - count: 2, - buffer: vec![10, 11, 12, 13, 14, 5, 6, 7, 8, 9], - }; - - assert_eq!(inflight, wantin3); - - inflight.free_to(14); - - let wantin4 = Inflights { - start: 5, - count: 0, - buffer: vec![10, 11, 12, 13, 14, 5, 6, 7, 8, 9], - }; - - assert_eq!(inflight, wantin4); - } - - #[test] - fn test_inflight_free_first_one() { - setup_for_test(); - let mut inflight = Inflights::new(10); - for i in 0..10 { - inflight.add(i); - } - - inflight.free_first_one(); - - let wantin = Inflights { - start: 1, - count: 9, - buffer: vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - }; - - assert_eq!(inflight, wantin); - } -} - -// TODO: Reorganize this whole file into separate files. -// See https://github.com/pingcap/raft-rs/issues/125 #[cfg(test)] mod test_progress_set { + use super::{Configuration, ProgressSet, Result}; + use crate::progress::Progress; use hashbrown::HashSet; - use {progress::Configuration, Progress, ProgressSet, Result}; - const CANARY: u64 = 123; #[test] diff --git a/src/prost.rs b/src/prost.rs new file mode 100644 index 000000000..085a2ed96 --- /dev/null +++ b/src/prost.rs @@ -0,0 +1,8 @@ +#![allow(dead_code)] +#![allow(missing_docs)] +#![allow(clippy::all)] + +pub mod eraftpb { + include!("prost/eraftpb.rs"); + include!("prost/wrapper_eraftpb.rs"); +} diff --git a/src/prost/eraftpb.rs b/src/prost/eraftpb.rs new file mode 100644 index 000000000..f8c9174e7 --- /dev/null +++ b/src/prost/eraftpb.rs @@ -0,0 +1,148 @@ +/// The entry is a type of change that needs to be applied. It contains two data fields. +/// While the fields are built into the model; their usage is determined by the entry_type. +/// +/// For normal entries, the data field should contain the data change that should be applied. +/// The context field can be used for any contextual data that might be relevant to the +/// application of the data. +/// +/// For configuration changes, the data will contain the ConfChange message and the +/// context will provide anything needed to assist the configuration change. The context +/// if for the user to set and use in this case. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Entry { + #[prost(enumeration = "EntryType", tag = "1")] + pub entry_type: i32, + #[prost(uint64, tag = "2")] + pub term: u64, + #[prost(uint64, tag = "3")] + pub index: u64, + #[prost(bytes, tag = "4")] + pub data: std::vec::Vec, + #[prost(bytes, tag = "6")] + pub context: std::vec::Vec, + /// Deprecated! It is kept for backward compatibility. + /// TODO: remove it in the next major release. + #[prost(bool, tag = "5")] + pub sync_log: bool, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SnapshotMetadata { + #[prost(message, optional, tag = "1")] + pub conf_state: ::std::option::Option, + #[prost(message, optional, tag = "4")] + pub pending_membership_change: ::std::option::Option, + #[prost(uint64, tag = "5")] + pub pending_membership_change_index: u64, + #[prost(uint64, tag = "2")] + pub index: u64, + #[prost(uint64, tag = "3")] + pub term: u64, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Snapshot { + #[prost(bytes, tag = "1")] + pub data: std::vec::Vec, + #[prost(message, optional, tag = "2")] + pub metadata: ::std::option::Option, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Message { + #[prost(enumeration = "MessageType", tag = "1")] + pub msg_type: i32, + #[prost(uint64, tag = "2")] + pub to: u64, + #[prost(uint64, tag = "3")] + pub from: u64, + #[prost(uint64, tag = "4")] + pub term: u64, + #[prost(uint64, tag = "5")] + pub log_term: u64, + #[prost(uint64, tag = "6")] + pub index: u64, + #[prost(message, repeated, tag = "7")] + pub entries: ::std::vec::Vec, + #[prost(uint64, tag = "8")] + pub commit: u64, + #[prost(message, optional, tag = "9")] + pub snapshot: ::std::option::Option, + #[prost(bool, tag = "10")] + pub reject: bool, + #[prost(uint64, tag = "11")] + pub reject_hint: u64, + #[prost(bytes, tag = "12")] + pub context: std::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct HardState { + #[prost(uint64, tag = "1")] + pub term: u64, + #[prost(uint64, tag = "2")] + pub vote: u64, + #[prost(uint64, tag = "3")] + pub commit: u64, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ConfState { + #[prost(uint64, repeated, tag = "1")] + pub nodes: ::std::vec::Vec, + #[prost(uint64, repeated, tag = "2")] + pub learners: ::std::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ConfChange { + #[prost(uint64, tag = "1")] + pub id: u64, + #[prost(enumeration = "ConfChangeType", tag = "2")] + pub change_type: i32, + /// Used in `AddNode`, `RemoveNode`, and `AddLearnerNode`. + #[prost(uint64, tag = "3")] + pub node_id: u64, + #[prost(bytes, tag = "4")] + pub context: std::vec::Vec, + /// Used in `BeginMembershipChange` and `FinalizeMembershipChange`. + #[prost(message, optional, tag = "5")] + pub configuration: ::std::option::Option, + /// Used in `BeginMembershipChange` and `FinalizeMembershipChange`. + /// Because `RawNode::apply_conf_change` takes a `ConfChange` instead of an `Entry` we must + /// include this index so it can be known. + #[prost(uint64, tag = "6")] + pub start_index: u64, +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum EntryType { + EntryNormal = 0, + EntryConfChange = 1, +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum MessageType { + MsgHup = 0, + MsgBeat = 1, + MsgPropose = 2, + MsgAppend = 3, + MsgAppendResponse = 4, + MsgRequestVote = 5, + MsgRequestVoteResponse = 6, + MsgSnapshot = 7, + MsgHeartbeat = 8, + MsgHeartbeatResponse = 9, + MsgUnreachable = 10, + MsgSnapStatus = 11, + MsgCheckQuorum = 12, + MsgTransferLeader = 13, + MsgTimeoutNow = 14, + MsgReadIndex = 15, + MsgReadIndexResp = 16, + MsgRequestPreVote = 17, + MsgRequestPreVoteResponse = 18, +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum ConfChangeType { + AddNode = 0, + RemoveNode = 1, + AddLearnerNode = 2, + BeginMembershipChange = 3, + FinalizeMembershipChange = 4, +} diff --git a/src/prost/wrapper_eraftpb.rs b/src/prost/wrapper_eraftpb.rs new file mode 100644 index 000000000..e10c4afd0 --- /dev/null +++ b/src/prost/wrapper_eraftpb.rs @@ -0,0 +1,1133 @@ +// Generated file, please don't edit manually. + +impl Entry { + pub fn new_() -> Entry { + ::std::default::Default::default() + } + #[inline] + pub fn clear_entry_type(&mut self) { + self.entry_type = 0 + } + #[inline] + pub fn set_entry_type_(&mut self, v: EntryType) { + self.entry_type = unsafe { ::std::mem::transmute::(v) }; + } + #[inline] + pub fn get_entry_type(&self) -> EntryType { + unsafe { ::std::mem::transmute::(self.entry_type) } + } + #[inline] + pub fn clear_term(&mut self) { + self.term = 0 + } + #[inline] + pub fn set_term(&mut self, v: u64) { + self.term = v; + } + #[inline] + pub fn get_term(&self) -> u64 { + self.term + } + #[inline] + pub fn clear_index(&mut self) { + self.index = 0 + } + #[inline] + pub fn set_index(&mut self, v: u64) { + self.index = v; + } + #[inline] + pub fn get_index(&self) -> u64 { + self.index + } + #[inline] + pub fn clear_data(&mut self) { + self.data.clear(); + } + #[inline] + pub fn set_data(&mut self, v: std::vec::Vec) { + self.data = v; + } + #[inline] + pub fn get_data(&self) -> &[u8] { + &self.data + } + #[inline] + pub fn mut_data(&mut self) -> &mut std::vec::Vec { + &mut self.data + } + #[inline] + pub fn take_data(&mut self) -> std::vec::Vec { + ::std::mem::replace(&mut self.data, ::std::vec::Vec::new()) + } + #[inline] + pub fn clear_context(&mut self) { + self.context.clear(); + } + #[inline] + pub fn set_context(&mut self, v: std::vec::Vec) { + self.context = v; + } + #[inline] + pub fn get_context(&self) -> &[u8] { + &self.context + } + #[inline] + pub fn mut_context(&mut self) -> &mut std::vec::Vec { + &mut self.context + } + #[inline] + pub fn take_context(&mut self) -> std::vec::Vec { + ::std::mem::replace(&mut self.context, ::std::vec::Vec::new()) + } + #[inline] + pub fn clear_sync_log(&mut self) { + self.sync_log = false + } + #[inline] + pub fn set_sync_log(&mut self, v: bool) { + self.sync_log = v; + } + #[inline] + pub fn get_sync_log(&self) -> bool { + self.sync_log + } +} +impl ::protobuf::Clear for Entry { + fn clear(&mut self) { + ::prost::Message::clear(self); + } +} +impl ::protobuf::Message for Entry { + fn compute_size(&self) -> u32 { + ::prost::Message::encoded_len(self) as u32 + } + fn get_cached_size(&self) -> u32 { + ::prost::Message::encoded_len(self) as u32 + } + fn as_any(&self) -> &::std::any::Any { + self as &::std::any::Any + } + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + fn new() -> Self { + Self::new_() + } + fn write_to_with_cached_sizes( + &self, + _os: &mut ::protobuf::CodedOutputStream, + ) -> ::protobuf::ProtobufResult<()> { + unimplemented!(); + } + fn default_instance() -> &'static Entry { + ::lazy_static::lazy_static! { + static ref INSTANCE: Entry = Entry::new_(); + } + &*INSTANCE + } + fn is_initialized(&self) -> bool { + true + } + fn merge_from( + &mut self, + _is: &mut ::protobuf::CodedInputStream, + ) -> ::protobuf::ProtobufResult<()> { + unimplemented!(); + } + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + unimplemented!(); + } + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + unimplemented!(); + } + fn write_to_bytes(&self) -> ::protobuf::ProtobufResult> { + let mut buf = Vec::new(); + if let Err(_) = ::prost::Message::encode(self, &mut buf) { + return Err(::protobuf::ProtobufError::WireError( + ::protobuf::error::WireError::Other, + )); + } + Ok(buf) + } + fn merge_from_bytes(&mut self, bytes: &[u8]) -> ::protobuf::ProtobufResult<()> { + if let Err(_) = ::prost::Message::merge(self, bytes) { + return Err(::protobuf::ProtobufError::WireError( + ::protobuf::error::WireError::Other, + )); + } + Ok(()) + } +} +impl SnapshotMetadata { + pub fn new_() -> SnapshotMetadata { + ::std::default::Default::default() + } + #[inline] + pub fn has_conf_state(&self) -> bool { + self.conf_state.is_some() + } + #[inline] + pub fn clear_conf_state(&mut self) { + self.conf_state = ::std::option::Option::None + } + #[inline] + pub fn set_conf_state(&mut self, v: ConfState) { + self.conf_state = ::std::option::Option::Some(v); + } + #[inline] + pub fn get_conf_state(&self) -> &ConfState { + match self.conf_state.as_ref() { + Some(v) => v, + None => ::default_instance(), + } + } + #[inline] + pub fn mut_conf_state(&mut self) -> &mut ConfState { + if self.conf_state.is_none() { + self.conf_state = ::std::option::Option::Some(ConfState::default()); + } + self.conf_state.as_mut().unwrap() + } + #[inline] + pub fn take_conf_state(&mut self) -> ConfState { + self.conf_state.take().unwrap_or_else(ConfState::default) + } + #[inline] + pub fn has_pending_membership_change(&self) -> bool { + self.pending_membership_change.is_some() + } + #[inline] + pub fn clear_pending_membership_change(&mut self) { + self.pending_membership_change = ::std::option::Option::None + } + #[inline] + pub fn set_pending_membership_change(&mut self, v: ConfState) { + self.pending_membership_change = ::std::option::Option::Some(v); + } + #[inline] + pub fn get_pending_membership_change(&self) -> &ConfState { + match self.pending_membership_change.as_ref() { + Some(v) => v, + None => ::default_instance(), + } + } + #[inline] + pub fn mut_pending_membership_change(&mut self) -> &mut ConfState { + if self.pending_membership_change.is_none() { + self.pending_membership_change = ::std::option::Option::Some(ConfState::default()); + } + self.pending_membership_change.as_mut().unwrap() + } + #[inline] + pub fn take_pending_membership_change(&mut self) -> ConfState { + self.pending_membership_change + .take() + .unwrap_or_else(ConfState::default) + } + #[inline] + pub fn clear_pending_membership_change_index(&mut self) { + self.pending_membership_change_index = 0 + } + #[inline] + pub fn set_pending_membership_change_index(&mut self, v: u64) { + self.pending_membership_change_index = v; + } + #[inline] + pub fn get_pending_membership_change_index(&self) -> u64 { + self.pending_membership_change_index + } + #[inline] + pub fn clear_index(&mut self) { + self.index = 0 + } + #[inline] + pub fn set_index(&mut self, v: u64) { + self.index = v; + } + #[inline] + pub fn get_index(&self) -> u64 { + self.index + } + #[inline] + pub fn clear_term(&mut self) { + self.term = 0 + } + #[inline] + pub fn set_term(&mut self, v: u64) { + self.term = v; + } + #[inline] + pub fn get_term(&self) -> u64 { + self.term + } +} +impl ::protobuf::Clear for SnapshotMetadata { + fn clear(&mut self) { + ::prost::Message::clear(self); + } +} +impl ::protobuf::Message for SnapshotMetadata { + fn compute_size(&self) -> u32 { + ::prost::Message::encoded_len(self) as u32 + } + fn get_cached_size(&self) -> u32 { + ::prost::Message::encoded_len(self) as u32 + } + fn as_any(&self) -> &::std::any::Any { + self as &::std::any::Any + } + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + fn new() -> Self { + Self::new_() + } + fn write_to_with_cached_sizes( + &self, + _os: &mut ::protobuf::CodedOutputStream, + ) -> ::protobuf::ProtobufResult<()> { + unimplemented!(); + } + fn default_instance() -> &'static SnapshotMetadata { + ::lazy_static::lazy_static! { + static ref INSTANCE: SnapshotMetadata = SnapshotMetadata::new_(); + } + &*INSTANCE + } + fn is_initialized(&self) -> bool { + true + } + fn merge_from( + &mut self, + _is: &mut ::protobuf::CodedInputStream, + ) -> ::protobuf::ProtobufResult<()> { + unimplemented!(); + } + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + unimplemented!(); + } + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + unimplemented!(); + } + fn write_to_bytes(&self) -> ::protobuf::ProtobufResult> { + let mut buf = Vec::new(); + if let Err(_) = ::prost::Message::encode(self, &mut buf) { + return Err(::protobuf::ProtobufError::WireError( + ::protobuf::error::WireError::Other, + )); + } + Ok(buf) + } + fn merge_from_bytes(&mut self, bytes: &[u8]) -> ::protobuf::ProtobufResult<()> { + if let Err(_) = ::prost::Message::merge(self, bytes) { + return Err(::protobuf::ProtobufError::WireError( + ::protobuf::error::WireError::Other, + )); + } + Ok(()) + } +} +impl Snapshot { + pub fn new_() -> Snapshot { + ::std::default::Default::default() + } + #[inline] + pub fn clear_data(&mut self) { + self.data.clear(); + } + #[inline] + pub fn set_data(&mut self, v: std::vec::Vec) { + self.data = v; + } + #[inline] + pub fn get_data(&self) -> &[u8] { + &self.data + } + #[inline] + pub fn mut_data(&mut self) -> &mut std::vec::Vec { + &mut self.data + } + #[inline] + pub fn take_data(&mut self) -> std::vec::Vec { + ::std::mem::replace(&mut self.data, ::std::vec::Vec::new()) + } + #[inline] + pub fn has_metadata(&self) -> bool { + self.metadata.is_some() + } + #[inline] + pub fn clear_metadata(&mut self) { + self.metadata = ::std::option::Option::None + } + #[inline] + pub fn set_metadata(&mut self, v: SnapshotMetadata) { + self.metadata = ::std::option::Option::Some(v); + } + #[inline] + pub fn get_metadata(&self) -> &SnapshotMetadata { + match self.metadata.as_ref() { + Some(v) => v, + None => ::default_instance(), + } + } + #[inline] + pub fn mut_metadata(&mut self) -> &mut SnapshotMetadata { + if self.metadata.is_none() { + self.metadata = ::std::option::Option::Some(SnapshotMetadata::default()); + } + self.metadata.as_mut().unwrap() + } + #[inline] + pub fn take_metadata(&mut self) -> SnapshotMetadata { + self.metadata + .take() + .unwrap_or_else(SnapshotMetadata::default) + } +} +impl ::protobuf::Clear for Snapshot { + fn clear(&mut self) { + ::prost::Message::clear(self); + } +} +impl ::protobuf::Message for Snapshot { + fn compute_size(&self) -> u32 { + ::prost::Message::encoded_len(self) as u32 + } + fn get_cached_size(&self) -> u32 { + ::prost::Message::encoded_len(self) as u32 + } + fn as_any(&self) -> &::std::any::Any { + self as &::std::any::Any + } + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + fn new() -> Self { + Self::new_() + } + fn write_to_with_cached_sizes( + &self, + _os: &mut ::protobuf::CodedOutputStream, + ) -> ::protobuf::ProtobufResult<()> { + unimplemented!(); + } + fn default_instance() -> &'static Snapshot { + ::lazy_static::lazy_static! { + static ref INSTANCE: Snapshot = Snapshot::new_(); + } + &*INSTANCE + } + fn is_initialized(&self) -> bool { + true + } + fn merge_from( + &mut self, + _is: &mut ::protobuf::CodedInputStream, + ) -> ::protobuf::ProtobufResult<()> { + unimplemented!(); + } + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + unimplemented!(); + } + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + unimplemented!(); + } + fn write_to_bytes(&self) -> ::protobuf::ProtobufResult> { + let mut buf = Vec::new(); + if let Err(_) = ::prost::Message::encode(self, &mut buf) { + return Err(::protobuf::ProtobufError::WireError( + ::protobuf::error::WireError::Other, + )); + } + Ok(buf) + } + fn merge_from_bytes(&mut self, bytes: &[u8]) -> ::protobuf::ProtobufResult<()> { + if let Err(_) = ::prost::Message::merge(self, bytes) { + return Err(::protobuf::ProtobufError::WireError( + ::protobuf::error::WireError::Other, + )); + } + Ok(()) + } +} +impl Message { + pub fn new_() -> Message { + ::std::default::Default::default() + } + #[inline] + pub fn clear_msg_type(&mut self) { + self.msg_type = 0 + } + #[inline] + pub fn set_msg_type_(&mut self, v: MessageType) { + self.msg_type = unsafe { ::std::mem::transmute::(v) }; + } + #[inline] + pub fn get_msg_type(&self) -> MessageType { + unsafe { ::std::mem::transmute::(self.msg_type) } + } + #[inline] + pub fn clear_to(&mut self) { + self.to = 0 + } + #[inline] + pub fn set_to(&mut self, v: u64) { + self.to = v; + } + #[inline] + pub fn get_to(&self) -> u64 { + self.to + } + #[inline] + pub fn clear_from(&mut self) { + self.from = 0 + } + #[inline] + pub fn set_from(&mut self, v: u64) { + self.from = v; + } + #[inline] + pub fn get_from(&self) -> u64 { + self.from + } + #[inline] + pub fn clear_term(&mut self) { + self.term = 0 + } + #[inline] + pub fn set_term(&mut self, v: u64) { + self.term = v; + } + #[inline] + pub fn get_term(&self) -> u64 { + self.term + } + #[inline] + pub fn clear_log_term(&mut self) { + self.log_term = 0 + } + #[inline] + pub fn set_log_term(&mut self, v: u64) { + self.log_term = v; + } + #[inline] + pub fn get_log_term(&self) -> u64 { + self.log_term + } + #[inline] + pub fn clear_index(&mut self) { + self.index = 0 + } + #[inline] + pub fn set_index(&mut self, v: u64) { + self.index = v; + } + #[inline] + pub fn get_index(&self) -> u64 { + self.index + } + #[inline] + pub fn clear_entries(&mut self) { + self.entries.clear(); + } + #[inline] + pub fn set_entries(&mut self, v: ::std::vec::Vec) { + self.entries = v; + } + #[inline] + pub fn get_entries(&self) -> &::std::vec::Vec { + &self.entries + } + #[inline] + pub fn mut_entries(&mut self) -> &mut ::std::vec::Vec { + &mut self.entries + } + #[inline] + pub fn take_entries(&mut self) -> ::std::vec::Vec { + ::std::mem::replace(&mut self.entries, ::std::vec::Vec::new()) + } + #[inline] + pub fn clear_commit(&mut self) { + self.commit = 0 + } + #[inline] + pub fn set_commit(&mut self, v: u64) { + self.commit = v; + } + #[inline] + pub fn get_commit(&self) -> u64 { + self.commit + } + #[inline] + pub fn has_snapshot(&self) -> bool { + self.snapshot.is_some() + } + #[inline] + pub fn clear_snapshot(&mut self) { + self.snapshot = ::std::option::Option::None + } + #[inline] + pub fn set_snapshot(&mut self, v: Snapshot) { + self.snapshot = ::std::option::Option::Some(v); + } + #[inline] + pub fn get_snapshot(&self) -> &Snapshot { + match self.snapshot.as_ref() { + Some(v) => v, + None => ::default_instance(), + } + } + #[inline] + pub fn mut_snapshot(&mut self) -> &mut Snapshot { + if self.snapshot.is_none() { + self.snapshot = ::std::option::Option::Some(Snapshot::default()); + } + self.snapshot.as_mut().unwrap() + } + #[inline] + pub fn take_snapshot(&mut self) -> Snapshot { + self.snapshot.take().unwrap_or_else(Snapshot::default) + } + #[inline] + pub fn clear_reject(&mut self) { + self.reject = false + } + #[inline] + pub fn set_reject(&mut self, v: bool) { + self.reject = v; + } + #[inline] + pub fn get_reject(&self) -> bool { + self.reject + } + #[inline] + pub fn clear_reject_hint(&mut self) { + self.reject_hint = 0 + } + #[inline] + pub fn set_reject_hint(&mut self, v: u64) { + self.reject_hint = v; + } + #[inline] + pub fn get_reject_hint(&self) -> u64 { + self.reject_hint + } + #[inline] + pub fn clear_context(&mut self) { + self.context.clear(); + } + #[inline] + pub fn set_context(&mut self, v: std::vec::Vec) { + self.context = v; + } + #[inline] + pub fn get_context(&self) -> &[u8] { + &self.context + } + #[inline] + pub fn mut_context(&mut self) -> &mut std::vec::Vec { + &mut self.context + } + #[inline] + pub fn take_context(&mut self) -> std::vec::Vec { + ::std::mem::replace(&mut self.context, ::std::vec::Vec::new()) + } +} +impl ::protobuf::Clear for Message { + fn clear(&mut self) { + ::prost::Message::clear(self); + } +} +impl ::protobuf::Message for Message { + fn compute_size(&self) -> u32 { + ::prost::Message::encoded_len(self) as u32 + } + fn get_cached_size(&self) -> u32 { + ::prost::Message::encoded_len(self) as u32 + } + fn as_any(&self) -> &::std::any::Any { + self as &::std::any::Any + } + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + fn new() -> Self { + Self::new_() + } + fn write_to_with_cached_sizes( + &self, + _os: &mut ::protobuf::CodedOutputStream, + ) -> ::protobuf::ProtobufResult<()> { + unimplemented!(); + } + fn default_instance() -> &'static Message { + ::lazy_static::lazy_static! { + static ref INSTANCE: Message = Message::new_(); + } + &*INSTANCE + } + fn is_initialized(&self) -> bool { + true + } + fn merge_from( + &mut self, + _is: &mut ::protobuf::CodedInputStream, + ) -> ::protobuf::ProtobufResult<()> { + unimplemented!(); + } + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + unimplemented!(); + } + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + unimplemented!(); + } + fn write_to_bytes(&self) -> ::protobuf::ProtobufResult> { + let mut buf = Vec::new(); + if let Err(_) = ::prost::Message::encode(self, &mut buf) { + return Err(::protobuf::ProtobufError::WireError( + ::protobuf::error::WireError::Other, + )); + } + Ok(buf) + } + fn merge_from_bytes(&mut self, bytes: &[u8]) -> ::protobuf::ProtobufResult<()> { + if let Err(_) = ::prost::Message::merge(self, bytes) { + return Err(::protobuf::ProtobufError::WireError( + ::protobuf::error::WireError::Other, + )); + } + Ok(()) + } +} +impl HardState { + pub fn new_() -> HardState { + ::std::default::Default::default() + } + #[inline] + pub fn clear_term(&mut self) { + self.term = 0 + } + #[inline] + pub fn set_term(&mut self, v: u64) { + self.term = v; + } + #[inline] + pub fn get_term(&self) -> u64 { + self.term + } + #[inline] + pub fn clear_vote(&mut self) { + self.vote = 0 + } + #[inline] + pub fn set_vote(&mut self, v: u64) { + self.vote = v; + } + #[inline] + pub fn get_vote(&self) -> u64 { + self.vote + } + #[inline] + pub fn clear_commit(&mut self) { + self.commit = 0 + } + #[inline] + pub fn set_commit(&mut self, v: u64) { + self.commit = v; + } + #[inline] + pub fn get_commit(&self) -> u64 { + self.commit + } +} +impl ::protobuf::Clear for HardState { + fn clear(&mut self) { + ::prost::Message::clear(self); + } +} +impl ::protobuf::Message for HardState { + fn compute_size(&self) -> u32 { + ::prost::Message::encoded_len(self) as u32 + } + fn get_cached_size(&self) -> u32 { + ::prost::Message::encoded_len(self) as u32 + } + fn as_any(&self) -> &::std::any::Any { + self as &::std::any::Any + } + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + fn new() -> Self { + Self::new_() + } + fn write_to_with_cached_sizes( + &self, + _os: &mut ::protobuf::CodedOutputStream, + ) -> ::protobuf::ProtobufResult<()> { + unimplemented!(); + } + fn default_instance() -> &'static HardState { + ::lazy_static::lazy_static! { + static ref INSTANCE: HardState = HardState::new_(); + } + &*INSTANCE + } + fn is_initialized(&self) -> bool { + true + } + fn merge_from( + &mut self, + _is: &mut ::protobuf::CodedInputStream, + ) -> ::protobuf::ProtobufResult<()> { + unimplemented!(); + } + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + unimplemented!(); + } + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + unimplemented!(); + } + fn write_to_bytes(&self) -> ::protobuf::ProtobufResult> { + let mut buf = Vec::new(); + if let Err(_) = ::prost::Message::encode(self, &mut buf) { + return Err(::protobuf::ProtobufError::WireError( + ::protobuf::error::WireError::Other, + )); + } + Ok(buf) + } + fn merge_from_bytes(&mut self, bytes: &[u8]) -> ::protobuf::ProtobufResult<()> { + if let Err(_) = ::prost::Message::merge(self, bytes) { + return Err(::protobuf::ProtobufError::WireError( + ::protobuf::error::WireError::Other, + )); + } + Ok(()) + } +} +impl ConfState { + pub fn new_() -> ConfState { + ::std::default::Default::default() + } + #[inline] + pub fn clear_nodes(&mut self) { + self.nodes.clear(); + } + #[inline] + pub fn set_nodes(&mut self, v: ::std::vec::Vec) { + self.nodes = v; + } + #[inline] + pub fn get_nodes(&self) -> &::std::vec::Vec { + &self.nodes + } + #[inline] + pub fn mut_nodes(&mut self) -> &mut ::std::vec::Vec { + &mut self.nodes + } + #[inline] + pub fn take_nodes(&mut self) -> ::std::vec::Vec { + ::std::mem::replace(&mut self.nodes, ::std::vec::Vec::new()) + } + #[inline] + pub fn clear_learners(&mut self) { + self.learners.clear(); + } + #[inline] + pub fn set_learners(&mut self, v: ::std::vec::Vec) { + self.learners = v; + } + #[inline] + pub fn get_learners(&self) -> &::std::vec::Vec { + &self.learners + } + #[inline] + pub fn mut_learners(&mut self) -> &mut ::std::vec::Vec { + &mut self.learners + } + #[inline] + pub fn take_learners(&mut self) -> ::std::vec::Vec { + ::std::mem::replace(&mut self.learners, ::std::vec::Vec::new()) + } +} +impl ::protobuf::Clear for ConfState { + fn clear(&mut self) { + ::prost::Message::clear(self); + } +} +impl ::protobuf::Message for ConfState { + fn compute_size(&self) -> u32 { + ::prost::Message::encoded_len(self) as u32 + } + fn get_cached_size(&self) -> u32 { + ::prost::Message::encoded_len(self) as u32 + } + fn as_any(&self) -> &::std::any::Any { + self as &::std::any::Any + } + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + fn new() -> Self { + Self::new_() + } + fn write_to_with_cached_sizes( + &self, + _os: &mut ::protobuf::CodedOutputStream, + ) -> ::protobuf::ProtobufResult<()> { + unimplemented!(); + } + fn default_instance() -> &'static ConfState { + ::lazy_static::lazy_static! { + static ref INSTANCE: ConfState = ConfState::new_(); + } + &*INSTANCE + } + fn is_initialized(&self) -> bool { + true + } + fn merge_from( + &mut self, + _is: &mut ::protobuf::CodedInputStream, + ) -> ::protobuf::ProtobufResult<()> { + unimplemented!(); + } + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + unimplemented!(); + } + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + unimplemented!(); + } + fn write_to_bytes(&self) -> ::protobuf::ProtobufResult> { + let mut buf = Vec::new(); + if let Err(_) = ::prost::Message::encode(self, &mut buf) { + return Err(::protobuf::ProtobufError::WireError( + ::protobuf::error::WireError::Other, + )); + } + Ok(buf) + } + fn merge_from_bytes(&mut self, bytes: &[u8]) -> ::protobuf::ProtobufResult<()> { + if let Err(_) = ::prost::Message::merge(self, bytes) { + return Err(::protobuf::ProtobufError::WireError( + ::protobuf::error::WireError::Other, + )); + } + Ok(()) + } +} +impl ConfChange { + pub fn new_() -> ConfChange { + ::std::default::Default::default() + } + #[inline] + pub fn clear_id(&mut self) { + self.id = 0 + } + #[inline] + pub fn set_id(&mut self, v: u64) { + self.id = v; + } + #[inline] + pub fn get_id(&self) -> u64 { + self.id + } + #[inline] + pub fn clear_change_type(&mut self) { + self.change_type = 0 + } + #[inline] + pub fn set_change_type_(&mut self, v: ConfChangeType) { + self.change_type = unsafe { ::std::mem::transmute::(v) }; + } + #[inline] + pub fn get_change_type(&self) -> ConfChangeType { + unsafe { ::std::mem::transmute::(self.change_type) } + } + #[inline] + pub fn clear_node_id(&mut self) { + self.node_id = 0 + } + #[inline] + pub fn set_node_id(&mut self, v: u64) { + self.node_id = v; + } + #[inline] + pub fn get_node_id(&self) -> u64 { + self.node_id + } + #[inline] + pub fn clear_context(&mut self) { + self.context.clear(); + } + #[inline] + pub fn set_context(&mut self, v: std::vec::Vec) { + self.context = v; + } + #[inline] + pub fn get_context(&self) -> &[u8] { + &self.context + } + #[inline] + pub fn mut_context(&mut self) -> &mut std::vec::Vec { + &mut self.context + } + #[inline] + pub fn take_context(&mut self) -> std::vec::Vec { + ::std::mem::replace(&mut self.context, ::std::vec::Vec::new()) + } + #[inline] + pub fn has_configuration(&self) -> bool { + self.configuration.is_some() + } + #[inline] + pub fn clear_configuration(&mut self) { + self.configuration = ::std::option::Option::None + } + #[inline] + pub fn set_configuration(&mut self, v: ConfState) { + self.configuration = ::std::option::Option::Some(v); + } + #[inline] + pub fn get_configuration(&self) -> &ConfState { + match self.configuration.as_ref() { + Some(v) => v, + None => ::default_instance(), + } + } + #[inline] + pub fn mut_configuration(&mut self) -> &mut ConfState { + if self.configuration.is_none() { + self.configuration = ::std::option::Option::Some(ConfState::default()); + } + self.configuration.as_mut().unwrap() + } + #[inline] + pub fn take_configuration(&mut self) -> ConfState { + self.configuration.take().unwrap_or_else(ConfState::default) + } + #[inline] + pub fn clear_start_index(&mut self) { + self.start_index = 0 + } + #[inline] + pub fn set_start_index(&mut self, v: u64) { + self.start_index = v; + } + #[inline] + pub fn get_start_index(&self) -> u64 { + self.start_index + } +} +impl ::protobuf::Clear for ConfChange { + fn clear(&mut self) { + ::prost::Message::clear(self); + } +} +impl ::protobuf::Message for ConfChange { + fn compute_size(&self) -> u32 { + ::prost::Message::encoded_len(self) as u32 + } + fn get_cached_size(&self) -> u32 { + ::prost::Message::encoded_len(self) as u32 + } + fn as_any(&self) -> &::std::any::Any { + self as &::std::any::Any + } + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + fn new() -> Self { + Self::new_() + } + fn write_to_with_cached_sizes( + &self, + _os: &mut ::protobuf::CodedOutputStream, + ) -> ::protobuf::ProtobufResult<()> { + unimplemented!(); + } + fn default_instance() -> &'static ConfChange { + ::lazy_static::lazy_static! { + static ref INSTANCE: ConfChange = ConfChange::new_(); + } + &*INSTANCE + } + fn is_initialized(&self) -> bool { + true + } + fn merge_from( + &mut self, + _is: &mut ::protobuf::CodedInputStream, + ) -> ::protobuf::ProtobufResult<()> { + unimplemented!(); + } + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + unimplemented!(); + } + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + unimplemented!(); + } + fn write_to_bytes(&self) -> ::protobuf::ProtobufResult> { + let mut buf = Vec::new(); + if let Err(_) = ::prost::Message::encode(self, &mut buf) { + return Err(::protobuf::ProtobufError::WireError( + ::protobuf::error::WireError::Other, + )); + } + Ok(buf) + } + fn merge_from_bytes(&mut self, bytes: &[u8]) -> ::protobuf::ProtobufResult<()> { + if let Err(_) = ::prost::Message::merge(self, bytes) { + return Err(::protobuf::ProtobufError::WireError( + ::protobuf::error::WireError::Other, + )); + } + Ok(()) + } +} +impl EntryType { + pub fn values() -> &'static [Self] { + static VALUES: &'static [EntryType] = &[EntryType::EntryNormal, EntryType::EntryConfChange]; + VALUES + } +} +impl MessageType { + pub fn values() -> &'static [Self] { + static VALUES: &'static [MessageType] = &[ + MessageType::MsgHup, + MessageType::MsgBeat, + MessageType::MsgPropose, + MessageType::MsgAppend, + MessageType::MsgAppendResponse, + MessageType::MsgRequestVote, + MessageType::MsgRequestVoteResponse, + MessageType::MsgSnapshot, + MessageType::MsgHeartbeat, + MessageType::MsgHeartbeatResponse, + MessageType::MsgUnreachable, + MessageType::MsgSnapStatus, + MessageType::MsgCheckQuorum, + MessageType::MsgTransferLeader, + MessageType::MsgTimeoutNow, + MessageType::MsgReadIndex, + MessageType::MsgReadIndexResp, + MessageType::MsgRequestPreVote, + MessageType::MsgRequestPreVoteResponse, + ]; + VALUES + } +} +impl ConfChangeType { + pub fn values() -> &'static [Self] { + static VALUES: &'static [ConfChangeType] = &[ + ConfChangeType::AddNode, + ConfChangeType::RemoveNode, + ConfChangeType::AddLearnerNode, + ConfChangeType::BeginMembershipChange, + ConfChangeType::FinalizeMembershipChange, + ]; + VALUES + } +} diff --git a/src/raft.rs b/src/raft.rs index c6e721fca..1a4c05fd4 100644 --- a/src/raft.rs +++ b/src/raft.rs @@ -27,20 +27,21 @@ use std::cmp; -use eraftpb::{ +use crate::eraftpb::{ ConfChange, ConfChangeType, Entry, EntryType, HardState, Message, MessageType, Snapshot, }; use hashbrown::{HashMap, HashSet}; -use protobuf; -use protobuf::RepeatedField; +use prost::Message as ProstMsg; use rand::{self, Rng}; use super::errors::{Error, Result, StorageError}; -use super::progress::{CandidacyStatus, Configuration, Progress, ProgressSet, ProgressState}; -use super::raft_log::{self, RaftLog}; +use super::progress::progress_set::{CandidacyStatus, Configuration, ProgressSet}; +use super::progress::{Progress, ProgressState}; +use super::raft_log::RaftLog; use super::read_only::{ReadOnly, ReadOnlyOption, ReadState}; use super::storage::Storage; use super::Config; +use crate::util; // CAMPAIGN_PRE_ELECTION represents the first phase of a normal election when // Config.pre_vote is true. @@ -189,6 +190,7 @@ pub struct Raft { pub pre_vote: bool, skip_bcast_commit: bool, + batch_append: bool, heartbeat_timeout: usize, election_timeout: usize, @@ -209,7 +211,7 @@ trait AssertSend: Send {} impl AssertSend for Raft {} fn new_message(to: u64, field_type: MessageType, from: Option) -> Message { - let mut m = Message::new(); + let mut m = Message::new_(); m.set_to(to); if let Some(id) = from { m.set_from(id); @@ -234,26 +236,13 @@ impl Raft { c.validate()?; let raft_state = store.initial_state()?; let conf_state = &raft_state.conf_state; - let raft_log = RaftLog::new(store, c.tag.clone()); - let mut peers: &[u64] = &c.peers; - let mut learners: &[u64] = &c.learners; - if !conf_state.get_nodes().is_empty() || !conf_state.get_learners().is_empty() { - if !peers.is_empty() || !learners.is_empty() { - // TODO: the peers argument is always nil except in - // tests; the argument should be removed and these tests should be - // updated to specify their nodes through a snap - panic!( - "{} cannot specify both new(peers/learners) and ConfState.(Nodes/Learners)", - c.tag - ) - } - peers = conf_state.get_nodes(); - learners = conf_state.get_learners(); - } + let peers = conf_state.get_nodes(); + let learners = conf_state.get_learners(); + let mut r = Raft { id: c.id, read_states: Default::default(), - raft_log, + raft_log: RaftLog::new(store, c.tag.clone()), max_inflight: c.max_inflight_msgs, max_msg_size: c.max_size_per_msg, prs: Some(ProgressSet::with_capacity(peers.len(), learners.len())), @@ -279,6 +268,7 @@ impl Raft { max_election_timeout: c.max_election_tick(), skip_bcast_commit: c.skip_bcast_commit, tag: c.tag.to_owned(), + batch_append: c.batch_append, }; for p in peers { let pr = Progress::new(1, r.max_inflight); @@ -296,7 +286,7 @@ impl Raft { } } - if raft_state.hard_state != HardState::new() { + if raft_state.hard_state != HardState::new_() { r.load_state(&raft_state.hard_state); } if c.applied > 0 { @@ -371,7 +361,7 @@ impl Raft { /// Returns a value representing the hardstate at the time of calling. pub fn hard_state(&self) -> HardState { - let mut hs = HardState::new(); + let mut hs = HardState::new_(); hs.set_term(self.term); hs.set_vote(self.vote); hs.set_commit(self.raft_log.committed); @@ -439,10 +429,16 @@ impl Raft { pub fn began_membership_change_at(&self) -> Option { self.pending_membership_change .as_ref() - .map(|v| v.get_start_index()) + .map(ConfChange::get_start_index) + } + + /// Set whether batch append msg at runtime. + #[inline] + pub fn set_batch_append(&mut self, batch_append: bool) { + self.batch_append = batch_append; } - /// send persists state to stable storage and then sends to its mailbox. + // send persists state to stable storage and then sends to its mailbox. fn send(&mut self, mut m: Message) { debug!("Sending from {} to {}: {:?}", self.id, m.get_to(), m); m.set_from(self.id); @@ -552,22 +548,36 @@ impl Raft { m.set_msg_type(MessageType::MsgAppend); m.set_index(pr.next_idx - 1); m.set_log_term(term); - m.set_entries(RepeatedField::from_vec(ents)); + m.set_entries(ents); m.set_commit(self.raft_log.committed); if !m.get_entries().is_empty() { - match pr.state { - ProgressState::Replicate => { - let last = m.get_entries().last().unwrap().get_index(); - pr.optimistic_update(last); - pr.ins.add(last); + let last = m.get_entries().last().unwrap().get_index(); + pr.update_state(last); + } + } + + fn try_batching(&mut self, to: u64, pr: &mut Progress, ents: &mut Vec) -> bool { + // if MsgAppend for the reciver already exists, try_batching + // will append the entries to the existing MsgAppend + let mut is_batched = false; + for msg in &mut self.msgs { + if msg.get_msg_type() == MessageType::MsgAppend && msg.get_to() == to { + if !ents.is_empty() { + if !util::is_continuous_ents(msg, ents) { + return is_batched; + } + let mut batched_entries = msg.take_entries(); + batched_entries.append(ents); + msg.set_entries(batched_entries); + let last_idx = msg.get_entries().last().unwrap().get_index(); + pr.update_state(last_idx); } - ProgressState::Probe => pr.pause(), - _ => panic!( - "{} is sending append in unhandled state {:?}", - self.tag, pr.state - ), + msg.set_commit(self.raft_log.committed); + is_batched = true; + break; } } + is_batched } /// Sends RPC, with entries to the given peer. @@ -582,22 +592,31 @@ impl Raft { } let term = self.raft_log.term(pr.next_idx - 1); let ents = self.raft_log.entries(pr.next_idx, self.max_msg_size); - let mut m = Message::new(); + let mut m = Message::new_(); m.set_to(to); if term.is_err() || ents.is_err() { // send snapshot if we failed to get term or entries trace!( - "{} Skipping sending to {}, term: {:?}, ents: {:?}", + "{} Skipping sending to {}, term: {:?}, index: {}, ents: {:?}", self.tag, to, term, + pr.next_idx, ents, ); if !self.prepare_send_snapshot(&mut m, pr, to) { return; } } else { - self.prepare_send_entries(&mut m, pr, term.unwrap(), ents.unwrap()); + let mut ents = ents.unwrap(); + if self.batch_append { + let batched = self.try_batching(to, pr, &mut ents); + if batched { + return; + } + } + let term = term.unwrap(); + self.prepare_send_entries(&mut m, pr, term, ents); } self.send(m); } @@ -610,7 +629,7 @@ impl Raft { // or it might not have all the committed entries. // The leader MUST NOT forward the follower's commit to // an unmatched index. - let mut m = Message::new(); + let mut m = Message::new_(); m.set_to(to); m.set_msg_type(MessageType::MsgHeartbeat); let commit = cmp::min(pr.matched, self.raft_log.committed); @@ -683,10 +702,11 @@ impl Raft { } fn append_finalize_conf_change_entry(&mut self) { - let mut conf_change = ConfChange::new(); + let mut conf_change = ConfChange::new_(); conf_change.set_change_type(ConfChangeType::FinalizeMembershipChange); - let data = protobuf::Message::write_to_bytes(&conf_change).unwrap(); - let mut entry = Entry::new(); + let mut data = Vec::with_capacity(ProstMsg::encoded_len(&conf_change)); + conf_change.encode(&mut data).unwrap(); + let mut entry = Entry::new_(); entry.set_entry_type(EntryType::EntryConfChange); entry.set_data(data); // Index/Term set here. @@ -762,7 +782,7 @@ impl Raft { self.election_elapsed = 0; let m = new_message(INVALID_ID, MessageType::MsgHup, Some(self.id)); - self.step(m).is_ok(); + let _ = self.step(m); true } @@ -778,7 +798,7 @@ impl Raft { if self.check_quorum { let m = new_message(INVALID_ID, MessageType::MsgCheckQuorum, Some(self.id)); has_ready = true; - self.step(m).is_ok(); + let _ = self.step(m); } if self.state == StateRole::Leader && self.lead_transferee.is_some() { self.abort_leader_transfer() @@ -793,7 +813,7 @@ impl Raft { self.heartbeat_elapsed = 0; has_ready = true; let m = new_message(INVALID_ID, MessageType::MsgBeat, Some(self.id)); - self.step(m).is_ok(); + let _ = self.step(m); } has_ready } @@ -880,7 +900,7 @@ impl Raft { // could be expensive. self.pending_conf_index = self.raft_log.last_index(); - self.append_entry(&mut [Entry::new()]); + self.append_entry(&mut [Entry::new_()]); // In most cases, we append only a new entry marked with an index and term. // In the specific case of a node recovering while in the middle of a membership change, @@ -979,7 +999,6 @@ impl Raft { /// message from a peer. pub fn step(&mut self, m: Message) -> Result<()> { // Handle the message term, which may result in our stepping down to a follower. - if m.get_term() == 0 { // local message } else if m.get_term() > self.term { @@ -1120,11 +1139,7 @@ impl Raft { if self.state != StateRole::Leader { let ents = self .raft_log - .slice( - self.raft_log.applied + 1, - self.raft_log.committed + 1, - raft_log::NO_LIMIT, - ) + .slice(self.raft_log.applied + 1, self.raft_log.committed + 1, None) .expect("unexpected error getting unapplied entries"); let n = self.num_pending_conf(&ents); if n != 0 && self.raft_log.committed > self.raft_log.applied { @@ -1149,12 +1164,14 @@ impl Raft { } } MessageType::MsgRequestVote | MessageType::MsgRequestPreVote => { + debug_assert!(m.get_log_term() != 0, "{:?} log term can't be 0", m); + // We can vote if this is a repeat of a vote we've already cast... let can_vote = (self.vote == m.get_from()) || // ...we haven't voted and we don't think there's a leader yet in this term... (self.vote == INVALID_ID && self.leader_id == INVALID_ID) || // ...or this is a PreVote for a future term... - (m.msg_type == MessageType::MsgRequestPreVote && m.get_term() > self.term); + (m.msg_type == MessageType::MsgRequestPreVote as i32 && m.get_term() > self.term); // ...and we believe the candidate is up to date. if can_vote && self.raft_log.is_up_to_date(m.get_index(), m.get_log_term()) { // When responding to Msg{Pre,}Vote messages we include the term @@ -1233,9 +1250,8 @@ impl Raft { }; self.set_pending_membership_change(conf_change.clone()); - let max_inflights = self.max_inflight; - self.mut_prs() - .begin_membership_change(configuration, Progress::new(1, max_inflights))?; + let pr = Progress::new(self.raft_log.last_index() + 1, self.max_inflight); + self.mut_prs().begin_membership_change(configuration, pr)?; Ok(()) } @@ -1404,7 +1420,7 @@ impl Raft { m: &Message, prs: &mut ProgressSet, send_append: &mut bool, - more_to_send: &mut Option, + more_to_send: &mut Vec, ) { // Update the node. Drop the value explicitly since we'll check the qourum after. { @@ -1440,12 +1456,12 @@ impl Raft { }; self.read_states.push(rs); } else { - let mut to_send = Message::new(); + let mut to_send = Message::new_(); to_send.set_to(req.get_from()); to_send.set_msg_type(MessageType::MsgReadIndexResp); to_send.set_index(rs.index); to_send.set_entries(req.take_entries()); - *more_to_send = Some(to_send); + more_to_send.push(to_send); } } } @@ -1535,7 +1551,7 @@ impl Raft { send_append: &mut bool, old_paused: &mut bool, maybe_commit: &mut bool, - more_to_send: &mut Option, + more_to_send: &mut Vec, ) { if self.prs().get(m.get_from()).is_none() { debug!("{} no progress available for {}", self.tag, m.get_from()); @@ -1625,7 +1641,7 @@ impl Raft { configuration [index {}, applied {}]", e, self.pending_conf_index, self.raft_log.applied ); - *e = Entry::new(); + *e = Entry::new_(); e.set_entry_type(EntryType::EntryNormal); } else { self.pending_conf_index = self.raft_log.last_index() + i as u64 + 1; @@ -1657,7 +1673,7 @@ impl Raft { self.bcast_heartbeat_with_ctx(Some(ctx)); } ReadOnlyOption::LeaseBased => { - let mut read_index = self.raft_log.committed; + let read_index = self.raft_log.committed; if m.get_from() == INVALID_ID || m.get_from() == self.id { // from local member let rs = ReadState { @@ -1666,7 +1682,7 @@ impl Raft { }; self.read_states.push(rs); } else { - let mut to_send = Message::new(); + let mut to_send = Message::new_(); to_send.set_to(m.get_from()); to_send.set_msg_type(MessageType::MsgReadIndexResp); to_send.set_index(read_index); @@ -1697,7 +1713,7 @@ impl Raft { let mut send_append = false; let mut maybe_commit = false; let mut old_paused = false; - let mut more_to_send = None; + let mut more_to_send = vec![]; self.check_message_with_progress( &mut m, &mut send_append, @@ -1723,8 +1739,10 @@ impl Raft { self.send_append(from, prs.get_mut(from).unwrap()); self.set_prs(prs); } - if let Some(to_send) = more_to_send { - self.send(to_send) + if !more_to_send.is_empty() { + for to_send in more_to_send.drain(..) { + self.send(to_send); + } } Ok(()) @@ -1907,14 +1925,16 @@ impl Raft { pub fn handle_append_entries(&mut self, m: &Message) { if m.get_index() < self.raft_log.committed { debug!("{} Got message with lower index than committed.", self.tag); - let mut to_send = Message::new(); + let mut to_send = Message::new_(); to_send.set_to(m.get_from()); to_send.set_msg_type(MessageType::MsgAppendResponse); to_send.set_index(self.raft_log.committed); self.send(to_send); return; } - let mut to_send = Message::new(); + debug_assert!(m.get_log_term() != 0, "{:?} log term can't be 0", m); + + let mut to_send = Message::new_(); to_send.set_to(m.get_from()); to_send.set_msg_type(MessageType::MsgAppendResponse); match self.raft_log.maybe_append( @@ -1950,7 +1970,7 @@ impl Raft { /// For a message, commit and send out heartbeat. pub fn handle_heartbeat(&mut self, mut m: Message) { self.raft_log.commit_to(m.get_commit()); - let mut to_send = Message::new(); + let mut to_send = Message::new_(); to_send.set_to(m.get_from()); to_send.set_msg_type(MessageType::MsgHeartbeatResponse); to_send.set_context(m.take_context()); @@ -1958,6 +1978,7 @@ impl Raft { } fn handle_snapshot(&mut self, mut m: Message) { + debug_assert!(m.get_term() != 0, "{:?} term can't be 0", m); let (sindex, sterm) = ( m.get_snapshot().get_metadata().get_index(), m.get_snapshot().get_metadata().get_term(), @@ -1967,7 +1988,7 @@ impl Raft { "{} [commit: {}, term: {}] restored snapshot [index: {}, term: {}]", self.tag, self.term, self.raft_log.committed, sindex, sterm ); - let mut to_send = Message::new(); + let mut to_send = Message::new_(); to_send.set_to(m.get_from()); to_send.set_msg_type(MessageType::MsgAppendResponse); to_send.set_index(self.raft_log.last_index()); @@ -1977,7 +1998,7 @@ impl Raft { "{} [commit: {}] ignored snapshot [index: {}, term: {}]", self.tag, self.raft_log.committed, sindex, sterm ); - let mut to_send = Message::new(); + let mut to_send = Message::new_(); to_send.set_to(m.get_from()); to_send.set_msg_type(MessageType::MsgAppendResponse); to_send.set_index(self.raft_log.committed); @@ -2037,7 +2058,7 @@ impl Raft { self.prs = Some(prs); if meta.get_pending_membership_change_index() > 0 { let cs = meta.get_pending_membership_change().clone(); - let mut conf_change = ConfChange::new(); + let mut conf_change = ConfChange::new_(); conf_change.set_change_type(ConfChangeType::BeginMembershipChange); conf_change.set_configuration(cs); conf_change.set_start_index(meta.get_pending_membership_change_index()); @@ -2085,12 +2106,14 @@ impl Raft { /// /// ```rust /// use raft::{Raft, Config, storage::MemStorage, eraftpb::ConfState}; + /// use raft::raw_node::RawNode; /// let config = Config { /// id: 1, - /// peers: vec![1], /// ..Default::default() /// }; - /// let mut raft = Raft::new(&config, MemStorage::default()).unwrap(); + /// let store = MemStorage::new_with_conf_state((vec![1], vec![])); + /// let mut node = RawNode::new(&config, store).unwrap(); + /// let mut raft = node.raft; /// raft.become_candidate(); /// raft.become_leader(); // It must be a leader! /// @@ -2120,19 +2143,20 @@ impl Raft { ); let destination_index = self.raft_log.last_index() + 1; // Prep a configuration change to append. - let mut conf_change = ConfChange::new(); + let mut conf_change = ConfChange::new_(); conf_change.set_change_type(ConfChangeType::BeginMembershipChange); conf_change.set_configuration(config.into()); conf_change.set_start_index(destination_index); - let data = protobuf::Message::write_to_bytes(&conf_change)?; - let mut entry = Entry::new(); + let mut data = Vec::with_capacity(ProstMsg::encoded_len(&conf_change)); + conf_change.encode(&mut data).unwrap(); + let mut entry = Entry::new_(); entry.set_entry_type(EntryType::EntryConfChange); entry.set_data(data); - let mut message = Message::new(); + let mut message = Message::new_(); message.set_msg_type(MessageType::MsgPropose); message.set_from(self.id); message.set_index(destination_index); - message.set_entries(RepeatedField::from_vec(vec![entry])); + message.set_entries(vec![entry]); // `append_entry` sets term, index for us. self.step(message)?; Ok(()) diff --git a/src/raft_log.rs b/src/raft_log.rs index 4d8942c9f..e616c8775 100644 --- a/src/raft_log.rs +++ b/src/raft_log.rs @@ -27,14 +27,14 @@ use std::cmp; -use eraftpb::{Entry, Snapshot}; +use crate::eraftpb::{Entry, Snapshot}; -use errors::{Error, Result, StorageError}; -use log_unstable::Unstable; -use storage::Storage; -use util; +use crate::errors::{Error, Result, StorageError}; +use crate::log_unstable::Unstable; +use crate::storage::Storage; +use crate::util; -pub use util::NO_LIMIT; +pub use crate::util::NO_LIMIT; /// Raft log implementation #[derive(Default)] @@ -326,7 +326,8 @@ impl RaftLog { } /// Returns entries starting from a particular index and not exceeding a bytesize. - pub fn entries(&self, idx: u64, max_size: u64) -> Result> { + pub fn entries(&self, idx: u64, max_size: impl Into>) -> Result> { + let max_size = max_size.into(); let last = self.last_index(); if idx > last { return Ok(Vec::new()); @@ -337,7 +338,7 @@ impl RaftLog { /// Returns all the entries. pub fn all_entries(&self) -> Vec { let first_index = self.first_index(); - match self.entries(first_index, NO_LIMIT) { + match self.entries(first_index, None) { Err(e) => { // try again if there was a racing compaction if e == Error::Store(StorageError::Compacted) { @@ -364,7 +365,7 @@ impl RaftLog { let offset = cmp::max(since_idx + 1, self.first_index()); let committed = self.committed; if committed + 1 > offset { - match self.slice(offset, committed + 1, NO_LIMIT) { + match self.slice(offset, committed + 1, None) { Ok(vec) => return Some(vec), Err(e) => panic!("{} {}", self.tag, e), } @@ -434,7 +435,13 @@ impl RaftLog { /// Grabs a slice of entries from the raft. Unlike a rust slice pointer, these are /// returned by value. The result is truncated to the max_size in bytes. - pub fn slice(&self, low: u64, high: u64, max_size: u64) -> Result> { + pub fn slice( + &self, + low: u64, + high: u64, + max_size: impl Into>, + ) -> Result> { + let max_size = max_size.into(); let err = self.must_check_outofbounds(low, high); if err.is_some() { return Err(err.unwrap()); @@ -495,29 +502,29 @@ impl RaftLog { mod test { use std::panic::{self, AssertUnwindSafe}; - use eraftpb; - use errors::{Error, StorageError}; + use crate::eraftpb; + use crate::errors::{Error, StorageError}; + use crate::raft_log::{self, RaftLog}; + use crate::storage::MemStorage; use harness::setup_for_test; - use protobuf; - use raft_log::{self, RaftLog}; - use storage::MemStorage; + use prost::Message as ProstMsg; fn new_raft_log(s: MemStorage) -> RaftLog { RaftLog::new(s, String::from("")) } fn new_entry(index: u64, term: u64) -> eraftpb::Entry { - let mut e = eraftpb::Entry::new(); + let mut e = eraftpb::Entry::new_(); e.set_term(term); e.set_index(index); e } fn new_snapshot(meta_index: u64, meta_term: u64) -> eraftpb::Snapshot { - let mut meta = eraftpb::SnapshotMetadata::new(); + let mut meta = eraftpb::SnapshotMetadata::new_(); meta.set_index(meta_index); meta.set_term(meta_term); - let mut snapshot = eraftpb::Snapshot::new(); + let mut snapshot = eraftpb::Snapshot::new_(); snapshot.set_metadata(meta); snapshot } @@ -639,7 +646,7 @@ mod test { if index != windex { panic!("#{}: last_index = {}, want {}", i, index, windex); } - match raft_log.entries(1, raft_log::NO_LIMIT) { + match raft_log.entries(1, None) { Err(e) => panic!("#{}: unexpected error {}", i, e), Ok(ref g) if g != wents => panic!("#{}: logEnts = {:?}, want {:?}", i, &g, &wents), _ => { @@ -700,9 +707,7 @@ mod test { assert_eq!(prev + 1, raft_log.last_index()); prev = raft_log.last_index(); - let ents = raft_log - .entries(prev, raft_log::NO_LIMIT) - .expect("unexpected error"); + let ents = raft_log.entries(prev, None).expect("unexpected error"); assert_eq!(1, ents.len()); } @@ -966,7 +971,8 @@ mod test { let (offset, num) = (100u64, 100u64); let (last, half) = (offset + num, offset + num / 2); let halfe = new_entry(half, half); - let halfe_size = u64::from(protobuf::Message::compute_size(&halfe)); + + let halfe_size = ProstMsg::encoded_len(&halfe) as u64; let store = MemStorage::new(); store @@ -1067,7 +1073,8 @@ mod test { ]; for (i, &(from, to, limit, ref w, wpanic)) in tests.iter().enumerate() { - let res = panic::catch_unwind(AssertUnwindSafe(|| raft_log.slice(from, to, limit))); + let res = + panic::catch_unwind(AssertUnwindSafe(|| raft_log.slice(from, to, Some(limit)))); if res.is_err() ^ wpanic { panic!("#{}: panic = {}, want {}: {:?}", i, true, false, res); } @@ -1269,7 +1276,7 @@ mod test { raft_log.last_index() - ents_len + 1, raft_log.last_index() + 1, ); - let gents = raft_log.slice(from, to, raft_log::NO_LIMIT).expect(""); + let gents = raft_log.slice(from, to, None).expect(""); if &gents != ents { panic!("#{}: appended entries = {:?}, want {:?}", i, gents, ents); } @@ -1310,24 +1317,24 @@ mod test { setup_for_test(); let tests = vec![ // out of upper bound - (1000, vec![1001u64], vec![0usize], false), + (1000, vec![1001u64], vec![0usize], true), ( 1000, vec![300, 500, 800, 900], vec![700, 500, 200, 100], - true, + false, ), // out of lower bound - (1000, vec![300, 299], vec![700, 0], false), + (1000, vec![300, 299], vec![700, 700], false), ]; - for (i, &(last_index, ref compact, ref wleft, wallow)) in tests.iter().enumerate() { + for (i, &(index, ref compact, ref wleft, should_panic)) in tests.iter().enumerate() { let store = MemStorage::new(); - for i in 1u64..=last_index { + for i in 1u64..index { store.wl().append(&[new_entry(i, 0)]).expect(""); } let mut raft_log = new_raft_log(store); - raft_log.maybe_commit(last_index, 0); + raft_log.maybe_commit(index - 1, 0); let committed = raft_log.committed; #[allow(deprecated)] raft_log.applied_to(committed); @@ -1335,22 +1342,14 @@ mod test { for (j, idx) in compact.into_iter().enumerate() { let res = panic::catch_unwind(AssertUnwindSafe(|| raft_log.store.wl().compact(*idx))); - if res.is_err() { - if wallow { - panic!("#{}: has_panic = true, want false: {:?}", i, res); - } - continue; + if !(should_panic ^ res.is_ok()) { + panic!("#{}: should_panic: {}, but got: {:?}", i, should_panic, res); } - let compact_res = res.unwrap(); - if let Err(e) = compact_res { - if wallow { - panic!("#{}.{} allow = false, want true, error: {}", i, j, e); + if !should_panic { + let l = raft_log.all_entries().len(); + if l != wleft[j] { + panic!("#{}.{} len = {}, want {}", i, j, l, wleft[j]); } - continue; - } - let l = raft_log.all_entries().len(); - if l != wleft[j] { - panic!("#{}.{} len = {}, want {}", i, j, l, wleft[j]); } } } diff --git a/src/raw_node.rs b/src/raw_node.rs index ed0f10132..9bc24392b 100644 --- a/src/raw_node.rs +++ b/src/raw_node.rs @@ -32,18 +32,16 @@ use std::mem; -use eraftpb::{ +use prost::Message as ProstMsg; + +use crate::config::Config; +use crate::eraftpb::{ ConfChange, ConfChangeType, ConfState, Entry, EntryType, HardState, Message, MessageType, Snapshot, }; -use protobuf::{self, RepeatedField}; - -use super::config::Config; -use super::errors::{Error, Result}; -use super::read_only::ReadState; -use super::Status; -use super::Storage; -use super::{Raft, SoftState, INVALID_ID}; +use crate::errors::{Error, Result}; +use crate::read_only::ReadState; +use crate::{Raft, SoftState, Status, Storage, INVALID_ID}; /// Represents a Peer node in the cluster. #[derive(Debug, Default)] @@ -219,8 +217,8 @@ pub struct RawNode { impl RawNode { #[allow(clippy::new_ret_no_self)] - /// Create a new RawNode given some [`Config`](../struct.Config.html) and a list of [`Peer`](raw_node/struct.Peer.html)s. - pub fn new(config: &Config, store: T, mut peers: Vec) -> Result> { + /// Create a new RawNode given some [`Config`](../struct.Config.html). + pub fn new(config: &Config, store: T) -> Result> { assert_ne!(config.id, 0, "config.id must not be zero"); let r = Raft::new(config, store)?; let mut rn = RawNode { @@ -228,38 +226,8 @@ impl RawNode { prev_hs: Default::default(), prev_ss: Default::default(), }; - let last_index = rn.raft.get_store().last_index().expect(""); - if last_index == 0 { - rn.raft.become_follower(1, INVALID_ID); - let mut ents = Vec::with_capacity(peers.len()); - for (i, peer) in peers.iter_mut().enumerate() { - let mut cc = ConfChange::new(); - cc.set_change_type(ConfChangeType::AddNode); - cc.set_node_id(peer.id); - if let Some(ctx) = peer.context.take() { - cc.set_context(ctx); - } - let data = - protobuf::Message::write_to_bytes(&cc).expect("unexpected marshal error"); - let mut e = Entry::new(); - e.set_entry_type(EntryType::EntryConfChange); - e.set_term(1); - e.set_index(i as u64 + 1); - e.set_data(data); - ents.push(e); - } - rn.raft.raft_log.append(&ents); - rn.raft.raft_log.committed = ents.len() as u64; - for peer in peers { - rn.raft.add_node(peer.id)?; - } - } + rn.prev_hs = rn.raft.hard_state(); rn.prev_ss = rn.raft.soft_state(); - if last_index == 0 { - rn.prev_hs = Default::default(); - } else { - rn.prev_hs = rn.raft.hard_state(); - } Ok(rn) } @@ -268,7 +236,7 @@ impl RawNode { self.prev_ss = rd.ss.unwrap(); } if let Some(e) = rd.hs { - if e != HardState::new() { + if e != HardState::new_() { self.prev_hs = e; } } @@ -276,7 +244,7 @@ impl RawNode { let e = rd.entries.last().unwrap(); self.raft.raft_log.stable_to(e.get_index(), e.get_term()); } - if rd.snapshot != Snapshot::new() { + if rd.snapshot != Snapshot::new_() { self.raft .raft_log .stable_snap_to(rd.snapshot.get_metadata().get_index()); @@ -300,34 +268,35 @@ impl RawNode { /// Campaign causes this RawNode to transition to candidate state. pub fn campaign(&mut self) -> Result<()> { - let mut m = Message::new(); + let mut m = Message::new_(); m.set_msg_type(MessageType::MsgHup); self.raft.step(m) } /// Propose proposes data be appended to the raft log. pub fn propose(&mut self, context: Vec, data: Vec) -> Result<()> { - let mut m = Message::new(); + let mut m = Message::new_(); m.set_msg_type(MessageType::MsgPropose); m.set_from(self.raft.id); - let mut e = Entry::new(); + let mut e = Entry::new_(); e.set_data(data); e.set_context(context); - m.set_entries(RepeatedField::from_vec(vec![e])); + m.set_entries(vec![e]); self.raft.step(m) } /// ProposeConfChange proposes a config change. #[cfg_attr(feature = "cargo-clippy", allow(clippy::needless_pass_by_value))] pub fn propose_conf_change(&mut self, context: Vec, cc: ConfChange) -> Result<()> { - let data = protobuf::Message::write_to_bytes(&cc)?; - let mut m = Message::new(); + let mut data = Vec::with_capacity(ProstMsg::encoded_len(&cc)); + cc.encode(&mut data)?; + let mut m = Message::new_(); m.set_msg_type(MessageType::MsgPropose); - let mut e = Entry::new(); + let mut e = Entry::new_(); e.set_entry_type(EntryType::EntryConfChange); e.set_data(data); e.set_context(context); - m.set_entries(RepeatedField::from_vec(vec![e])); + m.set_entries(vec![e]); self.raft.step(m) } @@ -343,7 +312,7 @@ impl RawNode { if cc.get_node_id() == INVALID_ID && cc.get_change_type() != ConfChangeType::BeginMembershipChange { - let mut cs = ConfState::new(); + let mut cs = ConfState::new_(); cs.set_nodes(self.raft.prs().voter_ids().iter().cloned().collect()); cs.set_learners(self.raft.prs().learner_ids().iter().cloned().collect()); return Ok(cs); @@ -412,7 +381,7 @@ impl RawNode { return true; } let hs = raft.hard_state(); - if hs != HardState::new() && hs != self.prev_hs { + if hs != HardState::new_() && hs != self.prev_hs { return true; } false @@ -470,30 +439,30 @@ impl RawNode { /// ReportUnreachable reports the given node is not reachable for the last send. pub fn report_unreachable(&mut self, id: u64) { - let mut m = Message::new(); + let mut m = Message::new_(); m.set_msg_type(MessageType::MsgUnreachable); m.set_from(id); // we don't care if it is ok actually - self.raft.step(m).is_ok(); + let _ = self.raft.step(m); } /// ReportSnapshot reports the status of the sent snapshot. pub fn report_snapshot(&mut self, id: u64, status: SnapshotStatus) { let rej = status == SnapshotStatus::Failure; - let mut m = Message::new(); + let mut m = Message::new_(); m.set_msg_type(MessageType::MsgSnapStatus); m.set_from(id); m.set_reject(rej); // we don't care if it is ok actually - self.raft.step(m).is_ok(); + let _ = self.raft.step(m); } /// TransferLeader tries to transfer leadership to the given transferee. pub fn transfer_leader(&mut self, transferee: u64) { - let mut m = Message::new(); + let mut m = Message::new_(); m.set_msg_type(MessageType::MsgTransferLeader); m.set_from(transferee); - self.raft.step(m).is_ok(); + let _ = self.raft.step(m); } /// ReadIndex requests a read state. The read state will be set in ready. @@ -501,12 +470,12 @@ impl RawNode { /// index, any linearizable read requests issued before the read request can be /// processed safely. The read state will have the same rctx attached. pub fn read_index(&mut self, rctx: Vec) { - let mut m = Message::new(); + let mut m = Message::new_(); m.set_msg_type(MessageType::MsgReadIndex); - let mut e = Entry::new(); + let mut e = Entry::new_(); e.set_data(rctx); - m.set_entries(RepeatedField::from_vec(vec![e])); - self.raft.step(m).is_ok(); + m.set_entries(vec![e]); + let _ = self.raft.step(m); } /// Returns the store as an immutable reference. @@ -526,14 +495,22 @@ impl RawNode { pub fn skip_bcast_commit(&mut self, skip: bool) { self.raft.skip_bcast_commit(skip) } + + /// Set whether to batch append msg at runtime. + #[inline] + pub fn set_batch_append(&mut self, batch_append: bool) { + self.raft.set_batch_append(batch_append) + } } #[cfg(test)] mod test { - use super::is_local_msg; - use eraftpb::MessageType; use harness::setup_for_test; + use crate::eraftpb::MessageType; + + use super::is_local_msg; + #[test] fn test_is_local_msg() { setup_for_test(); diff --git a/src/read_only.rs b/src/read_only.rs index a51a3475a..d605f072e 100644 --- a/src/read_only.rs +++ b/src/read_only.rs @@ -27,7 +27,7 @@ use std::collections::VecDeque; -use eraftpb::Message; +use crate::eraftpb::Message; use hashbrown::{HashMap, HashSet}; diff --git a/src/status.rs b/src/status.rs index ce9c1bd1d..93e01ccd3 100644 --- a/src/status.rs +++ b/src/status.rs @@ -25,12 +25,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -use eraftpb::HardState; +use crate::eraftpb::HardState; use hashbrown::HashMap; -use progress::Progress; -use raft::{Raft, SoftState, StateRole}; -use storage::Storage; +use crate::progress::Progress; +use crate::raft::{Raft, SoftState, StateRole}; +use crate::storage::Storage; /// Represents the current status of the raft #[derive(Default)] diff --git a/src/storage.rs b/src/storage.rs index a54f7be98..88446f6bf 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -33,25 +33,29 @@ use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard}; -use eraftpb::{ConfChange, ConfState, Entry, HardState, Snapshot}; +use crate::eraftpb::*; -use errors::{Error, Result, StorageError}; -use util; +use crate::errors::{Error, Result, StorageError}; +use crate::util::limit_size; /// Holds both the hard state (commit index, vote leader, term) and the configuration state /// (Current node IDs) -#[derive(Debug, Clone, Getters, Setters)] +#[derive(Debug, Clone, Default, Getters, Setters)] pub struct RaftState { /// Contains the last meta information including commit index, the vote leader, and the vote term. pub hard_state: HardState, - /// Records the current node IDs like `[1, 2, 3]` in the cluster. Every Raft node must have a unique ID in the cluster; + + /// Records the current node IDs like `[1, 2, 3]` in the cluster. Every Raft node must have a + /// unique ID in the cluster; pub conf_state: ConfState, + /// If this peer is in the middle of a membership change (The period between /// `BeginMembershipChange` and `FinalizeMembershipChange`) this will hold the final desired /// state. #[get = "pub"] #[set] pending_conf_state: Option, + /// If `pending_conf_state` exists this will contain the index of the `BeginMembershipChange` /// entry. #[get = "pub"] @@ -59,31 +63,62 @@ pub struct RaftState { pending_conf_state_start_index: Option, } -/// Storage saves all the information about the current Raft implementation, including Raft Log, commit index, the leader to vote for, etc. -/// Pay attention to what is returned when there is no Log but it needs to get the `term` at index `first_index() - 1`. To solve this, you can use a dummy Log entry to keep the last truncated Log entry. See [`entries: vec![Entry::new()]`](src/storage.rs#L85) as a reference. +impl RaftState { + /// Create a new RaftState. + pub fn new(hard_state: HardState, conf_state: ConfState) -> RaftState { + RaftState { + hard_state, + conf_state, + pending_conf_state: None, + pending_conf_state_start_index: None, + } + } + /// Indicates the `RaftState` is initialized or not. + pub fn initialized(&self) -> bool { + self.conf_state != ConfState::default() + } +} + +/// Storage saves all the information about the current Raft implementation, including Raft Log, +/// commit index, the leader to vote for, etc. /// /// If any Storage method returns an error, the raft instance will -/// become inoperable and refuse to paticipate in elections; the +/// become inoperable and refuse to participate in elections; the /// application is responsible for cleanup and recovery in this case. pub trait Storage { - /// `initial_state` is called when Raft is initialized. This interface will return a `RaftState` which contains `HardState` and `ConfState`; + /// `initial_state` is called when Raft is initialized. This interface will return a `RaftState` + /// which contains `HardState` and `ConfState`. + /// + /// `RaftState` could be initialized or not. If it's initialized it means the `Storage` is + /// created with a configuration, and its last index and term should be greater than 0. fn initial_state(&self) -> Result; + /// Returns a slice of log entries in the range `[low, high)`. - /// max_size limits the total size of the log entries returned, but - /// entries returns at least one entry if any. - fn entries(&self, low: u64, high: u64, max_size: u64) -> Result>; + /// max_size limits the total size of the log entries returned if not `None`, however + /// the slice of entries returned will always have length at least 1 if entries are + /// found in the range. + /// + /// # Panics + /// + /// Panics if `high` is higher than `Storage::last_index(&self) + 1`. + fn entries(&self, low: u64, high: u64, max_size: impl Into>) -> Result>; + /// Returns the term of entry idx, which must be in the range /// [first_index()-1, last_index()]. The term of the entry before /// first_index is retained for matching purpose even though the /// rest of that entry may not be available. fn term(&self, idx: u64) -> Result; - /// Returns the index of the first log entry that is - /// possible available via entries (older entries have been incorporated - /// into the latest snapshot; if storage only contains the dummy entry the - /// first log entry is not available). + + /// Returns the index of the first log entry that is possible available via entries, which will + /// always equal to `truncated index` plus 1. + /// + /// New created (but not initialized) `Storage` can be considered as truncated at 0 so that 1 + /// will be returned in this case. fn first_index(&self) -> Result; - /// The index of the last entry in the log. + + /// The index of the last entry replicated in the `Storage`. fn last_index(&self) -> Result; + /// Returns the most recent snapshot. /// /// If snapshot is temporarily unavailable, it should return SnapshotTemporarilyUnavailable, @@ -95,20 +130,20 @@ pub trait Storage { /// The Memory Storage Core instance holds the actual state of the storage struct. To access this /// value, use the `rl` and `wl` functions on the main MemStorage implementation. pub struct MemStorageCore { - hard_state: HardState, - snapshot: Snapshot, - // TODO: maybe vec_deque + raft_state: RaftState, // entries[i] has raft log position i+snapshot.get_metadata().get_index() entries: Vec, + // Metadata of the last snapshot received. + snapshot_metadata: SnapshotMetadata, } impl Default for MemStorageCore { fn default() -> MemStorageCore { MemStorageCore { - // When starting from scratch populate the list with a dummy entry at term zero. - entries: vec![Entry::new()], - hard_state: HardState::new(), - snapshot: Snapshot::new(), + raft_state: Default::default(), + entries: vec![], + // Every time a snapshot is applied to the storage, the metadata will be stored here. + snapshot_metadata: Default::default(), } } } @@ -116,7 +151,37 @@ impl Default for MemStorageCore { impl MemStorageCore { /// Saves the current HardState. pub fn set_hardstate(&mut self, hs: HardState) { - self.hard_state = hs; + self.raft_state.hard_state = hs; + } + + /// Get the hard state. + pub fn hard_state(&self) -> &HardState { + &self.raft_state.hard_state + } + + /// Get the mut hard state. + pub fn mut_hard_state(&mut self) -> &mut HardState { + &mut self.raft_state.hard_state + } + + /// Commit to an index. + /// + /// # Panics + /// + /// Panics if there is no such entry in raft logs. + pub fn commit_to(&mut self, index: u64) -> Result<()> { + assert!( + self.has_entry_at(index), + "commit_to {} but the entry not exists", + index + ); + + let diff = (index - self.entries[0].get_index()) as usize; + self.raft_state.hard_state.set_commit(index); + self.raft_state + .hard_state + .set_term(self.entries[diff].get_term()); + Ok(()) } /// Saves the current conf state. @@ -125,142 +190,172 @@ impl MemStorageCore { cs: ConfState, pending_membership_change: Option<(ConfState, u64)>, ) { - self.snapshot.mut_metadata().set_conf_state(cs); + self.raft_state.conf_state = cs; if let Some((cs, idx)) = pending_membership_change { - self.snapshot - .mut_metadata() - .set_pending_membership_change(cs); - self.snapshot - .mut_metadata() - .set_pending_membership_change_index(idx); + self.raft_state.pending_conf_state = Some(cs); + self.raft_state.pending_conf_state_start_index = Some(idx); } } - fn inner_last_index(&self) -> u64 { - self.entries[0].get_index() + self.entries.len() as u64 - 1 + #[inline] + fn has_entry_at(&self, index: u64) -> bool { + !self.entries.is_empty() && index >= self.first_index() && index <= self.last_index() } - /// Overwrites the contents of this Storage object with those of the given snapshot. - pub fn apply_snapshot(&mut self, snapshot: Snapshot) -> Result<()> { - // handle check for old snapshot being applied - let index = self.snapshot.get_metadata().get_index(); - let snapshot_index = snapshot.get_metadata().get_index(); - if index >= snapshot_index { - return Err(Error::Store(StorageError::SnapshotOutOfDate)); + fn first_index(&self) -> u64 { + match self.entries.first() { + Some(e) => e.get_index(), + None => self.snapshot_metadata.get_index() + 1, } + } - let mut e = Entry::new(); - e.set_term(snapshot.get_metadata().get_term()); - e.set_index(snapshot.get_metadata().get_index()); - self.entries = vec![e]; - self.snapshot = snapshot; - Ok(()) + fn last_index(&self) -> u64 { + match self.entries.last() { + Some(e) => e.get_index(), + None => self.snapshot_metadata.get_index(), + } } - /// Makes a snapshot which can be retrieved with snapshot() and - /// can be used to reconstruct the state at that point. - /// If any configuration changes have been made since the last compaction, - /// the result of the last apply_conf_change must be passed in. - pub fn create_snapshot( - &mut self, - idx: u64, - cs: Option, - pending_membership_change: Option, - data: Vec, - ) -> Result<&Snapshot> { - if idx <= self.snapshot.get_metadata().get_index() { + /// Overwrites the contents of this Storage object with those of the given snapshot. + /// + /// # Panics + /// + /// Panics if the snapshot index is less than the storage's first index. + pub fn apply_snapshot(&mut self, mut snapshot: Snapshot) -> Result<()> { + let mut meta = snapshot.take_metadata(); + let term = meta.get_term(); + let index = meta.get_index(); + + if self.first_index() > index { return Err(Error::Store(StorageError::SnapshotOutOfDate)); } - let offset = self.entries[0].get_index(); - if idx > self.inner_last_index() { - panic!( - "snapshot {} is out of bound lastindex({})", - idx, - self.inner_last_index() - ) + self.snapshot_metadata = meta.clone(); + + self.raft_state.hard_state.set_term(term); + self.raft_state.hard_state.set_commit(index); + self.entries.clear(); + + // Update conf states. + self.raft_state.conf_state = meta.take_conf_state(); + if meta.get_pending_membership_change_index() > 0 { + let cs = meta.take_pending_membership_change(); + let i = meta.get_pending_membership_change_index(); + self.raft_state.pending_conf_state = Some(cs); + self.raft_state.pending_conf_state_start_index = Some(i); } - self.snapshot.mut_metadata().set_index(idx); - self.snapshot + Ok(()) + } + + fn snapshot(&self) -> Snapshot { + let mut snapshot = Snapshot::new_(); + + // Use the latest applied_idx to construct the snapshot. + let applied_idx = self.raft_state.hard_state.get_commit(); + let term = self.raft_state.hard_state.get_term(); + snapshot.mut_metadata().set_index(applied_idx); + snapshot.mut_metadata().set_term(term); + + snapshot .mut_metadata() - .set_term(self.entries[(idx - offset) as usize].get_term()); - if let Some(cs) = cs { - self.snapshot.mut_metadata().set_conf_state(cs) - } - if let Some(pending_change) = pending_membership_change { - let meta = self.snapshot.mut_metadata(); - meta.set_pending_membership_change(pending_change.get_configuration().clone()); - meta.set_pending_membership_change_index(pending_change.get_start_index()); + .set_conf_state(self.raft_state.conf_state.clone()); + if let Some(ref cs) = self.raft_state.pending_conf_state { + let i = self.raft_state.pending_conf_state_start_index.unwrap(); + let meta = snapshot.mut_metadata(); + meta.set_pending_membership_change(cs.clone()); + meta.set_pending_membership_change_index(i); } - self.snapshot.set_data(data); - Ok(&self.snapshot) + snapshot } /// Discards all log entries prior to compact_index. /// It is the application's responsibility to not attempt to compact an index /// greater than RaftLog.applied. + /// + /// # Panics + /// + /// Panics if `compact_index` is higher than `Storage::last_index(&self) + 1`. pub fn compact(&mut self, compact_index: u64) -> Result<()> { - let offset = self.entries[0].get_index(); - if compact_index <= offset { - return Err(Error::Store(StorageError::Compacted)); + if compact_index <= self.first_index() { + // Don't need to treat this case as an error. + return Ok(()); } - if compact_index > self.inner_last_index() { + + if compact_index > self.last_index() + 1 { panic!( - "compact {} is out of bound lastindex({})", + "compact not received raft logs: {}, last index: {}", compact_index, - self.inner_last_index() - ) + self.last_index() + ); } - let i = (compact_index - offset) as usize; - let entries = self.entries.drain(i..).collect(); - self.entries = entries; + if let Some(entry) = self.entries.first() { + let offset = compact_index - entry.get_index(); + self.entries.drain(..offset as usize); + } Ok(()) } /// Append the new entries to storage. - /// TODO: ensure the entries are continuous and - /// entries[0].get_index() > self.entries[0].get_index() + /// + /// # Panics + /// + /// Panics if `ents` contains compacted entries, or there's a gap between `ents` and the last + /// received entry in the storage. pub fn append(&mut self, ents: &[Entry]) -> Result<()> { if ents.is_empty() { return Ok(()); } - let first = self.entries[0].get_index() + 1; - let last = ents[0].get_index() + ents.len() as u64 - 1; - - if last < first { - return Ok(()); + if self.first_index() > ents[0].get_index() { + panic!( + "overwrite compacted raft logs, compacted: {}, append: {}", + self.first_index() - 1, + ents[0].get_index(), + ); } - // truncate compacted entries - let te: &[Entry] = if first > ents[0].get_index() { - let start_ent = (first - ents[0].get_index()) as usize; - &ents[start_ent..] - } else { - ents - }; - - let offset = te[0].get_index() - self.entries[0].get_index(); - if self.entries.len() as u64 > offset { - let mut new_entries: Vec = vec![]; - new_entries.extend_from_slice(&self.entries[..offset as usize]); - new_entries.extend_from_slice(te); - self.entries = new_entries; - } else if self.entries.len() as u64 == offset { - self.entries.extend_from_slice(te); - } else { + if self.last_index() + 1 < ents[0].get_index() { panic!( - "missing log entry [last: {}, append at: {}]", - self.inner_last_index(), - te[0].get_index() - ) + "raft logs should be continuous, last index: {}, new appended: {}", + self.last_index(), + ents[0].get_index(), + ); } + // Remove all entries overwritten by `ents`. + let diff = ents[0].get_index() - self.first_index(); + self.entries.drain(diff as usize..); + self.entries.extend_from_slice(&ents); + Ok(()) + } + + /// Commit to `idx` and set configuration to the given states. Only used for tests. + pub fn commit_to_and_set_conf_states( + &mut self, + idx: u64, + cs: Option, + pending_membership_change: Option, + ) -> Result<()> { + self.commit_to(idx)?; + if let Some(cs) = cs { + self.raft_state.conf_state = cs; + } + if let Some(mut pending_change) = pending_membership_change { + let conf_state = pending_change.take_configuration(); + self.raft_state.pending_conf_state = Some(conf_state); + let index = pending_change.get_start_index(); + self.raft_state.pending_conf_state_start_index = Some(index); + } Ok(()) } } -/// `MemStorage` is a thread-safe implementation of Storage trait. -/// It is mainly used for test purpose. +/// `MemStorage` is a thread-safe but incomplete implementation of `Storage`, mainly for tests. +/// +/// A real `Storage` should save both raft logs and applied data. However `MemStorage` only +/// contains raft logs. So you can call `MemStorage::append` to persist new received unstable raft +/// logs and then access them with `Storage` APIs. The only exception is `Storage::snapshot`. There +/// is no data in `Snapshot` returned by `MemStorage::snapshot` because applied data is not stored +/// in `MemStorage`. #[derive(Clone, Default)] pub struct MemStorage { core: Arc>, @@ -274,15 +369,51 @@ impl MemStorage { } } + /// Create a new `MemStorage` with a given `Config`. The given `Config` will be used to + /// initialize the storage. + pub fn new_with_conf_state(conf_state: T) -> MemStorage + where + ConfState: From, + { + let store = MemStorage::new(); + store.initialize_with_conf_state(conf_state); + store + } + + /// Initialize a `MemStorage` with a given `Config`. + pub fn initialize_with_conf_state(&self, conf_state: T) + where + ConfState: From, + { + assert!(!self.initial_state().unwrap().initialized()); + trace!("create storage with given config"); + let mut core = self.wl(); + // Set index to 1 to make `first_index` greater than 1 so that there will be a gap between + // uninitialized followers and the leader. And then followers can catch up the initial + // configuration by snapshots. + // + // And, set term to 1 because in term 0 there is no leader exactly. + // + // An another alternative is appending some conf-change entries here to construct the + // initial configuration so that followers can catch up it by raft logs. However the entry + // count depends on how many peers in the initial configuration, which makes some indices + // not predictable. So we choose snapshot instead of raft logs here. + core.snapshot_metadata.set_index(1); + core.snapshot_metadata.set_term(1); + core.raft_state.hard_state.set_commit(1); + core.raft_state.hard_state.set_term(1); + core.raft_state.conf_state = ConfState::from(conf_state); + } + /// Opens up a read lock on the storage and returns a guard handle. Use this /// with functions that don't require mutation. - pub fn rl(&self) -> RwLockReadGuard { + pub fn rl(&self) -> RwLockReadGuard<'_, MemStorageCore> { self.core.read().unwrap() } /// Opens up a write lock on the storage and returns guard handle. Use this /// with functions that take a mutable reference to self. - pub fn wl(&self) -> RwLockWriteGuard { + pub fn wl(&self) -> RwLockWriteGuard<'_, MemStorageCore> { self.core.write().unwrap() } } @@ -290,63 +421,46 @@ impl MemStorage { impl Storage for MemStorage { /// Implements the Storage trait. fn initial_state(&self) -> Result { - let core = self.rl(); - let mut state = RaftState { - hard_state: core.hard_state.clone(), - conf_state: core.snapshot.get_metadata().get_conf_state().clone(), - pending_conf_state: None, - pending_conf_state_start_index: None, - }; - if core.snapshot.get_metadata().has_pending_membership_change() { - state.pending_conf_state = core - .snapshot - .get_metadata() - .get_pending_membership_change() - .clone() - .into(); - state.pending_conf_state_start_index = core - .snapshot - .get_metadata() - .get_pending_membership_change_index() - .into(); - } - Ok(state) + Ok(self.rl().raft_state.clone()) } /// Implements the Storage trait. - fn entries(&self, low: u64, high: u64, max_size: u64) -> Result> { + fn entries(&self, low: u64, high: u64, max_size: impl Into>) -> Result> { + let max_size = max_size.into(); let core = self.rl(); - let offset = core.entries[0].get_index(); - if low <= offset { + if low < core.first_index() { return Err(Error::Store(StorageError::Compacted)); } - if high > core.inner_last_index() + 1 { + if high > core.last_index() + 1 { panic!( - "index out of bound (last: {}, high: {}", - core.inner_last_index() + 1, + "index out of bound (last: {}, high: {})", + core.last_index() + 1, high ); } - // only contains dummy entries. - if core.entries.len() == 1 { - return Err(Error::Store(StorageError::Unavailable)); - } + let offset = core.entries[0].get_index(); let lo = (low - offset) as usize; let hi = (high - offset) as usize; let mut ents = core.entries[lo..hi].to_vec(); - util::limit_size(&mut ents, max_size); + limit_size(&mut ents, max_size); Ok(ents) } /// Implements the Storage trait. fn term(&self, idx: u64) -> Result { let core = self.rl(); - let offset = core.entries[0].get_index(); - if idx < offset { + if idx == core.snapshot_metadata.get_index() { + return Ok(core.snapshot_metadata.get_term()); + } + + if idx < core.first_index() { return Err(Error::Store(StorageError::Compacted)); } + + let offset = core.entries[0].get_index(); + assert!(idx >= offset); if idx - offset >= core.entries.len() as u64 { return Err(Error::Store(StorageError::Unavailable)); } @@ -355,52 +469,49 @@ impl Storage for MemStorage { /// Implements the Storage trait. fn first_index(&self) -> Result { - let core = self.rl(); - Ok(core.entries[0].get_index() + 1) + Ok(self.rl().first_index()) } /// Implements the Storage trait. fn last_index(&self) -> Result { - let core = self.rl(); - Ok(core.inner_last_index()) + Ok(self.rl().last_index()) } /// Implements the Storage trait. fn snapshot(&self) -> Result { let core = self.rl(); - Ok(core.snapshot.clone()) + Ok(core.snapshot()) } } #[cfg(test)] mod test { - extern crate harness; - use eraftpb::{ConfState, Entry, Snapshot}; + use std::panic::{self, AssertUnwindSafe}; + use harness::setup_for_test; - use protobuf; + use prost::Message as ProstMsg; - use errors::{Error as RaftError, StorageError}; - use storage::{MemStorage, Storage}; + use crate::eraftpb::{ConfState, Entry, Snapshot}; + use crate::errors::{Error as RaftError, StorageError}; - // TODO extract these duplicated utility functions for tests + use super::{MemStorage, Storage}; fn new_entry(index: u64, term: u64) -> Entry { - let mut e = Entry::new(); + let mut e = Entry::new_(); e.set_term(term); e.set_index(index); e } - fn size_of(m: &T) -> u32 { - m.compute_size() + fn size_of(m: &T) -> u32 { + ProstMsg::encoded_len(m) as u32 } - fn new_snapshot(index: u64, term: u64, nodes: Vec, data: Vec) -> Snapshot { - let mut s = Snapshot::new(); + fn new_snapshot(index: u64, term: u64, nodes: Vec) -> Snapshot { + let mut s = Snapshot::new_(); s.mut_metadata().set_index(index); s.mut_metadata().set_term(term); s.mut_metadata().mut_conf_state().set_nodes(nodes); - s.set_data(data); s } @@ -444,12 +555,7 @@ mod test { max_u64, Err(RaftError::Store(StorageError::Compacted)), ), - ( - 3, - 4, - max_u64, - Err(RaftError::Store(StorageError::Compacted)), - ), + (3, 4, max_u64, Ok(vec![new_entry(3, 3)])), (4, 5, max_u64, Ok(vec![new_entry(4, 4)])), (4, 6, max_u64, Ok(vec![new_entry(4, 4), new_entry(5, 5)])), ( @@ -510,10 +616,7 @@ mod test { panic!("want {:?}, got {:?}", wresult, result); } - storage - .wl() - .append(&[new_entry(6, 5)]) - .expect("append failed"); + storage.wl().append(&[new_entry(6, 5)]).unwrap(); let wresult = Ok(6); let result = storage.last_index(); if result != wresult { @@ -528,47 +631,35 @@ mod test { let storage = MemStorage::new(); storage.wl().entries = ents; - let wresult = Ok(4); - let result = storage.first_index(); - if result != wresult { - panic!("want {:?}, got {:?}", wresult, result); - } - - storage.wl().compact(4).expect("compact failed"); - let wresult = Ok(5); - let result = storage.first_index(); - if result != wresult { - panic!("want {:?}, got {:?}", wresult, result); - } + assert_eq!(storage.first_index(), Ok(3)); + storage.wl().compact(4).unwrap(); + assert_eq!(storage.first_index(), Ok(4)); } #[test] fn test_storage_compact() { setup_for_test(); let ents = vec![new_entry(3, 3), new_entry(4, 4), new_entry(5, 5)]; - let mut tests = vec![ - (2, Err(RaftError::Store(StorageError::Compacted)), 3, 3, 3), - (3, Err(RaftError::Store(StorageError::Compacted)), 3, 3, 3), - (4, Ok(()), 4, 4, 2), - (5, Ok(()), 5, 5, 1), - ]; - for (i, (idx, wresult, windex, wterm, wlen)) in tests.drain(..).enumerate() { + let mut tests = vec![(2, 3, 3, 3), (3, 3, 3, 3), (4, 4, 4, 2), (5, 5, 5, 1)]; + for (i, (idx, windex, wterm, wlen)) in tests.drain(..).enumerate() { let storage = MemStorage::new(); storage.wl().entries = ents.clone(); - let result = storage.wl().compact(idx); - if result != wresult { - panic!("#{}: want {:?}, got {:?}", i, wresult, result); - } - let index = storage.wl().entries[0].get_index(); + storage.wl().compact(idx).unwrap(); + let index = storage.first_index().unwrap(); if index != windex { panic!("#{}: want {}, index {}", i, windex, index); } - let term = storage.wl().entries[0].get_term(); + let term = if let Ok(v) = storage.entries(index, index + 1, 1) { + v.first().map_or(0, |e| e.get_term()) + } else { + 0 + }; if term != wterm { panic!("#{}: want {}, term {}", i, wterm, term); } - let len = storage.wl().entries.len(); + let last = storage.last_index().unwrap(); + let len = storage.entries(index, last + 1, 100).unwrap().len(); if len != wlen { panic!("#{}: want {}, term {}", i, wlen, len); } @@ -580,22 +671,20 @@ mod test { setup_for_test(); let ents = vec![new_entry(3, 3), new_entry(4, 4), new_entry(5, 5)]; let nodes = vec![1, 2, 3]; - let mut cs = ConfState::new(); - cs.set_nodes(nodes.clone()); - let data = b"data".to_vec(); + let mut conf_state = ConfState::new_(); + conf_state.set_nodes(nodes.clone()); let mut tests = vec![ - (4, Ok(new_snapshot(4, 4, nodes.clone(), data.clone()))), - (5, Ok(new_snapshot(5, 5, nodes.clone(), data.clone()))), + (4, Ok(new_snapshot(4, 4, nodes.clone()))), + (5, Ok(new_snapshot(5, 5, nodes.clone()))), ]; for (i, (idx, wresult)) in tests.drain(..).enumerate() { let storage = MemStorage::new(); storage.wl().entries = ents.clone(); + storage.wl().raft_state.hard_state.set_commit(idx); + storage.wl().raft_state.hard_state.set_term(idx); + storage.wl().raft_state.conf_state = conf_state.clone(); - storage - .wl() - .create_snapshot(idx, Some(cs.clone()), None, data.clone()) - .expect("create snapshot failed"); let result = storage.snapshot(); if result != wresult { panic!("#{}: want {:?}, got {:?}", i, wresult, result); @@ -610,13 +699,11 @@ mod test { let mut tests = vec![ ( vec![new_entry(3, 3), new_entry(4, 4), new_entry(5, 5)], - Ok(()), - vec![new_entry(3, 3), new_entry(4, 4), new_entry(5, 5)], + Some(vec![new_entry(3, 3), new_entry(4, 4), new_entry(5, 5)]), ), ( vec![new_entry(3, 3), new_entry(4, 6), new_entry(5, 6)], - Ok(()), - vec![new_entry(3, 3), new_entry(4, 6), new_entry(5, 6)], + Some(vec![new_entry(3, 3), new_entry(4, 6), new_entry(5, 6)]), ), ( vec![ @@ -625,49 +712,46 @@ mod test { new_entry(5, 5), new_entry(6, 5), ], - Ok(()), - vec![ + Some(vec![ new_entry(3, 3), new_entry(4, 4), new_entry(5, 5), new_entry(6, 5), - ], + ]), ), - // truncate incoming entries, truncate the existing entries and append + // overwrite compacted raft logs is not allowed ( vec![new_entry(2, 3), new_entry(3, 3), new_entry(4, 5)], - Ok(()), - vec![new_entry(3, 3), new_entry(4, 5)], + None, ), // truncate the existing entries and append ( vec![new_entry(4, 5)], - Ok(()), - vec![new_entry(3, 3), new_entry(4, 5)], + Some(vec![new_entry(3, 3), new_entry(4, 5)]), ), // direct append ( vec![new_entry(6, 6)], - Ok(()), - vec![ + Some(vec![ new_entry(3, 3), new_entry(4, 4), new_entry(5, 5), new_entry(6, 6), - ], + ]), ), ]; - for (i, (entries, wresult, wentries)) in tests.drain(..).enumerate() { + for (i, (entries, wentries)) in tests.drain(..).enumerate() { let storage = MemStorage::new(); storage.wl().entries = ents.clone(); - - let result = storage.wl().append(&entries); - if result != wresult { - panic!("#{}: want {:?}, got {:?}", i, wresult, result); - } - let e = &storage.wl().entries; - if *e != wentries { - panic!("#{}: want {:?}, entries {:?}", i, wentries, e); + let res = panic::catch_unwind(AssertUnwindSafe(|| storage.wl().append(&entries))); + if let Some(wentries) = wentries { + assert!(res.is_ok()); + let e = &storage.wl().entries; + if *e != wentries { + panic!("#{}: want {:?}, entries {:?}", i, wentries, e); + } + } else { + assert!(res.is_err()); } } } @@ -676,29 +760,14 @@ mod test { fn test_storage_apply_snapshot() { setup_for_test(); let nodes = vec![1, 2, 3]; - let data = b"data".to_vec(); - - let snapshots = vec![ - new_snapshot(4, 4, nodes.clone(), data.clone()), - new_snapshot(3, 3, nodes.clone(), data.clone()), - ]; - let storage = MemStorage::new(); // Apply snapshot successfully - let i = 0; - let wresult = Ok(()); - let r = storage.wl().apply_snapshot(snapshots[i].clone()); - if r != wresult { - panic!("#{}: want {:?}, got {:?}", i, wresult, r); - } + let snap = new_snapshot(4, 4, nodes.clone()); + assert!(storage.wl().apply_snapshot(snap).is_ok()); // Apply snapshot fails due to StorageError::SnapshotOutOfDate - let i = 1; - let wresult = Err(RaftError::Store(StorageError::SnapshotOutOfDate)); - let r = storage.wl().apply_snapshot(snapshots[i].clone()); - if r != wresult { - panic!("#{}: want {:?}, got {:?}", i, wresult, r); - } + let snap = new_snapshot(3, 3, nodes.clone()); + assert!(storage.wl().apply_snapshot(snap).is_err()); } } diff --git a/src/util.rs b/src/util.rs index cfddf2ea6..611165629 100644 --- a/src/util.rs +++ b/src/util.rs @@ -16,8 +16,8 @@ use std::u64; -use eraftpb::{ConfChange, ConfChangeType, ConfState}; -use protobuf::Message; +use crate::eraftpb::{ConfChange, ConfChangeType, ConfState, Entry, Message}; +use prost::Message as ProstMsg; /// A number to represent that there is no limit. pub const NO_LIMIT: u64 = u64::MAX; @@ -31,7 +31,7 @@ pub const NO_LIMIT: u64 = u64::MAX; /// use raft::{util::limit_size, prelude::*}; /// /// let template = { -/// let mut entry = Entry::new(); +/// let mut entry = Entry::new_(); /// entry.set_data("*".repeat(100).into_bytes()); /// entry /// }; @@ -46,23 +46,31 @@ pub const NO_LIMIT: u64 = u64::MAX; /// ]; /// /// assert_eq!(entries.len(), 5); -/// limit_size(&mut entries, 220); +/// limit_size(&mut entries, Some(220)); /// assert_eq!(entries.len(), 2); +/// +/// // `entries` will always have at least 1 Message +/// limit_size(&mut entries, Some(0)); +/// assert_eq!(entries.len(), 1); /// ``` -pub fn limit_size(entries: &mut Vec, max: u64) { - if max == NO_LIMIT || entries.len() <= 1 { +pub fn limit_size(entries: &mut Vec, max: Option) { + if entries.len() <= 1 { return; } + let max = match max { + None | Some(NO_LIMIT) => return, + Some(max) => max, + }; let mut size = 0; let limit = entries .iter() .take_while(|&e| { if size == 0 { - size += u64::from(Message::compute_size(e)); + size += ProstMsg::encoded_len(e) as u64; true } else { - size += u64::from(Message::compute_size(e)); + size += ProstMsg::encoded_len(e) as u64; size <= max } }) @@ -80,12 +88,35 @@ impl ConfState { } } +impl From<(Iter1, Iter2)> for ConfState +where + Iter1: IntoIterator, + Iter2: IntoIterator, +{ + fn from((voters, learners): (Iter1, Iter2)) -> Self { + let mut conf_state = ConfState::default(); + conf_state.mut_nodes().extend(voters.into_iter()); + conf_state.mut_learners().extend(learners.into_iter()); + conf_state + } +} + impl From<(u64, ConfState)> for ConfChange { fn from((start_index, state): (u64, ConfState)) -> Self { - let mut change = ConfChange::new(); + let mut change = ConfChange::new_(); change.set_change_type(ConfChangeType::BeginMembershipChange); change.set_configuration(state); change.set_start_index(start_index); change } } + +/// Check whether the entry is continuous to the message. +/// i.e msg's next entry index should be equal to the first entries's index +pub fn is_continuous_ents(msg: &Message, ents: &[Entry]) -> bool { + if !msg.get_entries().is_empty() && !ents.is_empty() { + let expected_next_idx = msg.get_entries().last().unwrap().get_index() + 1; + return expected_next_idx == ents.first().unwrap().get_index(); + } + true +} diff --git a/tests/failpoint_cases/mod.rs b/tests/failpoint_cases/mod.rs index 4b5f4f505..223b66153 100644 --- a/tests/failpoint_cases/mod.rs +++ b/tests/failpoint_cases/mod.rs @@ -11,11 +11,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +use crate::test_util::*; use fail; use harness::setup_for_test; use raft::eraftpb::MessageType; use std::sync::*; -use test_util::*; lazy_static! { /// Failpoints are global structs, hence rules set in different cases @@ -43,7 +43,7 @@ fn test_reject_stale_term_message() { let _guard = setup(); let mut r = new_test_raft(1, vec![1, 2, 3], 10, 1, new_storage()); fail::cfg("before_step", "panic").unwrap(); - r.load_state(&hard_state(2, 0, 0)); + r.load_state(&hard_state(2, 1, 0)); let mut m = new_message(0, 0, MessageType::MsgAppend, 0); m.set_term(r.term - 1); diff --git a/tests/integration_cases/test_membership_changes.rs b/tests/integration_cases/test_membership_changes.rs index c96e633f1..9aef8e469 100644 --- a/tests/integration_cases/test_membership_changes.rs +++ b/tests/integration_cases/test_membership_changes.rs @@ -11,19 +11,22 @@ // See the License for the specific language governing permissions and // limitations under the License. // -// + +use std::ops::{Deref, DerefMut}; + use harness::{setup_for_test, Network}; use hashbrown::{HashMap, HashSet}; -use protobuf::{self, RepeatedField}; + +use prost::Message as ProstMsg; use raft::{ eraftpb::{ ConfChange, ConfChangeType, ConfState, Entry, EntryType, Message, MessageType, Snapshot, }, storage::MemStorage, - Config, Configuration, Raft, Result, INVALID_ID, NO_LIMIT, + Config, Configuration, Raft, Result, INVALID_ID, }; -use std::ops::{Deref, DerefMut}; -use test_util::new_message; + +use crate::test_util::new_message; // Test that the API itself works. // @@ -39,11 +42,9 @@ mod api { &Config { id: 1, tag: "1".into(), - peers: vec![1], - learners: vec![], ..Default::default() }, - MemStorage::new(), + MemStorage::new_with_conf_state((vec![1], vec![])), )?; let begin_conf_change = begin_conf_change(&[1, 2, 3], &[4], raft.raft_log.last_index() + 1); raft.begin_membership_change(&begin_conf_change)?; @@ -60,11 +61,9 @@ mod api { &Config { id: 1, tag: "1".into(), - peers: vec![1], - learners: vec![], ..Default::default() }, - MemStorage::new(), + MemStorage::new_with_conf_state((vec![1], vec![])), )?; let begin_conf_change = begin_conf_change(&[1, 2, 3], &[1, 2, 3], raft.raft_log.last_index() + 1); @@ -76,16 +75,13 @@ mod api { #[test] fn checks_for_voter_demotion() -> Result<()> { setup_for_test(); - let mut raft = Raft::new( - &Config { - id: 1, - tag: "1".into(), - peers: vec![1, 2, 3], - learners: vec![4], - ..Default::default() - }, - MemStorage::new(), - )?; + let config = Config { + id: 1, + tag: "1".into(), + ..Default::default() + }; + let store = MemStorage::new_with_conf_state((vec![1, 2, 3], vec![4])); + let mut raft = Raft::new(&config, store)?; let begin_conf_change = begin_conf_change(&[1, 2], &[3, 4], raft.raft_log.last_index() + 1); assert!(raft.begin_membership_change(&begin_conf_change).is_err()); Ok(()) @@ -99,11 +95,9 @@ mod api { &Config { id: 1, tag: "1".into(), - peers: vec![1, 2, 3], - learners: vec![4], ..Default::default() }, - MemStorage::new(), + MemStorage::new_with_conf_state((vec![1, 2, 3], vec![4])), )?; let finalize_conf_change = finalize_conf_change(); assert!(raft @@ -134,7 +128,7 @@ mod three_peers_add_voter { info!("Advancing leader, now entered the joint"); scenario.assert_can_apply_transition_entry_at_index( &[1], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1]); @@ -143,16 +137,16 @@ mod three_peers_add_voter { scenario.expect_read_and_dispatch_messages_from(&[1])?; scenario.assert_can_apply_transition_entry_at_index( &[2, 3], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1, 2, 3]); info!("Allowing new peers to catch up."); - scenario.expect_read_and_dispatch_messages_from(&[4, 1, 4])?; + scenario.expect_read_and_dispatch_messages_from(&[4, 1, 4, 1])?; scenario.assert_can_apply_transition_entry_at_index( &[4], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1, 2, 3, 4]); @@ -161,7 +155,7 @@ mod three_peers_add_voter { scenario.expect_read_and_dispatch_messages_from(&[3, 2, 1])?; scenario.assert_can_apply_transition_entry_at_index( &[1, 2, 3, 4], - 3, + 4, ConfChangeType::FinalizeMembershipChange, ); scenario.assert_not_in_membership_change(&[1, 2, 3, 4]); @@ -191,7 +185,7 @@ mod three_peers_add_learner { info!("Advancing leader, now entered the joint"); scenario.assert_can_apply_transition_entry_at_index( &[1], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1]); @@ -200,16 +194,16 @@ mod three_peers_add_learner { scenario.expect_read_and_dispatch_messages_from(&[1])?; scenario.assert_can_apply_transition_entry_at_index( &[2, 3], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1, 2, 3]); info!("Allowing new peers to catch up."); - scenario.expect_read_and_dispatch_messages_from(&[4, 1, 4])?; + scenario.expect_read_and_dispatch_messages_from(&[4, 1, 4, 1])?; scenario.assert_can_apply_transition_entry_at_index( &[4], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1, 2, 3, 4]); @@ -218,7 +212,7 @@ mod three_peers_add_learner { scenario.expect_read_and_dispatch_messages_from(&[3, 2, 1])?; scenario.assert_can_apply_transition_entry_at_index( &[1, 2, 3, 4], - 3, + 4, ConfChangeType::FinalizeMembershipChange, ); scenario.assert_not_in_membership_change(&[1, 2, 3, 4]); @@ -248,7 +242,7 @@ mod remove_learner { info!("Advancing leader, now entered the joint"); scenario.assert_can_apply_transition_entry_at_index( &[1], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1]); @@ -257,7 +251,7 @@ mod remove_learner { scenario.expect_read_and_dispatch_messages_from(&[1])?; scenario.assert_can_apply_transition_entry_at_index( &[2, 3, 4], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1, 2, 3]); @@ -266,7 +260,7 @@ mod remove_learner { scenario.expect_read_and_dispatch_messages_from(&[4, 3, 2, 1])?; scenario.assert_can_apply_transition_entry_at_index( &[1, 2, 3, 4], - 3, + 4, ConfChangeType::FinalizeMembershipChange, ); scenario.assert_not_in_membership_change(&[1, 2, 3, 4]); @@ -296,7 +290,7 @@ mod remove_voter { info!("Advancing leader, now entered the joint"); scenario.assert_can_apply_transition_entry_at_index( &[1], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1]); @@ -305,7 +299,7 @@ mod remove_voter { scenario.expect_read_and_dispatch_messages_from(&[1])?; scenario.assert_can_apply_transition_entry_at_index( &[2, 3], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1, 2, 3]); @@ -314,7 +308,7 @@ mod remove_voter { scenario.expect_read_and_dispatch_messages_from(&[2, 1])?; scenario.assert_can_apply_transition_entry_at_index( &[1, 2], - 3, + 4, ConfChangeType::FinalizeMembershipChange, ); scenario.assert_not_in_membership_change(&[1, 2]); @@ -344,7 +338,7 @@ mod remove_leader { info!("Advancing leader, now entered the joint"); scenario.assert_can_apply_transition_entry_at_index( &[1], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1]); @@ -353,7 +347,7 @@ mod remove_leader { scenario.expect_read_and_dispatch_messages_from(&[1])?; scenario.assert_can_apply_transition_entry_at_index( &[2, 3], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1, 2, 3]); @@ -362,7 +356,7 @@ mod remove_leader { scenario.expect_read_and_dispatch_messages_from(&[2, 3, 1])?; scenario.assert_can_apply_transition_entry_at_index( &[1, 2, 3], - 3, + 4, ConfChangeType::FinalizeMembershipChange, ); scenario.assert_not_in_membership_change(&[1, 2, 3]); @@ -420,7 +414,7 @@ mod remove_leader { info!("Advancing leader, now entered the joint"); scenario.assert_can_apply_transition_entry_at_index( &[1], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1]); @@ -429,7 +423,7 @@ mod remove_leader { scenario.expect_read_and_dispatch_messages_from(&[1])?; scenario.assert_can_apply_transition_entry_at_index( &[2, 3], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1, 2, 3]); @@ -441,7 +435,7 @@ mod remove_leader { scenario.assert_can_apply_transition_entry_at_index( &[2, 3], - 3, + 4, ConfChangeType::FinalizeMembershipChange, ); scenario.assert_not_in_membership_change(&[2, 3]); @@ -477,8 +471,8 @@ mod remove_leader { scenario.send(messages); let peer_leader = scenario.peer_leaders(); - assert!(peer_leader[&2] != 1); - assert!(peer_leader[&3] != 1); + assert_ne!(peer_leader[&2], 1); + assert_ne!(peer_leader[&3], 1); Ok(()) } } @@ -504,7 +498,7 @@ mod three_peers_replace_voter { info!("Advancing leader, now entered the joint"); scenario.assert_can_apply_transition_entry_at_index( &[1], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1]); @@ -513,16 +507,16 @@ mod three_peers_replace_voter { scenario.expect_read_and_dispatch_messages_from(&[1])?; scenario.assert_can_apply_transition_entry_at_index( &[2], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1, 2]); info!("Allowing new peers to catch up."); - scenario.expect_read_and_dispatch_messages_from(&[4, 1, 4])?; + scenario.expect_read_and_dispatch_messages_from(&[4, 1, 4, 1])?; scenario.assert_can_apply_transition_entry_at_index( &[4], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1, 2, 4]); @@ -531,7 +525,7 @@ mod three_peers_replace_voter { scenario.expect_read_and_dispatch_messages_from(&[2, 1, 4])?; scenario.assert_can_apply_transition_entry_at_index( &[1, 2, 4], - 3, + 4, ConfChangeType::FinalizeMembershipChange, ); scenario.assert_not_in_membership_change(&[1, 2, 4]); @@ -556,7 +550,7 @@ mod three_peers_replace_voter { info!("Advancing leader, now entered the joint"); scenario.assert_can_apply_transition_entry_at_index( &[1], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1]); @@ -565,13 +559,13 @@ mod three_peers_replace_voter { scenario.expect_read_and_dispatch_messages_from(&[1])?; scenario.assert_can_apply_transition_entry_at_index( &[2, 3], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1, 2, 3]); info!("Leader power cycles."); - assert_eq!(scenario.peers[&1].began_membership_change_at(), Some(2)); + assert_eq!(scenario.peers[&1].began_membership_change_at(), Some(3)); if let Some(idx) = scenario.peers[&1].began_membership_change_at() { let raft = scenario.peers.get_mut(&1).unwrap(); @@ -583,7 +577,7 @@ mod three_peers_replace_voter { } scenario.power_cycle(&[1], None); - assert_eq!(scenario.peers[&1].began_membership_change_at(), Some(2)); + assert_eq!(scenario.peers[&1].began_membership_change_at(), Some(3)); scenario.assert_in_membership_change(&[1]); { let peer = scenario.peers.get_mut(&1).unwrap(); @@ -598,17 +592,17 @@ mod three_peers_replace_voter { scenario.expect_read_and_dispatch_messages_from(&[4, 1, 4, 1, 4, 1])?; scenario.assert_can_apply_transition_entry_at_index( &[4], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1, 2, 3, 4]); info!("Cluster leaving the joint."); scenario.expect_read_and_dispatch_messages_from(&[4, 3, 2, 1, 4, 3, 2, 1])?; - assert_eq!(scenario.peers[&1].began_membership_change_at(), Some(2)); + assert_eq!(scenario.peers[&1].began_membership_change_at(), Some(3)); scenario.assert_can_apply_transition_entry_at_index( &[1, 2, 3, 4], - 4, + 5, ConfChangeType::FinalizeMembershipChange, ); scenario.assert_not_in_membership_change(&[1, 2, 4]); @@ -633,7 +627,7 @@ mod three_peers_replace_voter { info!("Advancing leader, now entered the joint"); scenario.assert_can_apply_transition_entry_at_index( &[1], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1]); @@ -642,7 +636,7 @@ mod three_peers_replace_voter { scenario.expect_read_and_dispatch_messages_from(&[1])?; scenario.assert_can_apply_transition_entry_at_index( &[2, 3], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1, 2, 3]); @@ -652,22 +646,21 @@ mod three_peers_replace_voter { let snapshot = { let peer = scenario.peers.get_mut(&1).unwrap(); warn!("BLAH {:?}", peer.pending_membership_change().clone()); - peer.raft_log.store.wl().create_snapshot( - 2, + peer.raft_log.store.wl().commit_to_and_set_conf_states( + 3, ConfState::from(peer.prs().configuration().clone()).into(), peer.pending_membership_change().clone(), - vec![], )?; let snapshot = peer.raft_log.snapshot()?; warn!("BLAH {:?}", snapshot.get_metadata()); - peer.raft_log.store.wl().compact(2)?; + peer.raft_log.store.wl().compact(3)?; snapshot }; // At this point, there is a sentinel at index 3, term 2. info!("Leader power cycles."); - assert_eq!(scenario.peers[&1].began_membership_change_at(), Some(2)); + assert_eq!(scenario.peers[&1].began_membership_change_at(), Some(3)); scenario.power_cycle(&[1], snapshot.clone()); { let peer = scenario.peers.get_mut(&1).unwrap(); @@ -675,7 +668,7 @@ mod three_peers_replace_voter { peer.become_leader(); } - assert_eq!(scenario.peers[&1].began_membership_change_at(), Some(2)); + assert_eq!(scenario.peers[&1].began_membership_change_at(), Some(3)); scenario.assert_in_membership_change(&[1]); info!("Allowing new peers to catch up."); @@ -684,7 +677,7 @@ mod three_peers_replace_voter { { assert_eq!( - 3, + 4, scenario.peers.get_mut(&4).unwrap().raft_log.unstable.offset ); let new_peer = scenario.peers.get_mut(&4).unwrap(); @@ -697,10 +690,10 @@ mod three_peers_replace_voter { info!("Cluster leaving the joint."); scenario.expect_read_and_dispatch_messages_from(&[4, 1, 4, 3, 2, 1, 3, 2, 1])?; - assert_eq!(scenario.peers[&1].began_membership_change_at(), Some(2)); + assert_eq!(scenario.peers[&1].began_membership_change_at(), Some(3)); scenario.assert_can_apply_transition_entry_at_index( &[1, 2, 3, 4], - 4, + 5, ConfChangeType::FinalizeMembershipChange, ); scenario.assert_not_in_membership_change(&[1, 2, 3, 4]); @@ -725,7 +718,7 @@ mod three_peers_replace_voter { info!("Advancing leader, now entered the joint"); scenario.assert_can_apply_transition_entry_at_index( &[1], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1]); @@ -736,16 +729,16 @@ mod three_peers_replace_voter { scenario.expect_read_and_dispatch_messages_from(&[1])?; scenario.assert_can_apply_transition_entry_at_index( &[2], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1, 2]); info!("Allowing new peers to catch up."); - scenario.expect_read_and_dispatch_messages_from(&[4, 1, 4])?; + scenario.expect_read_and_dispatch_messages_from(&[4, 1, 4, 1])?; scenario.assert_can_apply_transition_entry_at_index( &[4], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1, 2, 4]); @@ -754,7 +747,7 @@ mod three_peers_replace_voter { scenario.expect_read_and_dispatch_messages_from(&[2, 1, 4])?; scenario.assert_can_apply_transition_entry_at_index( &[1, 2, 4], - 3, + 4, ConfChangeType::FinalizeMembershipChange, ); scenario.assert_not_in_membership_change(&[1, 2, 4]); @@ -779,7 +772,7 @@ mod three_peers_replace_voter { info!("Advancing leader, now entered the joint"); scenario.assert_can_apply_transition_entry_at_index( &[1], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1]); @@ -790,7 +783,7 @@ mod three_peers_replace_voter { scenario.expect_read_and_dispatch_messages_from(&[1])?; scenario.assert_can_apply_transition_entry_at_index( &[2, 3], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1, 2, 3]); @@ -799,7 +792,7 @@ mod three_peers_replace_voter { scenario.expect_read_and_dispatch_messages_from(&[2, 1])?; scenario.assert_can_apply_transition_entry_at_index( &[1, 2, 3], - 3, + 4, ConfChangeType::FinalizeMembershipChange, ); scenario.assert_not_in_membership_change(&[1, 2, 3]); @@ -824,7 +817,7 @@ mod three_peers_replace_voter { info!("Advancing leader, now entered the joint"); scenario.assert_can_apply_transition_entry_at_index( &[1], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1]); @@ -836,7 +829,7 @@ mod three_peers_replace_voter { scenario.expect_read_and_dispatch_messages_from(&[1])?; scenario.assert_can_apply_transition_entry_at_index( &[2], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1, 2]); @@ -845,7 +838,7 @@ mod three_peers_replace_voter { scenario.expect_read_and_dispatch_messages_from(&[2, 1])?; scenario.assert_can_apply_transition_entry_at_index( &[1, 2], - 3, + 4, ConfChangeType::FinalizeMembershipChange, ); scenario.assert_not_in_membership_change(&[1, 2]); @@ -870,7 +863,7 @@ mod three_peers_replace_voter { info!("Advancing leader, now entered the joint"); scenario.assert_can_apply_transition_entry_at_index( &[1], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1]); @@ -880,10 +873,10 @@ mod three_peers_replace_voter { scenario.isolate(2); // Take 2 down. info!("Leader replicates the commit and finalize entry."); - scenario.expect_read_and_dispatch_messages_from(&[1, 4, 1])?; + scenario.expect_read_and_dispatch_messages_from(&[1, 4, 1, 4, 1, 4])?; scenario.assert_can_apply_transition_entry_at_index( &[4], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1, 4]); @@ -918,7 +911,7 @@ mod three_peers_replace_voter { scenario.expect_read_and_dispatch_messages_from(&[1, 2, 3, 4, 1, 2, 3, 1])?; scenario.assert_can_apply_transition_entry_at_index( &[2, 3], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1, 2, 3, 4]); @@ -930,7 +923,7 @@ mod three_peers_replace_voter { scenario.expect_read_and_dispatch_messages_from(&[1])?; scenario.assert_can_apply_transition_entry_at_index( &[1, 2, 3, 4], - 3, + 4, ConfChangeType::FinalizeMembershipChange, ); scenario.assert_not_in_membership_change(&[1, 2, 3, 4]); @@ -955,7 +948,7 @@ mod three_peers_replace_voter { info!("Advancing leader, now entered the joint"); scenario.assert_can_apply_transition_entry_at_index( &[1], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1]); @@ -997,10 +990,10 @@ mod three_peers_replace_voter { } info!("Giving the peer group time to recover."); - scenario.expect_read_and_dispatch_messages_from(&[1, 2, 3, 4, 1, 2, 4, 1])?; + scenario.expect_read_and_dispatch_messages_from(&[1, 2, 3, 4, 1, 2, 4, 1, 4, 1])?; scenario.assert_can_apply_transition_entry_at_index( &[2, 3, 4], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1, 2, 3, 4]); @@ -1012,7 +1005,7 @@ mod three_peers_replace_voter { scenario.expect_read_and_dispatch_messages_from(&[1])?; scenario.assert_can_apply_transition_entry_at_index( &[1, 2, 3, 4], - 3, + 4, ConfChangeType::FinalizeMembershipChange, ); scenario.assert_not_in_membership_change(&[1, 2, 3, 4]); @@ -1042,7 +1035,7 @@ mod three_peers_to_five_with_learner { info!("Advancing leader, now entered the joint"); scenario.assert_can_apply_transition_entry_at_index( &[1], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1]); @@ -1051,16 +1044,16 @@ mod three_peers_to_five_with_learner { scenario.expect_read_and_dispatch_messages_from(&[1])?; scenario.assert_can_apply_transition_entry_at_index( &[2, 3], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1, 2, 3]); info!("Allowing new peers to catch up."); - scenario.expect_read_and_dispatch_messages_from(&[4, 5, 6, 1, 4, 5, 6])?; + scenario.expect_read_and_dispatch_messages_from(&[4, 5, 6, 1, 4, 5, 6, 1, 4])?; scenario.assert_can_apply_transition_entry_at_index( &[4, 5, 6], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1, 2, 3, 4, 5, 6]); @@ -1069,7 +1062,7 @@ mod three_peers_to_five_with_learner { scenario.expect_read_and_dispatch_messages_from(&[3, 2, 1])?; scenario.assert_can_apply_transition_entry_at_index( &[1, 2, 3, 4, 5, 6], - 3, + 4, ConfChangeType::FinalizeMembershipChange, ); scenario.assert_not_in_membership_change(&[1, 2, 3, 4, 5, 6]); @@ -1095,7 +1088,7 @@ mod three_peers_to_five_with_learner { info!("Advancing leader, now entered the joint"); scenario.assert_can_apply_transition_entry_at_index( &[1], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1]); @@ -1104,17 +1097,17 @@ mod three_peers_to_five_with_learner { scenario.expect_read_and_dispatch_messages_from(&[1])?; scenario.assert_can_apply_transition_entry_at_index( &[2], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1, 2]); scenario.assert_not_in_membership_change(&[3]); info!("Allowing new peers to catch up."); - scenario.expect_read_and_dispatch_messages_from(&[4, 5, 6, 1])?; + scenario.expect_read_and_dispatch_messages_from(&[4, 5, 6, 1, 4, 5, 6, 1])?; scenario.assert_can_apply_transition_entry_at_index( &[4, 5, 6], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1, 2, 4, 5, 6]); @@ -1133,7 +1126,7 @@ mod three_peers_to_five_with_learner { scenario.expect_read_and_dispatch_messages_from(&[2, 1, 4, 5, 6, 1, 4, 5, 6, 1])?; scenario.assert_can_apply_transition_entry_at_index( &[1, 2, 4, 5], - 3, + 4, ConfChangeType::FinalizeMembershipChange, ); scenario.assert_not_in_membership_change(&[1, 2, 4, 5]); @@ -1163,17 +1156,17 @@ mod intermingled_config_changes { info!("Advancing leader, now entered the joint"); scenario.assert_can_apply_transition_entry_at_index( &[1], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1]); info!("Leader recieves an add node proposal, which it rejects since it is already in transition."); - scenario.propose_add_node_message(4).is_err(); + let _ = scenario.propose_add_node_message(4); assert_eq!( scenario.peers[&scenario.old_leader] .raft_log - .entries(4, 1) + .entries(5, 1) .unwrap()[0] .get_entry_type(), EntryType::EntryNormal @@ -1183,16 +1176,16 @@ mod intermingled_config_changes { scenario.expect_read_and_dispatch_messages_from(&[1])?; scenario.assert_can_apply_transition_entry_at_index( &[2, 3], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1, 2, 3]); info!("Allowing new peers to catch up."); - scenario.expect_read_and_dispatch_messages_from(&[4, 1, 4])?; + scenario.expect_read_and_dispatch_messages_from(&[4, 1, 4, 1, 4])?; scenario.assert_can_apply_transition_entry_at_index( &[4], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1, 2, 3, 4]); @@ -1201,7 +1194,7 @@ mod intermingled_config_changes { scenario.expect_read_and_dispatch_messages_from(&[3, 2, 1])?; scenario.assert_can_apply_transition_entry_at_index( &[1, 2, 3, 4], - 3, + 4, ConfChangeType::FinalizeMembershipChange, ); scenario.assert_not_in_membership_change(&[1, 2, 3, 4]); @@ -1230,7 +1223,7 @@ mod compaction { info!("Advancing leader, now entered the joint"); scenario.assert_can_apply_transition_entry_at_index( &[1], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1]); @@ -1239,16 +1232,16 @@ mod compaction { scenario.expect_read_and_dispatch_messages_from(&[1])?; scenario.assert_can_apply_transition_entry_at_index( &[2, 3], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1, 2, 3]); info!("Allowing new peers to catch up."); - scenario.expect_read_and_dispatch_messages_from(&[4, 1, 4])?; + scenario.expect_read_and_dispatch_messages_from(&[4, 1, 4, 1])?; scenario.assert_can_apply_transition_entry_at_index( &[4], - 2, + 3, ConfChangeType::BeginMembershipChange, ); scenario.assert_in_membership_change(&[1, 2, 3, 4]); @@ -1267,7 +1260,7 @@ mod compaction { scenario.expect_read_and_dispatch_messages_from(&[3, 2, 1])?; scenario.assert_can_apply_transition_entry_at_index( &[1, 2, 3, 4], - 3, + 4, ConfChangeType::FinalizeMembershipChange, ); scenario.assert_not_in_membership_change(&[1, 2, 3, 4]); @@ -1321,12 +1314,10 @@ impl Scenario { Raft::new( &Config { id, - peers: old_configuration.voters().iter().cloned().collect(), - learners: old_configuration.learners().iter().cloned().collect(), tag: format!("{}", id), ..Default::default() }, - MemStorage::new(), + MemStorage::new_with_conf_state(old_configuration.clone()), ) .unwrap() .into(), @@ -1351,19 +1342,16 @@ impl Scenario { /// This *only* creates the peers and adds them to the `Network`. It does not take other /// action. Newly created peers are only aware of the leader and themself. fn spawn_new_peers(&mut self) -> Result<()> { - let storage = MemStorage::new(); let new_peers = self.new_peers(); info!("Creating new peers. {:?}", new_peers); for &id in new_peers.voters() { let raft = Raft::new( &Config { id, - peers: vec![self.old_leader, id], - learners: vec![], tag: format!("{}", id), ..Default::default() }, - storage.clone(), + MemStorage::new_with_conf_state((vec![self.old_leader, id], vec![])), )?; self.peers.insert(id, raft.into()); } @@ -1371,12 +1359,10 @@ impl Scenario { let raft = Raft::new( &Config { id, - peers: vec![self.old_leader], - learners: vec![id], tag: format!("{}", id), ..Default::default() }, - storage.clone(), + MemStorage::new_with_conf_state((vec![self.old_leader], vec![id])), )?; self.peers.insert(id, raft.into()); } @@ -1477,8 +1463,7 @@ impl Scenario { let mut found = false; for entry in &entries { if entry.get_entry_type() == EntryType::EntryConfChange { - let conf_change = - protobuf::parse_from_bytes::(entry.get_data())?; + let conf_change = ConfChange::decode(entry.get_data())?; if conf_change.get_change_type() == entry_type { found = true; match entry_type { @@ -1588,10 +1573,10 @@ impl Scenario { for peer in peers { let entry = &self.peers[&peer] .raft_log - .slice(index, index + 1, NO_LIMIT) + .slice(index, index + 1, None) .unwrap()[0]; assert_eq!(entry.get_entry_type(), EntryType::EntryConfChange); - let conf_change = protobuf::parse_from_bytes::(entry.get_data()).unwrap(); + let conf_change = ConfChange::decode(entry.get_data()).unwrap(); assert_eq!(conf_change.get_change_type(), entry_type); } } @@ -1615,7 +1600,7 @@ fn conf_state<'a>( ) -> ConfState { let voters = voters.into_iter().cloned().collect::>(); let learners = learners.into_iter().cloned().collect::>(); - let mut conf_state = ConfState::new(); + let mut conf_state = ConfState::new_(); conf_state.set_nodes(voters); conf_state.set_learners(learners); conf_state @@ -1627,7 +1612,7 @@ fn begin_conf_change<'a>( index: u64, ) -> ConfChange { let conf_state = conf_state(voters, learners); - let mut conf_change = ConfChange::new(); + let mut conf_change = ConfChange::new_(); conf_change.set_change_type(ConfChangeType::BeginMembershipChange); conf_change.set_configuration(conf_state); conf_change.set_start_index(index); @@ -1635,7 +1620,7 @@ fn begin_conf_change<'a>( } fn finalize_conf_change<'a>() -> ConfChange { - let mut conf_change = ConfChange::new(); + let mut conf_change = ConfChange::new_(); conf_change.set_change_type(ConfChangeType::FinalizeMembershipChange); conf_change } @@ -1646,8 +1631,9 @@ fn begin_entry<'a>( index: u64, ) -> Entry { let conf_change = begin_conf_change(voters, learners, index); - let data = protobuf::Message::write_to_bytes(&conf_change).unwrap(); - let mut entry = Entry::new(); + let mut data = Vec::with_capacity(ProstMsg::encoded_len(&conf_change)); + conf_change.encode(&mut data).unwrap(); + let mut entry = Entry::new_(); entry.set_entry_type(EntryType::EntryConfChange); entry.set_data(data); entry.set_index(index); @@ -1661,30 +1647,31 @@ fn build_propose_change_message<'a>( index: u64, ) -> Message { let begin_entry = begin_entry(voters, learners, index); - let mut message = Message::new(); + let mut message = Message::new_(); message.set_to(recipient); message.set_msg_type(MessageType::MsgPropose); message.set_index(index); - message.set_entries(RepeatedField::from_vec(vec![begin_entry])); + message.set_entries(vec![begin_entry]); message } fn build_propose_add_node_message(recipient: u64, added_id: u64, index: u64) -> Message { let add_nodes_entry = { - let mut conf_change = ConfChange::new(); + let mut conf_change = ConfChange::new_(); conf_change.set_change_type(ConfChangeType::AddNode); conf_change.set_node_id(added_id); - let data = protobuf::Message::write_to_bytes(&conf_change).unwrap(); - let mut entry = Entry::new(); + let mut data = Vec::with_capacity(ProstMsg::encoded_len(&conf_change)); + conf_change.encode(&mut data).unwrap(); + let mut entry = Entry::new_(); entry.set_entry_type(EntryType::EntryConfChange); entry.set_data(data); entry.set_index(index); entry }; - let mut message = Message::new(); + let mut message = Message::new_(); message.set_to(recipient); message.set_msg_type(MessageType::MsgPropose); message.set_index(index); - message.set_entries(RepeatedField::from_vec(vec![add_nodes_entry])); + message.set_entries(vec![add_nodes_entry]); message } diff --git a/tests/integration_cases/test_raft.rs b/tests/integration_cases/test_raft.rs index 7e5e3f915..61cf2624f 100644 --- a/tests/integration_cases/test_raft.rs +++ b/tests/integration_cases/test_raft.rs @@ -31,13 +31,13 @@ use std::panic::{self, AssertUnwindSafe}; use harness::*; use hashbrown::HashSet; -use protobuf::{self, RepeatedField}; -use raft::eraftpb::{ - ConfChange, ConfChangeType, ConfState, Entry, EntryType, HardState, Message, MessageType, -}; +use prost::Message as ProstMsg; +use raft::eraftpb::*; use raft::storage::MemStorage; use raft::*; -use test_util::*; + +use crate::integration_cases::test_raft_paper::commit_noop_entry; +use crate::test_util::*; fn new_progress( state: ProgressState, @@ -57,42 +57,67 @@ fn read_messages(raft: &mut Raft) -> Vec { raft.msgs.drain(..).collect() } -fn ents_with_config(terms: &[u64], pre_vote: bool) -> Interface { - let store = MemStorage::new(); +fn ents_with_config(terms: &[u64], pre_vote: bool, id: u64, peers: Vec) -> Interface { + let store = MemStorage::new_with_conf_state((peers.clone(), vec![])); for (i, term) in terms.iter().enumerate() { - let mut e = Entry::new(); - e.set_index(i as u64 + 1); + let mut e = Entry::new_(); + // An additional `plus one` for initialized storage. + e.set_index(i as u64 + 1 + 1); e.set_term(*term); store.wl().append(&[e]).expect(""); } - let mut raft = new_test_raft_with_prevote(1, vec![], 5, 1, store, pre_vote); + let mut raft = new_test_raft_with_prevote(id, peers, 5, 1, store, pre_vote); raft.reset(terms[terms.len() - 1]); raft } +fn assert_raft_log( + prefix: &str, + raft_log: &RaftLog, + (committed, applied, last): (u64, u64, u64), +) { + assert_eq!( + raft_log.committed, committed, + "{}committed = {}, want = {}", + prefix, raft_log.committed, committed + ); + assert!( + raft_log.applied == applied, + "{}applied = {}, want = {}", + prefix, + raft_log.applied, + applied + ); + assert!( + raft_log.last_index() == last, + "{}last_index = {}, want = {}", + prefix, + raft_log.last_index(), + last + ); +} + // voted_with_config creates a raft state machine with vote and term set // to the given value but no log entries (indicating that it voted in // the given term but has not receive any logs). -fn voted_with_config(vote: u64, term: u64, pre_vote: bool) -> Interface { - let mut hard_state = HardState::new(); - hard_state.set_vote(vote); - hard_state.set_term(term); - let store = MemStorage::new(); - store.wl().set_hardstate(hard_state); - let mut raft = new_test_raft_with_prevote(1, vec![], 5, 1, store, pre_vote); +fn voted_with_config(vote: u64, term: u64, pre_vote: bool, id: u64, peers: Vec) -> Interface { + let store = MemStorage::new_with_conf_state((peers.clone(), vec![])); + store.wl().mut_hard_state().set_vote(vote); + store.wl().mut_hard_state().set_term(term); + let mut raft = new_test_raft_with_prevote(id, peers, 5, 1, store, pre_vote); raft.reset(term); raft } +// Persist committed index and fetch next entries. fn next_ents(r: &mut Raft, s: &MemStorage) -> Vec { - s.wl() - .append(r.raft_log.unstable_entries().unwrap_or(&[])) - .expect(""); + if let Some(entries) = r.raft_log.unstable_entries() { + s.wl().append(entries).expect(""); + } let (last_idx, last_term) = (r.raft_log.last_index(), r.raft_log.last_term()); r.raft_log.stable_to(last_idx, last_term); let ents = r.raft_log.next_entries(); - let committed = r.raft_log.committed; - r.commit_apply(committed); + r.commit_apply(r.raft_log.committed); ents.unwrap_or_else(Vec::new) } @@ -105,24 +130,6 @@ fn do_send_append(raft: &mut Raft, to: u64) { raft.set_prs(prs); } -fn new_raft_log(ents: &[Entry], offset: u64, committed: u64) -> RaftLog { - let store = MemStorage::new(); - store.wl().append(ents).expect(""); - RaftLog { - store, - unstable: Unstable { - offset, - ..Default::default() - }, - committed, - ..Default::default() - } -} - -fn new_raft_log_with_storage(s: MemStorage) -> RaftLog { - RaftLog::new(s, String::from("")) -} - #[test] fn test_progress_become_probe() { setup_for_test(); @@ -297,7 +304,8 @@ fn test_progress_leader() { let matched = raft.mut_prs().get_mut(1).unwrap().matched; let next_idx = raft.mut_prs().get_mut(1).unwrap().next_idx; - assert_eq!(matched, i + 1); + // An additional `+ 1` because the raft is initialized with index = 1. + assert_eq!(matched, i + 1 + 1); assert_eq!(next_idx, matched + 1); assert!(raft.step(prop_msg.clone()).is_ok()); @@ -330,13 +338,13 @@ fn test_progress_paused() { let mut raft = new_test_raft(1, vec![1, 2], 5, 1, new_storage()); raft.become_candidate(); raft.become_leader(); - let mut m = Message::new(); + let mut m = Message::new_(); m.set_from(1); m.set_to(1); m.set_msg_type(MessageType::MsgPropose); - let mut e = Entry::new(); + let mut e = Entry::new_(); e.set_data(b"some_data".to_vec()); - m.set_entries(RepeatedField::from_vec(vec![e])); + m.set_entries(vec![e]); raft.step(m.clone()).expect(""); raft.step(m.clone()).expect(""); raft.step(m.clone()).expect(""); @@ -357,31 +365,33 @@ fn test_leader_election_pre_vote() { } fn test_leader_election_with_config(pre_vote: bool) { + let mut config = Network::default_config(); + config.pre_vote = pre_vote; let mut tests = vec![ ( - Network::new_with_config(vec![None, None, None], pre_vote), + Network::new_with_config(vec![None, None, None], &config), StateRole::Leader, - 1, + 2, ), ( - Network::new_with_config(vec![None, None, NOP_STEPPER], pre_vote), + Network::new_with_config(vec![None, None, NOP_STEPPER], &config), StateRole::Leader, - 1, + 2, ), ( - Network::new_with_config(vec![None, NOP_STEPPER, NOP_STEPPER], pre_vote), + Network::new_with_config(vec![None, NOP_STEPPER, NOP_STEPPER], &config), StateRole::Candidate, - 1, + 2, ), ( - Network::new_with_config(vec![None, NOP_STEPPER, NOP_STEPPER, None], pre_vote), + Network::new_with_config(vec![None, NOP_STEPPER, NOP_STEPPER, None], &config), StateRole::Candidate, - 1, + 2, ), ( - Network::new_with_config(vec![None, NOP_STEPPER, NOP_STEPPER, None, None], pre_vote), + Network::new_with_config(vec![None, NOP_STEPPER, NOP_STEPPER, None, None], &config), StateRole::Leader, - 1, + 2, ), // three logs further along than 0, but in the same term so rejection // are returned instead of the votes being ignored. @@ -389,20 +399,20 @@ fn test_leader_election_with_config(pre_vote: bool) { Network::new_with_config( vec![ None, - Some(ents_with_config(&[1], pre_vote)), - Some(ents_with_config(&[1], pre_vote)), - Some(ents_with_config(&[1, 1], pre_vote)), + Some(ents_with_config(&[2], pre_vote, 2, vec![1, 2, 3, 4, 5])), + Some(ents_with_config(&[2], pre_vote, 3, vec![1, 2, 3, 4, 5])), + Some(ents_with_config(&[2, 2], pre_vote, 4, vec![1, 2, 3, 4, 5])), None, ], - pre_vote, + &config, ), StateRole::Follower, - 1, + 2, ), ]; for (i, &mut (ref mut network, state, term)) in tests.iter_mut().enumerate() { - let mut m = Message::new(); + let mut m = Message::new_(); m.set_from(1); m.set_to(1); m.set_msg_type(MessageType::MsgHup); @@ -412,7 +422,7 @@ fn test_leader_election_with_config(pre_vote: bool) { // In pre-vote mode, an election that fails to complete // leaves the node in pre-candidate state without advancing // the term. - (StateRole::PreCandidate, 0) + (StateRole::PreCandidate, 1) } else { (state, term) }; @@ -442,7 +452,9 @@ fn test_leader_cycle_pre_vote() { // pre-vote) work when not starting from a clean state (as they do in // test_leader_election) fn test_leader_cycle_with_config(pre_vote: bool) { - let mut network = Network::new_with_config(vec![None, None, None], pre_vote); + let mut config = Network::default_config(); + config.pre_vote = pre_vote; + let mut network = Network::new_with_config(vec![None, None, None], &config); for campaigner_id in 1..4 { network.send(vec![new_message( campaigner_id, @@ -499,15 +511,18 @@ fn test_leader_election_overwrite_newer_logs_with_config(pre_vote: bool) { // entry overwrites the loser's. (test_leader_sync_follower_log tests // the case where older log entries are overwritten, so this test // focuses on the case where the newer entries are lost). + let peers = vec![1, 2, 3, 4, 5]; + let mut config = Network::default_config(); + config.pre_vote = pre_vote; let mut network = Network::new_with_config( vec![ - Some(ents_with_config(&[1], pre_vote)), // Node 1: Won first election - Some(ents_with_config(&[1], pre_vote)), // Node 2: Get logs from node 1 - Some(ents_with_config(&[2], pre_vote)), // Node 3: Won second election - Some(voted_with_config(3, 2, pre_vote)), // Node 4: Voted but didn't get logs - Some(voted_with_config(3, 2, pre_vote)), // Node 5: Voted but didn't get logs + Some(ents_with_config(&[1], pre_vote, 1, peers.clone())), // Node 1: Won first election + Some(ents_with_config(&[1], pre_vote, 2, peers.clone())), // Node 2: Get logs from node 1 + Some(ents_with_config(&[2], pre_vote, 3, peers.clone())), // Node 3: Won second election + Some(voted_with_config(3, 2, pre_vote, 4, peers.clone())), // Node 4: Voted but didn't get logs + Some(voted_with_config(3, 2, pre_vote, 5, peers.clone())), // Node 5: Voted but didn't get logs ], - pre_vote, + &config, ); // Node 1 campaigns. The election fails because a quorum of nodes @@ -671,7 +686,7 @@ fn test_log_replicatioin() { ( Network::new(vec![None, None, None]), vec![new_message(1, 1, MessageType::MsgPropose, 1)], - 2, + 3, ), ( Network::new(vec![None, None, None]), @@ -680,7 +695,7 @@ fn test_log_replicatioin() { new_message(1, 2, MessageType::MsgHup, 0), new_message(1, 2, MessageType::MsgPropose, 1), ], - 4, + 5, ), ]; @@ -726,11 +741,11 @@ fn test_log_replicatioin() { fn test_single_node_commit() { setup_for_test(); let mut tt = Network::new(vec![None]); + assert_eq!(tt.peers[&1].raft_log.first_index(), 2); tt.send(vec![new_message(1, 1, MessageType::MsgHup, 0)]); tt.send(vec![new_message(1, 1, MessageType::MsgPropose, 1)]); tt.send(vec![new_message(1, 1, MessageType::MsgPropose, 1)]); - - assert_eq!(tt.peers[&1].raft_log.committed, 3); + assert_eq!(tt.peers[&1].raft_log.committed, 4); } // test_cannot_commit_without_new_term_entry tests the entries cannot be committed @@ -740,7 +755,9 @@ fn test_single_node_commit() { fn test_cannot_commit_without_new_term_entry() { setup_for_test(); let mut tt = Network::new(vec![None, None, None, None, None]); + assert_eq!(tt.peers[&1].raft_log.committed, 1); tt.send(vec![new_message(1, 1, MessageType::MsgHup, 0)]); + assert_eq!(tt.peers[&1].raft_log.committed, 2); // Empty entry of the term. // 0 cannot reach 2, 3, 4 tt.cut(1, 3); @@ -750,7 +767,7 @@ fn test_cannot_commit_without_new_term_entry() { tt.send(vec![new_message(1, 1, MessageType::MsgPropose, 1)]); tt.send(vec![new_message(1, 1, MessageType::MsgPropose, 1)]); - assert_eq!(tt.peers[&1].raft_log.committed, 1); + assert_eq!(tt.peers[&1].raft_log.committed, 2); // network recovery tt.recover(); @@ -761,7 +778,7 @@ fn test_cannot_commit_without_new_term_entry() { tt.send(vec![new_message(2, 2, MessageType::MsgHup, 0)]); // no log entries from previous term should be committed - assert_eq!(tt.peers[&2].raft_log.committed, 1); + assert_eq!(tt.peers[&2].raft_log.committed, 2); tt.recover(); // send heartbeat; reset wait @@ -769,7 +786,7 @@ fn test_cannot_commit_without_new_term_entry() { // append an entry at current term tt.send(vec![new_message(2, 2, MessageType::MsgPropose, 1)]); // expect the committed to be advanced - assert_eq!(tt.peers[&2].raft_log.committed, 5); + assert_eq!(tt.peers[&2].raft_log.committed, 6); } // test_commit_without_new_term_entry tests the entries could be committed @@ -788,7 +805,7 @@ fn test_commit_without_new_term_entry() { tt.send(vec![new_message(1, 1, MessageType::MsgPropose, 1)]); tt.send(vec![new_message(1, 1, MessageType::MsgPropose, 1)]); - assert_eq!(tt.peers[&1].raft_log.committed, 1); + assert_eq!(tt.peers[&1].raft_log.committed, 2); // network recovery tt.recover(); @@ -798,7 +815,7 @@ fn test_commit_without_new_term_entry() { // should be committed tt.send(vec![new_message(2, 2, MessageType::MsgHup, 0)]); - assert_eq!(tt.peers[&1].raft_log.committed, 4); + assert_eq!(tt.peers[&1].raft_log.committed, 5); } #[test] @@ -828,15 +845,20 @@ fn test_dueling_candidates() { // enough log. nt.send(vec![new_message(3, 3, MessageType::MsgHup, 0)]); - let wlog = new_raft_log(&[empty_entry(1, 1)], 2, 1); - let wlog2 = new_raft_log_with_storage(new_storage()); + let raft_logs = vec![ + // committed, applied, last index. + (2, 1, 2), + (2, 1, 2), + (1, 1, 1), + ]; + let tests = vec![ - (StateRole::Follower, 2, &wlog), - (StateRole::Follower, 2, &wlog), - (StateRole::Follower, 2, &wlog2), + (StateRole::Follower, 3), + (StateRole::Follower, 3), + (StateRole::Follower, 3), ]; - for (i, &(state, term, raft_log)) in tests.iter().enumerate() { + for (i, &(state, term)) in tests.iter().enumerate() { let id = i as u64 + 1; if nt.peers[&id].state != state { panic!( @@ -847,11 +869,9 @@ fn test_dueling_candidates() { if nt.peers[&id].term != term { panic!("#{}: term = {}, want {}", i, nt.peers[&id].term, term); } - let base = ltoa(raft_log); - let l = ltoa(&nt.peers[&(1 + i as u64)].raft_log); - if base != l { - panic!("#{}: raft_log:\n {}, want:\n {}", i, l, base); - } + + let prefix = format!("#{}: ", i); + assert_raft_log(&prefix, &nt.peers[&id].raft_log, raft_logs[i]); } } @@ -862,7 +882,9 @@ fn test_dueling_pre_candidates() { let b = new_test_raft_with_prevote(2, vec![1, 2, 3], 10, 1, new_storage(), true); let c = new_test_raft_with_prevote(3, vec![1, 2, 3], 10, 1, new_storage(), true); - let mut nt = Network::new_with_config(vec![Some(a), Some(b), Some(c)], true); + let mut config = Network::default_config(); + config.pre_vote = true; + let mut nt = Network::new_with_config(vec![Some(a), Some(b), Some(c)], &config); nt.cut(1, 3); nt.send(vec![new_message(1, 1, MessageType::MsgHup, 0)]); @@ -880,14 +902,15 @@ fn test_dueling_pre_candidates() { // With pre-vote, it does not disrupt the leader. nt.send(vec![new_message(3, 3, MessageType::MsgHup, 0)]); - let wlog = new_raft_log(&[empty_entry(0, 0), empty_entry(1, 1)], 2, 1); - let wlog2 = new_raft_log_with_storage(new_storage()); + // 3 items in every tuple is committed index, applied index and last index. + let expects = vec![(2, 1, 2), (2, 1, 2), (1, 1, 1)]; + let tests = vec![ - (1, StateRole::Leader, 1, &wlog), - (2, StateRole::Follower, 1, &wlog), - (3, StateRole::Follower, 1, &wlog2), + (1, StateRole::Leader, 2), + (2, StateRole::Follower, 2), + (3, StateRole::Follower, 2), ]; - for (i, &(id, state, term, raft_log)) in tests.iter().enumerate() { + for (i, &(id, state, term)) in tests.iter().enumerate() { if nt.peers[&id].state != state { panic!( "#{}: state = {:?}, want {:?}", @@ -897,11 +920,8 @@ fn test_dueling_pre_candidates() { if nt.peers[&id].term != term { panic!("#{}: term = {}, want {}", i, nt.peers[&id].term, term); } - let base = ltoa(raft_log); - let l = ltoa(&nt.peers[&(1 + i as u64)].raft_log); - if base != l { - panic!("#{}: raft_log:\n {}, want:\n {}", i, l, base); - } + let prefix = format!("#{}: ", i); + assert_raft_log(&prefix, &nt.peers[&id].raft_log, expects[i]); } } @@ -922,21 +942,18 @@ fn test_candidate_concede() { // send a proposal to 3 to flush out a MsgAppend to 1 let data = "force follower"; let mut m = new_message(3, 3, MessageType::MsgPropose, 0); - m.set_entries(RepeatedField::from_vec(vec![new_entry(0, 0, Some(data))])); + m.set_entries(vec![new_entry(0, 0, Some(data))]); tt.send(vec![m]); // send heartbeat; flush out commit tt.send(vec![new_message(3, 3, MessageType::MsgBeat, 0)]); assert_eq!(tt.peers[&1].state, StateRole::Follower); - assert_eq!(tt.peers[&1].term, 1); - - let ents = vec![empty_entry(1, 1), new_entry(1, 2, Some(data))]; - let want_log = ltoa(&new_raft_log(&ents, 3, 2)); - for (id, p) in &tt.peers { - let l = ltoa(&p.raft_log); - if l != want_log { - panic!("#{}: raft_log: {}, want: {}", id, l, want_log); - } + assert_eq!(tt.peers[&1].term, 2); + + for (_, p) in &tt.peers { + assert_eq!(p.raft_log.committed, 3); // All raft logs are committed. + assert_eq!(p.raft_log.applied, 1); // Raft logs are based on a snapshot with index 1. + assert_eq!(p.raft_log.last_index(), 3); } } @@ -952,7 +969,9 @@ fn test_single_node_candidate() { #[test] fn test_sinle_node_pre_candidate() { setup_for_test(); - let mut tt = Network::new_with_config(vec![None], true); + let mut config = Network::default_config(); + config.pre_vote = true; + let mut tt = Network::new_with_config(vec![None], &config); tt.send(vec![new_message(1, 1, MessageType::MsgHup, 0)]); assert_eq!(tt.peers[&1].state, StateRole::Leader); @@ -969,24 +988,16 @@ fn test_old_messages() { // pretend we're an old leader trying to make progress; this entry is expected to be ignored. let mut m = new_message(2, 1, MessageType::MsgAppend, 0); m.set_term(2); - m.set_entries(RepeatedField::from_vec(vec![empty_entry(2, 3)])); + m.set_entries(vec![empty_entry(2, 3)]); tt.send(vec![m]); // commit a new entry tt.send(vec![new_message(1, 1, MessageType::MsgPropose, 1)]); - let ents = vec![ - empty_entry(1, 1), - empty_entry(2, 2), - empty_entry(3, 3), - new_entry(3, 4, SOME_DATA), - ]; - let ilog = new_raft_log(&ents, 5, 4); - let base = ltoa(&ilog); - for (id, p) in &tt.peers { - let l = ltoa(&p.raft_log); - if l != base { - panic!("#{}: raft_log: {}, want: {}", id, l, base); - } + for (_, p) in &tt.peers { + let raft = p.raft.as_ref().unwrap(); + assert_eq!(raft.raft_log.committed, 5); + assert_eq!(raft.raft_log.applied, 1); + assert_eq!(raft.raft_log.last_index(), 5); } } @@ -1019,22 +1030,17 @@ fn test_proposal() { send(&mut nw, new_message(1, 1, MessageType::MsgHup, 0)); send(&mut nw, new_message(1, 1, MessageType::MsgPropose, 1)); - let want_log = if success { - new_raft_log(&[empty_entry(1, 1), new_entry(1, 2, SOME_DATA)], 3, 2) - } else { - new_raft_log_with_storage(new_storage()) - }; - let base = ltoa(&want_log); - for (id, p) in &nw.peers { - if p.raft.is_some() { - let l = ltoa(&p.raft_log); - if l != base { - panic!("#{}: raft_log: {}, want {}", id, l, base); - } + // committed index, applied index and last index. + let want_log = if success { (3, 1, 3) } else { (1, 1, 1) }; + + for (_, p) in &nw.peers { + if let Some(ref raft) = p.raft { + let prefix = format!("#{}: ", j); + assert_raft_log(&prefix, &raft.raft_log, want_log); } } - if nw.peers[&1].term != 1 { - panic!("#{}: term = {}, want: {}", j, nw.peers[&1].term, 1); + if nw.peers[&1].term != 2 { + panic!("#{}: term = {}, want: {}", j, nw.peers[&1].term, 2); } } } @@ -1053,19 +1059,17 @@ fn test_proposal_by_proxy() { // propose via follower tt.send(vec![new_message(2, 2, MessageType::MsgPropose, 1)]); - let want_log = new_raft_log(&[empty_entry(1, 1), new_entry(1, 2, SOME_DATA)], 3, 2); - let base = ltoa(&want_log); - for (id, p) in &tt.peers { + for (_, p) in &tt.peers { if p.raft.is_none() { continue; } - let l = ltoa(&p.raft_log); - if l != base { - panic!("#{}: raft_log: {}, want: {}", id, l, base); + if let Some(ref raft) = p.raft { + let prefix = format!("#{}: ", j); + assert_raft_log(&prefix, &raft.raft_log, (3, 1, 3)); } } - if tt.peers[&1].term != 1 { - panic!("#{}: term = {}, want {}", j, tt.peers[&1].term, 1); + if tt.peers[&1].term != 2 { + panic!("#{}: term = {}, want {}", j, tt.peers[&1].term, 2); } } } @@ -1075,85 +1079,37 @@ fn test_commit() { setup_for_test(); let mut tests = vec![ // single - (vec![1u64], vec![empty_entry(1, 1)], 1u64, 1u64), - (vec![1], vec![empty_entry(1, 1)], 2, 0), - (vec![2], vec![empty_entry(1, 1), empty_entry(2, 2)], 2, 2), - (vec![1], vec![empty_entry(2, 1)], 2, 1), + (vec![2], vec![empty_entry(2, 2)], 2, 2), // odd - ( - vec![2, 1, 1], - vec![empty_entry(1, 1), empty_entry(2, 2)], - 1, - 1, - ), - ( - vec![2, 1, 1], - vec![empty_entry(1, 1), empty_entry(1, 2)], - 2, - 0, - ), - ( - vec![2, 1, 2], - vec![empty_entry(1, 1), empty_entry(2, 2)], - 2, - 2, - ), - ( - vec![2, 1, 2], - vec![empty_entry(1, 1), empty_entry(1, 2)], - 2, - 0, - ), + (vec![2, 1, 1], vec![empty_entry(2, 2)], 1, 1), + (vec![2, 1, 1], vec![empty_entry(1, 2)], 2, 1), + (vec![2, 1, 2], vec![empty_entry(2, 2)], 2, 2), + (vec![2, 1, 2], vec![empty_entry(1, 2)], 2, 1), // even - ( - vec![2, 1, 1, 1], - vec![empty_entry(1, 1), empty_entry(2, 2)], - 1, - 1, - ), - ( - vec![2, 1, 1, 1], - vec![empty_entry(1, 1), empty_entry(1, 2)], - 2, - 0, - ), - ( - vec![2, 1, 1, 2], - vec![empty_entry(1, 1), empty_entry(2, 2)], - 1, - 1, - ), - ( - vec![2, 1, 1, 2], - vec![empty_entry(1, 1), empty_entry(1, 2)], - 2, - 0, - ), - ( - vec![2, 1, 2, 2], - vec![empty_entry(1, 1), empty_entry(2, 2)], - 2, - 2, - ), - ( - vec![2, 1, 2, 2], - vec![empty_entry(1, 1), empty_entry(1, 2)], - 2, - 0, - ), + (vec![2, 1, 1, 1], vec![empty_entry(2, 2)], 1, 1), + (vec![2, 1, 1, 1], vec![empty_entry(1, 2)], 2, 1), + (vec![2, 1, 1, 2], vec![empty_entry(2, 2)], 1, 1), + (vec![2, 1, 1, 2], vec![empty_entry(1, 2)], 2, 1), + (vec![2, 1, 2, 2], vec![empty_entry(2, 2)], 2, 2), + (vec![2, 1, 2, 2], vec![empty_entry(1, 2)], 2, 1), ]; for (i, (matches, logs, sm_term, w)) in tests.drain(..).enumerate() { - let store = MemStorage::new(); - store.wl().append(&logs).expect(""); - let mut hs = HardState::new(); + let store = MemStorage::new_with_conf_state((vec![1], vec![])); + store.wl().append(&logs).unwrap(); + let cfg = new_test_config(1, 10, 1); + let mut sm = new_test_raft_with_config(&cfg, store); + let mut hs = HardState::new_(); hs.set_term(sm_term); - store.wl().set_hardstate(hs); + sm.raft_log.store.wl().set_hardstate(hs); + sm.term = sm_term; - let mut sm = new_test_raft(1, vec![1], 5, 1, store); for (j, &v) in matches.iter().enumerate() { let id = j as u64 + 1; - if sm.prs().get(id).is_none() { + if let Some(pr) = sm.mut_prs().get_mut(id) { + pr.matched = v; + pr.next_idx = v + 1; + } else { sm.set_progress(id, v, v + 1, false); } } @@ -1206,46 +1162,46 @@ fn test_pass_election_timeout() { fn test_handle_msg_append() { setup_for_test(); let nm = |term, log_term, index, commit, ents: Option>| { - let mut m = Message::new(); + let mut m = Message::new_(); m.set_msg_type(MessageType::MsgAppend); m.set_term(term); m.set_log_term(log_term); m.set_index(index); m.set_commit(commit); if let Some(ets) = ents { - m.set_entries(RepeatedField::from_vec( - ets.iter().map(|&(i, t)| empty_entry(t, i)).collect(), - )); + m.set_entries(ets.iter().map(|&(i, t)| empty_entry(t, i)).collect()); } m }; let mut tests = vec![ // Ensure 1 - (nm(2, 3, 2, 3, None), 2, 0, true), // previous log mismatch - (nm(2, 3, 3, 3, None), 2, 0, true), // previous log non-exist + (nm(2, 3, 3, 3, None), 3, 1, true), // previous log mismatch + (nm(2, 3, 4, 3, None), 3, 1, true), // previous log non-exist // Ensure 2 - (nm(2, 1, 1, 1, None), 2, 1, false), - (nm(2, 0, 0, 1, Some(vec![(1, 2)])), 1, 1, false), - (nm(2, 2, 2, 3, Some(vec![(3, 2), (4, 2)])), 4, 3, false), - (nm(2, 2, 2, 4, Some(vec![(3, 2)])), 3, 3, false), - (nm(2, 1, 1, 4, Some(vec![(2, 2)])), 2, 2, false), + (nm(2, 1, 2, 2, None), 3, 2, false), + (nm(2, 1, 1, 2, Some(vec![(2, 2)])), 2, 2, false), + (nm(2, 2, 3, 4, Some(vec![(4, 2), (5, 2)])), 5, 4, false), + (nm(2, 2, 3, 5, Some(vec![(4, 2)])), 4, 4, false), + (nm(2, 1, 2, 5, Some(vec![(3, 2)])), 3, 3, false), // Ensure 3 - (nm(1, 1, 1, 3, None), 2, 1, false), // match entry 1, commit up to last new entry 1 - (nm(1, 1, 1, 3, Some(vec![(2, 2)])), 2, 2, false), // match entry 1, commit up to last new + (nm(1, 1, 2, 4, None), 3, 2, false), // match entry 1, commit up to last new entry 1 + (nm(1, 1, 2, 4, Some(vec![(3, 2)])), 3, 3, false), // match entry 1, commit up to last new // entry 2 - (nm(2, 2, 2, 3, None), 2, 2, false), // match entry 2, commit up to last new entry 2 - (nm(2, 2, 2, 4, None), 2, 2, false), // commit up to log.last() + (nm(2, 2, 3, 4, None), 3, 3, false), // match entry 2, commit up to last new entry 2 + (nm(2, 2, 3, 5, None), 3, 3, false), // commit up to log.last() ]; for (j, (m, w_index, w_commit, w_reject)) in tests.drain(..).enumerate() { - let store = new_storage(); - store - .wl() - .append(&[empty_entry(1, 1), empty_entry(2, 2)]) - .expect(""); - let mut sm = new_test_raft(1, vec![1], 10, 1, store); - sm.become_follower(2, INVALID_ID); + let mut sm = new_test_raft_with_logs( + 1, + vec![1], + 10, + 1, + MemStorage::new(), + &[empty_entry(1, 2), empty_entry(2, 3)], + ); + sm.become_follower(2, INVALID_ID); sm.handle_append_entries(&m); if sm.raft_log.last_index() != w_index { panic!( @@ -1287,12 +1243,13 @@ fn test_handle_heartbeat() { (nw(2, 1, 2, commit - 1), commit), // do not decrease commit ]; for (i, (m, w_commit)) in tests.drain(..).enumerate() { - let store = new_storage(); + let store = MemStorage::new_with_conf_state((vec![1, 2], vec![])); store .wl() - .append(&[empty_entry(1, 1), empty_entry(2, 2), empty_entry(3, 3)]) - .expect(""); - let mut sm = new_test_raft(1, vec![1, 2], 5, 1, store); + .append(&[empty_entry(1, 2), empty_entry(2, 3), empty_entry(3, 4)]) + .unwrap(); + let cfg = new_test_config(1, 10, 1); + let mut sm = new_test_raft_with_config(&cfg, store); sm.become_follower(2, 2); sm.raft_log.commit_to(commit); sm.handle_heartbeat(m); @@ -1324,7 +1281,7 @@ fn test_handle_heartbeat_resp() { store .wl() .append(&[empty_entry(1, 1), empty_entry(2, 2), empty_entry(3, 3)]) - .expect(""); + .unwrap(); let mut sm = new_test_raft(1, vec![1, 2], 5, 1, store); sm.become_candidate(); sm.become_leader(); @@ -1417,15 +1374,15 @@ fn test_msg_append_response_wait_reset() { // Node 2 acks the first entry, making it committed. let mut m = new_message(2, 0, MessageType::MsgAppendResponse, 0); - m.set_index(1); + m.set_index(2); sm.step(m).expect(""); - assert_eq!(sm.raft_log.committed, 1); + assert_eq!(sm.raft_log.committed, 2); // Also consume the MsgApp messages that update Commit on the followers. sm.read_messages(); // A new command is now proposed on node 1. m = new_message(1, 0, MessageType::MsgPropose, 0); - m.set_entries(RepeatedField::from_vec(vec![empty_entry(0, 0)])); + m.set_entries(vec![empty_entry(0, 0)]); sm.step(m).expect(""); // The command is broadcast to all nodes not in the wait state. @@ -1435,7 +1392,7 @@ fn test_msg_append_response_wait_reset() { assert_eq!(msgs[0].get_msg_type(), MessageType::MsgAppend); assert_eq!(msgs[0].get_to(), 2); assert_eq!(msgs[0].get_entries().len(), 1); - assert_eq!(msgs[0].get_entries()[0].get_index(), 2); + assert_eq!(msgs[0].get_entries()[0].get_index(), 3); // Now Node 3 acks the first entry. This releases the wait and entry 2 is sent. m = new_message(3, 0, MessageType::MsgAppendResponse, 0); @@ -1445,7 +1402,7 @@ fn test_msg_append_response_wait_reset() { assert_eq!(msgs.len(), 1); assert_eq!(msgs[0].get_msg_type(), MessageType::MsgAppend); assert_eq!(msgs[0].get_to(), 3); - assert_eq!(msgs[0].get_entries().len(), 1); + assert_eq!(msgs[0].get_entries().len(), 2); assert_eq!(msgs[0].get_entries()[0].get_index(), 2); } @@ -1457,39 +1414,32 @@ fn test_recv_msg_request_vote() { fn test_recv_msg_request_vote_for_type(msg_type: MessageType) { let mut tests = vec![ - (StateRole::Follower, 0, 0, INVALID_ID, true), - (StateRole::Follower, 0, 1, INVALID_ID, true), - (StateRole::Follower, 0, 2, INVALID_ID, true), - (StateRole::Follower, 0, 3, INVALID_ID, false), - (StateRole::Follower, 1, 0, INVALID_ID, true), (StateRole::Follower, 1, 1, INVALID_ID, true), (StateRole::Follower, 1, 2, INVALID_ID, true), (StateRole::Follower, 1, 3, INVALID_ID, false), - (StateRole::Follower, 2, 0, INVALID_ID, true), (StateRole::Follower, 2, 1, INVALID_ID, true), - (StateRole::Follower, 2, 2, INVALID_ID, false), + (StateRole::Follower, 2, 2, INVALID_ID, true), (StateRole::Follower, 2, 3, INVALID_ID, false), - (StateRole::Follower, 3, 0, INVALID_ID, true), (StateRole::Follower, 3, 1, INVALID_ID, true), (StateRole::Follower, 3, 2, INVALID_ID, false), (StateRole::Follower, 3, 3, INVALID_ID, false), - (StateRole::Follower, 3, 2, 2, false), - (StateRole::Follower, 3, 2, 1, true), - (StateRole::Leader, 3, 3, 1, true), - (StateRole::PreCandidate, 3, 3, 1, true), - (StateRole::Candidate, 3, 3, 1, true), + (StateRole::Follower, 4, 1, INVALID_ID, true), + (StateRole::Follower, 4, 2, INVALID_ID, false), + (StateRole::Follower, 4, 3, INVALID_ID, false), + (StateRole::Follower, 4, 2, 2, false), + (StateRole::Follower, 4, 2, 1, true), + (StateRole::Leader, 4, 3, 1, true), + (StateRole::PreCandidate, 4, 3, 1, true), + (StateRole::Candidate, 4, 3, 1, true), ]; for (j, (state, index, log_term, vote_for, w_reject)) in tests.drain(..).enumerate() { - let raft_log = new_raft_log( - &[empty_entry(0, 0), empty_entry(2, 1), empty_entry(2, 2)], - 3, - 0, - ); - let mut sm = new_test_raft(1, vec![1], 10, 1, new_storage()); + let store = MemStorage::new_with_conf_state((vec![1], vec![])); + let ents = &[empty_entry(2, 2), empty_entry(2, 3)]; + store.wl().append(ents).unwrap(); + let mut sm = new_test_raft(1, vec![1], 10, 1, store); sm.state = state; sm.vote = vote_for; - sm.raft_log = raft_log; let mut m = new_message(2, 0, msg_type, 0); m.set_index(index); @@ -1545,67 +1495,67 @@ fn test_state_transition() { StateRole::Follower, StateRole::PreCandidate, true, - 0, + 1, INVALID_ID, ), ( StateRole::Follower, StateRole::Candidate, true, - 1, + 2, INVALID_ID, ), - (StateRole::Follower, StateRole::Leader, false, 0, INVALID_ID), + (StateRole::Follower, StateRole::Leader, false, 1, INVALID_ID), ( StateRole::PreCandidate, StateRole::Follower, true, - 0, + 1, INVALID_ID, ), ( StateRole::PreCandidate, StateRole::PreCandidate, true, - 0, + 1, INVALID_ID, ), ( StateRole::PreCandidate, StateRole::Candidate, true, - 1, + 2, INVALID_ID, ), - (StateRole::PreCandidate, StateRole::Leader, true, 0, 1), + (StateRole::PreCandidate, StateRole::Leader, true, 1, 1), ( StateRole::Candidate, StateRole::Follower, true, - 0, + 1, INVALID_ID, ), ( StateRole::Candidate, StateRole::PreCandidate, true, - 0, + 1, INVALID_ID, ), ( StateRole::Candidate, StateRole::Candidate, true, - 1, + 2, INVALID_ID, ), - (StateRole::Candidate, StateRole::Leader, true, 0, 1), + (StateRole::Candidate, StateRole::Leader, true, 1, 1), (StateRole::Leader, StateRole::Follower, true, 1, INVALID_ID), ( StateRole::Leader, StateRole::PreCandidate, false, - 0, + 1, INVALID_ID, ), ( @@ -1615,7 +1565,7 @@ fn test_state_transition() { 1, INVALID_ID, ), - (StateRole::Leader, StateRole::Leader, true, 0, 1), + (StateRole::Leader, StateRole::Leader, true, 1, 1), ]; for (i, (from, to, wallow, wterm, wlead)) in tests.drain(..).enumerate() { let sm: &mut Raft = &mut new_test_raft(1, vec![1], 10, 1, new_storage()); @@ -1647,16 +1597,17 @@ fn test_state_transition() { fn test_all_server_stepdown() { setup_for_test(); let mut tests = vec![ - (StateRole::Follower, StateRole::Follower, 3, 0), - (StateRole::PreCandidate, StateRole::Follower, 3, 0), - (StateRole::Candidate, StateRole::Follower, 3, 0), - (StateRole::Leader, StateRole::Follower, 3, 1), + // state, want_state, term, last_index, entry count. + (StateRole::Follower, StateRole::Follower, 3, 1, 0), + (StateRole::PreCandidate, StateRole::Follower, 3, 1, 0), + (StateRole::Candidate, StateRole::Follower, 3, 1, 0), + (StateRole::Leader, StateRole::Follower, 3, 2, 1), ]; let tmsg_types = vec![MessageType::MsgRequestVote, MessageType::MsgAppend]; let tterm = 3u64; - for (i, (state, wstate, wterm, windex)) in tests.drain(..).enumerate() { + for (i, (state, wstate, wterm, windex, entries)) in tests.drain(..).enumerate() { let mut sm = new_test_raft(1, vec![1, 2, 3], 10, 1, new_storage()); match state { StateRole::Follower => sm.become_follower(1, INVALID_ID), @@ -1690,8 +1641,8 @@ fn test_all_server_stepdown() { ); } let entry_count = sm.raft_log.all_entries().len() as u64; - if entry_count != windex { - panic!("{}.{} ents count = {}, want {}", i, j, entry_count, windex); + if entry_count != entries { + panic!("{}.{} ents count = {}, want {}", i, j, entry_count, entries); } let wlead = if msg_type == MessageType::MsgRequestVote { INVALID_ID @@ -2173,26 +2124,44 @@ fn test_read_only_option_safe() { assert_eq!(nt.peers[&1].state, StateRole::Leader); let mut tests = vec![ - (1, 10, 11, "ctx1"), - (2, 10, 21, "ctx2"), - (3, 10, 31, "ctx3"), - (1, 10, 41, "ctx4"), - (2, 10, 51, "ctx5"), - (3, 10, 61, "ctx6"), + (1, 10, 12, vec!["ctx1", "ctx11"], false), + (2, 10, 22, vec!["ctx2", "ctx22"], false), + (3, 10, 32, vec!["ctx3", "ctx33"], false), + (1, 10, 42, vec!["ctx4", "ctx44"], true), + (2, 10, 52, vec!["ctx5", "ctx55"], true), + (3, 10, 62, vec!["ctx6", "ctx66"], true), ]; - for (i, (id, proposals, wri, wctx)) in tests.drain(..).enumerate() { + for (i, (id, proposals, wri, wctx, pending)) in tests.drain(..).enumerate() { for _ in 0..proposals { nt.send(vec![new_message(1, 1, MessageType::MsgPropose, 1)]); } - let e = new_entry(0, 0, Some(wctx)); - nt.send(vec![new_message_with_entries( + let msg1 = new_message_with_entries( id, id, MessageType::MsgReadIndex, - vec![e], - )]); + vec![new_entry(0, 0, Some(wctx[0]))], + ); + let msg2 = new_message_with_entries( + id, + id, + MessageType::MsgReadIndex, + vec![new_entry(0, 0, Some(wctx[1]))], + ); + + // `pending` indicates that a `ReadIndex` request will not get through quorum checking immediately + // so that it remains in the `read_index_queue` + if pending { + // drop MsgHeartbeatResponse here to prevent leader handling pending ReadIndex request per round + nt.ignore(MessageType::MsgHeartbeatResponse); + nt.send(vec![msg1.clone(), msg1.clone(), msg2.clone()]); + nt.recover(); + // send a ReadIndex request with the last ctx to notify leader to handle pending read requests + nt.send(vec![msg2.clone()]); + } else { + nt.send(vec![msg1.clone(), msg1.clone(), msg2.clone()]); + } let read_states: Vec = nt .peers @@ -2204,16 +2173,18 @@ fn test_read_only_option_safe() { if read_states.is_empty() { panic!("#{}: read_states is empty, want non-empty", i); } - let rs = &read_states[0]; - if rs.index != wri { - panic!("#{}: read_index = {}, want {}", i, rs.index, wri) - } - let vec_wctx = wctx.as_bytes().to_vec(); - if rs.request_ctx != vec_wctx { - panic!( - "#{}: request_ctx = {:?}, want {:?}", - i, rs.request_ctx, vec_wctx - ) + assert_eq!(read_states.len(), wctx.len()); + for (rs, wctx) in read_states.iter().zip(wctx) { + if rs.index != wri { + panic!("#{}: read_index = {}, want {}", i, rs.index, wri) + } + let ctx_bytes = wctx.as_bytes().to_vec(); + if rs.request_ctx != ctx_bytes { + panic!( + "#{}: request_ctx = {:?}, want {:?}", + i, rs.request_ctx, ctx_bytes + ) + } } } } @@ -2319,12 +2290,12 @@ fn test_read_only_option_lease() { assert_eq!(nt.peers[&1].state, StateRole::Leader); let mut tests = vec![ - (1, 10, 11, "ctx1"), - (2, 10, 21, "ctx2"), - (3, 10, 31, "ctx3"), - (1, 10, 41, "ctx4"), - (2, 10, 51, "ctx5"), - (3, 10, 61, "ctx6"), + (1, 10, 12, "ctx1"), + (2, 10, 22, "ctx2"), + (3, 10, 32, "ctx3"), + (1, 10, 42, "ctx4"), + (2, 10, 52, "ctx5"), + (3, 10, 62, "ctx6"), ]; for (i, (id, proposals, wri, wctx)) in tests.drain(..).enumerate() { @@ -2389,7 +2360,7 @@ fn test_read_only_option_lease_without_check_quorum() { let read_states = &nt.peers[&2].read_states; assert!(!read_states.is_empty()); let rs = &read_states[0]; - assert_eq!(rs.index, 1); + assert_eq!(rs.index, 2); let vec_ctx = ctx.as_bytes().to_vec(); assert_eq!(rs.request_ctx, vec_ctx); } @@ -2400,22 +2371,22 @@ fn test_read_only_option_lease_without_check_quorum() { fn test_read_only_for_new_leader() { setup_for_test(); let heartbeat_ticks = 1; - let node_configs = vec![(1, 1, 1, 0), (2, 2, 2, 2), (3, 2, 2, 2)]; + let node_configs = vec![(1, 2, 2, 1), (2, 3, 3, 3), (3, 3, 3, 3)]; let mut peers = vec![]; for (id, committed, applied, compact_index) in node_configs { - let mut cfg = new_test_config(id, vec![1, 2, 3], 10, heartbeat_ticks); + let mut cfg = new_test_config(id, 10, heartbeat_ticks); cfg.applied = applied; - let storage = new_storage(); - let entries = vec![empty_entry(1, 1), empty_entry(1, 2)]; + let storage = MemStorage::new_with_conf_state((vec![1, 2, 3], vec![])); + let entries = vec![empty_entry(1, 2), empty_entry(1, 3)]; storage.wl().append(&entries).unwrap(); - let mut hs = HardState::new(); + let mut hs = HardState::new_(); hs.set_term(1); hs.set_commit(committed); storage.wl().set_hardstate(hs); if compact_index != 0 { storage.wl().compact(compact_index).unwrap(); } - let i = Interface::new(Raft::new(&cfg, storage).unwrap()); + let i = new_test_raft_with_config(&cfg, storage); peers.push(Some(i)); } let mut nt = Network::new(peers); @@ -2428,7 +2399,7 @@ fn test_read_only_for_new_leader() { assert_eq!(nt.peers[&1].state, StateRole::Leader); // Ensure peer 1 drops read only request. - let windex = 4; + let windex = 5; let wctx = "ctx"; nt.send(vec![new_message_with_entries( 1, @@ -2445,7 +2416,7 @@ fn test_read_only_for_new_leader() { nt.peers.get_mut(&1).unwrap().tick(); } nt.send(vec![new_message(1, 1, MessageType::MsgPropose, 1)]); - assert_eq!(nt.peers[&1].raft_log.committed, 4); + assert_eq!(nt.peers[&1].raft_log.committed, 5); assert_eq!( nt.peers[&1] .raft_log @@ -2477,24 +2448,30 @@ fn test_read_only_for_new_leader() { #[test] fn test_leader_append_response() { setup_for_test(); - // initial progress: match = 0; next = 3 + // Initial progress: match = 0, next = 4 on followers. let mut tests = vec![ - (3, true, 0, 3, 0, 0, 0), // stale resp; no replies - (2, true, 0, 2, 1, 1, 0), // denied resp; leader does not commit; descrease next and send - // probing msg - (2, false, 2, 4, 2, 2, 2), // accept resp; leader commits; broadcast with commit index - (0, false, 0, 3, 0, 0, 0), + // Stale resp; no replies. + (4, true, 0, 4, 0, 0, 0), + // Denied resp; decrease next and send probing message. + (3, true, 0, 3, 1, 2, 1), + // Accepted resp; leader commits to 3; broadcast with committed index. + (3, false, 3, 5, 2, 3, 3), + (0, false, 0, 4, 0, 0, 0), ]; for (i, (index, reject, wmatch, wnext, wmsg_num, windex, wcommitted)) in tests.drain(..).enumerate() { - // sm term is 1 after it becomes the leader. - // thus the last log term must be 1 to be committed. - let mut sm = new_test_raft(1, vec![1, 2, 3], 10, 1, new_storage()); - sm.raft_log = new_raft_log(&[empty_entry(0, 1), empty_entry(1, 2)], 3, 0); + // Initial raft logs: last index = 3, commited = 1. + let store = MemStorage::new_with_conf_state((vec![1, 2, 3], vec![])); + let ents = &[empty_entry(1, 2), empty_entry(2, 3)]; + store.wl().append(ents).unwrap(); + let mut sm = new_test_raft(1, vec![1, 2, 3], 10, 1, store); + + // sm term is 2 after it becomes the leader. sm.become_candidate(); sm.become_leader(); + sm.read_messages(); let mut m = new_message(2, 0, MessageType::MsgAppendResponse, 0); m.set_index(index); @@ -2546,13 +2523,14 @@ fn test_leader_append_response() { #[test] fn test_bcast_beat() { setup_for_test(); - let offset = 1000u64; + let store = new_storage(); + let mut sm = new_test_raft(1, vec![1, 2, 3], 10, 1, store); + // make a state machine with log.offset = 1000 + let offset = 1000u64; let s = new_snapshot(offset, 1, vec![1, 2, 3]); - let store = new_storage(); - store.wl().apply_snapshot(s).expect(""); - let mut sm = new_test_raft(1, vec![], 10, 1, store); - sm.term = 1; + sm.restore(s.clone()); + sm.raft_log.store.wl().apply_snapshot(s).unwrap(); sm.become_candidate(); sm.become_leader(); @@ -2575,6 +2553,7 @@ fn test_bcast_beat() { .expect(""); let mut msgs = sm.read_messages(); assert_eq!(msgs.len(), 2); + let mut want_commit_map = HashMap::new(); want_commit_map.insert( 2, @@ -2630,9 +2609,11 @@ fn test_recv_msg_beat() { ]; for (i, (state, w_msg)) in tests.drain(..).enumerate() { - let mut sm = new_test_raft(1, vec![1, 2, 3], 10, 1, new_storage()); - sm.raft_log = new_raft_log(&[empty_entry(0, 1), empty_entry(1, 2)], 0, 0); - sm.term = 1; + let store = MemStorage::new_with_conf_state((vec![1, 2, 3], vec![])); + let ents = &[empty_entry(1, 2), empty_entry(1, 3)]; + store.wl().append(ents).unwrap(); + + let mut sm = new_test_raft(1, vec![1, 2, 3], 10, 1, store); sm.state = state; sm.step(new_message(1, 1, MessageType::MsgBeat, 0)) .expect(""); @@ -2657,14 +2638,14 @@ fn test_recv_msg_beat() { #[test] fn test_leader_increase_next() { setup_for_test(); - let previous_ents = vec![empty_entry(1, 1), empty_entry(1, 2), empty_entry(1, 3)]; + let previous_ents = vec![empty_entry(1, 2), empty_entry(1, 3), empty_entry(1, 4)]; let mut tests = vec![ // state replicate; optimistically increase next - // previous entries + noop entry + propose + 1 + // previous entries + noop entry + propose + 2 ( ProgressState::Replicate, 2, - previous_ents.len() as u64 + 1 + 1 + 1, + previous_ents.len() as u64 + 1 + 1 + 2, ), // state probe, not optimistically increase next (ProgressState::Probe, 2, 2), @@ -2697,6 +2678,8 @@ fn test_send_append_for_progress_probe() { r.become_candidate(); r.become_leader(); r.read_messages(); + // Because on index 1 there is a snapshot. + r.mut_prs().get_mut(2).unwrap().maybe_update(2 - 1); r.mut_prs().get_mut(2).unwrap().become_probe(); // each round is a heartbeat @@ -2709,7 +2692,7 @@ fn test_send_append_for_progress_probe() { do_send_append(&mut r, 2); let msg = r.read_messages(); assert_eq!(msg.len(), 1); - assert_eq!(msg[0].get_index(), 0); + assert_eq!(msg[0].get_index(), 1); } assert!(r.prs().get(2).unwrap().paused); @@ -2737,7 +2720,7 @@ fn test_send_append_for_progress_probe() { .expect(""); let msg = r.read_messages(); assert_eq!(msg.len(), 1); - assert_eq!(msg[0].get_index(), 0); + assert_eq!(msg[0].get_index(), 1); assert!(r.prs().get(2).unwrap().paused); } @@ -2748,6 +2731,9 @@ fn test_send_append_for_progress_replicate() { r.become_candidate(); r.become_leader(); r.read_messages(); + // Suppose node 2 has received the snapshot, and becomes active. + r.mut_prs().get_mut(2).unwrap().next_idx = 2; + r.mut_prs().get_mut(2).unwrap().matched = 1; r.mut_prs().get_mut(2).unwrap().become_replicate(); for _ in 0..10 { @@ -2778,7 +2764,7 @@ fn test_recv_msg_unreachable() { setup_for_test(); let previous_ents = vec![empty_entry(1, 1), empty_entry(1, 2), empty_entry(1, 3)]; let s = new_storage(); - s.wl().append(&previous_ents).expect(""); + s.wl().append(&previous_ents).unwrap(); let mut r = new_test_raft(1, vec![1, 2], 10, 1, s); r.become_candidate(); r.become_leader(); @@ -2826,7 +2812,7 @@ fn test_restore_ignore_snapshot() { setup_for_test(); let previous_ents = vec![empty_entry(1, 1), empty_entry(1, 2), empty_entry(1, 3)]; let commit = 1u64; - let mut sm = new_test_raft(1, vec![1, 2], 10, 1, new_storage()); + let mut sm = new_test_raft(1, vec![], 10, 1, new_storage()); sm.raft_log.append(&previous_ents); sm.raft_log.commit_to(commit); @@ -2915,16 +2901,14 @@ fn test_slow_node_restore() { nt.send(vec![new_message(1, 1, MessageType::MsgPropose, 1)]); } next_ents(&mut nt.peers.get_mut(&1).unwrap(), &nt.storage[&1]); - let mut cs = ConfState::new(); - cs.set_nodes(nt.peers[&1].prs().voter_ids().iter().cloned().collect()); nt.storage[&1] .wl() - .create_snapshot(nt.peers[&1].raft_log.applied, Some(cs), None, vec![]) - .expect(""); + .commit_to(nt.peers[&1].raft_log.applied) + .unwrap(); nt.storage[&1] .wl() .compact(nt.peers[&1].raft_log.applied) - .expect(""); + .unwrap(); nt.recover(); // send heartbeats so that the leader can learn everyone is active. @@ -2958,7 +2942,7 @@ fn test_step_config() { r.become_leader(); let index = r.raft_log.last_index(); let mut m = new_message(1, 1, MessageType::MsgPropose, 0); - let mut e = Entry::new(); + let mut e = Entry::new_(); e.set_entry_type(EntryType::EntryConfChange); m.mut_entries().push(e); r.step(m).expect(""); @@ -2975,8 +2959,9 @@ fn test_step_ignore_config() { let mut r = new_test_raft(1, vec![1, 2], 10, 1, new_storage()); r.become_candidate(); r.become_leader(); + assert!(!r.has_pending_conf()); let mut m = new_message(1, 1, MessageType::MsgPropose, 0); - let mut e = Entry::new(); + let mut e = Entry::new_(); e.set_entry_type(EntryType::EntryConfChange); m.mut_entries().push(e); assert!(!r.has_pending_conf()); @@ -2985,10 +2970,10 @@ fn test_step_ignore_config() { let index = r.raft_log.last_index(); let pending_conf_index = r.pending_conf_index; r.step(m.clone()).expect(""); - let mut we = empty_entry(1, 3); + let mut we = empty_entry(2, 4); we.set_entry_type(EntryType::EntryNormal); let wents = vec![we]; - let entries = r.raft_log.entries(index + 1, NO_LIMIT).expect(""); + let entries = r.raft_log.entries(index + 1, None).expect(""); assert_eq!(entries, wents); assert_eq!(r.pending_conf_index, pending_conf_index); } @@ -2998,10 +2983,10 @@ fn test_step_ignore_config() { #[test] fn test_new_leader_pending_config() { setup_for_test(); - let mut tests = vec![(false, 0), (true, 1)]; + let mut tests = vec![(false, 1), (true, 2)]; for (i, (add_entry, wpending_index)) in tests.drain(..).enumerate() { let mut r = new_test_raft(1, vec![1, 2], 10, 1, new_storage()); - let mut e = Entry::new(); + let mut e = Entry::new_(); if add_entry { e.set_entry_type(EntryType::EntryNormal); r.append_entry(&mut [e]); @@ -3155,12 +3140,14 @@ fn test_commit_after_remove_node() -> Result<()> { // Begin to remove the second node. let mut m = new_message(0, 0, MessageType::MsgPropose, 0); - let mut e = Entry::new(); + let mut e = Entry::new_(); e.set_entry_type(EntryType::EntryConfChange); - let mut cc = ConfChange::new(); + let mut cc = ConfChange::new_(); cc.set_change_type(ConfChangeType::RemoveNode); cc.set_node_id(2); - e.set_data(protobuf::Message::write_to_bytes(&cc).unwrap()); + let mut ccdata = Vec::with_capacity(ProstMsg::encoded_len(&cc)); + cc.encode(&mut ccdata).unwrap(); + e.set_data(ccdata); m.mut_entries().push(e); r.step(m).expect(""); // Stabilize the log and make sure nothing is committed yet. @@ -3287,7 +3274,7 @@ fn test_leader_transfer_to_slow_follower() { nt.send(vec![new_message(1, 1, MessageType::MsgPropose, 1)]); nt.recover(); - assert_eq!(nt.peers[&1].prs().get(3).unwrap().matched, 1); + assert_eq!(nt.peers[&1].prs().get(3).unwrap().matched, 2); // Transfer leadership to 3 when node 3 is lack of log. nt.send(vec![new_message(3, 1, MessageType::MsgTransferLeader, 0)]); @@ -3305,19 +3292,17 @@ fn test_leader_transfer_after_snapshot() { nt.send(vec![new_message(1, 1, MessageType::MsgPropose, 1)]); next_ents(&mut nt.peers.get_mut(&1).unwrap(), &nt.storage[&1]); - let mut cs = ConfState::new(); - cs.set_nodes(nt.peers[&1].prs().voter_ids().iter().cloned().collect()); nt.storage[&1] .wl() - .create_snapshot(nt.peers[&1].raft_log.applied, Some(cs), None, vec![]) - .expect(""); + .commit_to(nt.peers[&1].raft_log.applied) + .unwrap(); nt.storage[&1] .wl() .compact(nt.peers[&1].raft_log.applied) - .expect(""); + .unwrap(); nt.recover(); - assert_eq!(nt.peers[&1].prs().get(3).unwrap().matched, 1); + assert_eq!(nt.peers[&1].prs().get(3).unwrap().matched, 2); // Transfer leadership to 3 when node 3 is lack of snapshot. nt.send(vec![new_message(3, 1, MessageType::MsgTransferLeader, 0)]); @@ -3357,12 +3342,14 @@ fn test_leader_transfer_to_non_existing_node() { #[test] fn test_leader_transfer_to_learner() { setup_for_test(); - let mut leader_config = new_test_config(1, vec![1], 10, 1); - leader_config.learners = vec![2]; - let leader = new_test_raft_with_config(&leader_config, new_storage()); - let mut learner_config = new_test_config(2, vec![1], 10, 1); - learner_config.learners = vec![2]; - let learner = new_test_raft_with_config(&learner_config, new_storage()); + let s = MemStorage::new_with_conf_state((vec![1], vec![2])); + let c = new_test_config(1, 10, 1); + let leader = new_test_raft_with_config(&c, s); + + let s = MemStorage::new_with_conf_state((vec![1], vec![2])); + let c = new_test_config(2, 10, 1); + let learner = new_test_raft_with_config(&c, s); + let mut nt = Network::new(vec![Some(leader), Some(learner)]); nt.send(vec![new_message(1, 1, MessageType::MsgHup, 0)]); @@ -3417,7 +3404,7 @@ fn test_leader_transfer_ignore_proposal() { "should return drop proposal error while transferring" ); - assert_eq!(nt.peers[&1].prs().get(1).unwrap().matched, 1); + assert_eq!(nt.peers[&1].prs().get(1).unwrap().matched, 2); } #[test] @@ -3573,7 +3560,9 @@ fn test_node_with_smaller_term_can_complete_election() { n3.become_follower(1, INVALID_ID); // cause a network partition to isolate node 3 - let mut nt = Network::new_with_config(vec![Some(n1), Some(n2), Some(n3)], true); + let mut config = Network::default_config(); + config.pre_vote = true; + let mut nt = Network::new_with_config(vec![Some(n1), Some(n2), Some(n3)], &config); nt.cut(1, 3); nt.cut(2, 3); @@ -3628,9 +3617,14 @@ pub fn new_test_learner_raft( heartbeat: usize, storage: MemStorage, ) -> Interface { - let mut cfg = new_test_config(id, peers, election, heartbeat); - cfg.learners = learners; - Interface::new(Raft::new(&cfg, storage).unwrap()) + if storage.initial_state().unwrap().initialized() && peers.is_empty() { + panic!("new_test_raft with empty peers on initialized store"); + } + if !peers.is_empty() && !storage.initial_state().unwrap().initialized() { + storage.initialize_with_conf_state((peers, learners)); + } + let cfg = new_test_config(id, election, heartbeat); + new_test_raft_with_config(&cfg, storage) } // TestLearnerElectionTimeout verfies that the leader should not start election @@ -3846,7 +3840,7 @@ fn test_learner_receive_snapshot() { network.peers.get_mut(&1).unwrap().tick(); } - let mut msg = Message::new(); + let mut msg = Message::new_(); msg.set_from(1); msg.set_to(1); msg.set_msg_type(MessageType::MsgBeat); @@ -4052,8 +4046,9 @@ fn test_learner_respond_vote() -> Result<()> { #[test] fn test_election_tick_range() { setup_for_test(); - let mut cfg = new_test_config(1, vec![1, 2, 3], 10, 1); - let mut raft = Raft::new(&cfg, new_storage()).unwrap(); + let mut cfg = new_test_config(1, 10, 1); + let s = MemStorage::new_with_conf_state((vec![1, 2, 3], vec![])); + let mut raft = new_test_raft_with_config(&cfg, s).raft.unwrap(); for _ in 0..1000 { raft.reset_randomized_election_timeout(); let randomized_timeout = raft.get_randomized_election_timeout(); @@ -4075,7 +4070,7 @@ fn test_election_tick_range() { cfg.validate().unwrap_err(); cfg.max_election_tick = cfg.election_tick + 1; - raft = Raft::new(&cfg, new_storage()).unwrap(); + raft = new_test_raft_with_config(&cfg, new_storage()).raft.unwrap(); for _ in 0..100 { raft.reset_randomized_election_timeout(); let randomized_timeout = raft.get_randomized_election_timeout(); @@ -4136,12 +4131,13 @@ fn test_prevote_with_split_vote() { fn test_prevote_with_check_quorum() { setup_for_test(); let bootstrap = |id| { - let mut cfg = new_test_config(id, vec![1, 2, 3], 10, 1); + let mut cfg = new_test_config(id, 10, 1); cfg.pre_vote = true; cfg.check_quorum = true; - let mut raft = Raft::new(&cfg, new_storage()).unwrap(); - raft.become_follower(1, INVALID_ID); - Interface::new(raft) + let s = MemStorage::new_with_conf_state((vec![1, 2, 3], vec![])); + let mut i = new_test_raft_with_config(&cfg, s); + i.become_follower(1, INVALID_ID); + i }; let (peer1, peer2, peer3) = (bootstrap(1), bootstrap(2), bootstrap(3)); @@ -4202,7 +4198,35 @@ fn test_prevote_with_check_quorum() { // ensure a new Raft returns a Error::ConfigInvalid with an invalid config #[test] fn test_new_raft_with_bad_config_errors() { - let invalid_config = new_test_config(INVALID_ID, vec![1, 2], 1, 1); - let raft = Raft::new(&invalid_config, new_storage()); + let invalid_config = new_test_config(INVALID_ID, 1, 1); + let s = MemStorage::new_with_conf_state((vec![1, 2], vec![])); + let raft = Raft::new(&invalid_config, s); assert!(raft.is_err()) } + +// tests whether MsgAppend are batched +#[test] +fn test_batch_msg_append() { + setup_for_test(); + let storage = new_storage(); + let mut raft = new_test_raft(1, vec![1, 2, 3], 10, 1, storage.clone()); + raft.become_candidate(); + raft.become_leader(); + raft.set_batch_append(true); + commit_noop_entry(&mut raft, &storage); + for _ in 0..10 { + let prop_msg = new_message(1, 1, MessageType::MsgPropose, 1); + assert!(raft.step(prop_msg).is_ok()); + } + assert_eq!(raft.msgs.len(), 2); + for msg in &raft.msgs { + assert_eq!(msg.entries.len(), 10); + assert_eq!(msg.get_index(), 2); + } + // if the append entry is not continuous, raft should not batch the RPC + let mut reject_msg = new_message(2, 1, MessageType::MsgAppendResponse, 0); + reject_msg.reject = true; + reject_msg.index = 3; + assert!(raft.step(reject_msg).is_ok()); + assert_eq!(raft.msgs.len(), 3); +} diff --git a/tests/integration_cases/test_raft_flow_control.rs b/tests/integration_cases/test_raft_flow_control.rs index 8f161734b..6b51fc050 100644 --- a/tests/integration_cases/test_raft_flow_control.rs +++ b/tests/integration_cases/test_raft_flow_control.rs @@ -25,9 +25,18 @@ // See the License for the specific language governing permissions and // limitations under the License. +use crate::test_util::*; use harness::setup_for_test; -use raft::eraftpb::*; -use test_util::*; +use raft::{eraftpb::*, Raft, Storage}; + +// Force progress `pr` to be in replicate state at `i`. +fn progress_become_replicate(r: &mut Raft, pr: u64, i: u64) +where + T: Storage, +{ + r.mut_prs().get_mut(pr).unwrap().maybe_update(i - 1); + r.mut_prs().get_mut(pr).unwrap().become_replicate(); +} // test_msg_app_flow_control_full ensures: // 1. msgApp can fill the sending window until full @@ -39,8 +48,11 @@ fn test_msg_app_flow_control_full() { r.become_candidate(); r.become_leader(); + // The configuration is initialized at 1 and the leader's empty entry is at 2. + assert_eq!(r.raft_log.last_index(), 2); + // force the progress to be in replicate state - r.mut_prs().get_mut(2).unwrap().become_replicate(); + progress_become_replicate(&mut r, 2, 2); // fill in the inflights window for i in 0..r.max_inflight { r.step(new_message(1, 1, MessageType::MsgPropose, 1)) @@ -76,8 +88,11 @@ fn test_msg_app_flow_control_move_forward() { r.become_candidate(); r.become_leader(); + // The configuration is initialized at 1 and the leader's empty entry is at 2. + assert_eq!(r.raft_log.last_index(), 2); + // force the progress to be in replicate state - r.mut_prs().get_mut(2).unwrap().become_replicate(); + progress_become_replicate(&mut r, 2, 2); // fill in the inflights window for _ in 0..r.max_inflight { r.step(new_message(1, 1, MessageType::MsgPropose, 1)) @@ -85,9 +100,9 @@ fn test_msg_app_flow_control_move_forward() { r.read_messages(); } - // 1 is noop, 2 is the first proposal we just sent. - // so we start with 2. - for tt in 2..r.max_inflight { + // 2 is noop, 3 is the first proposal we just sent. + // so we start with 3. + for tt in 3..r.max_inflight { // move forward the window let mut m = new_message(2, 1, MessageType::MsgAppendResponse, 0); m.set_index(tt as u64); @@ -131,7 +146,7 @@ fn test_msg_app_flow_control_recv_heartbeat() { r.become_leader(); // force the progress to be in replicate state - r.mut_prs().get_mut(2).unwrap().become_replicate(); + progress_become_replicate(&mut r, 2, 2); // fill in the inflights window for _ in 0..r.max_inflight { r.step(new_message(1, 1, MessageType::MsgPropose, 1)) diff --git a/tests/integration_cases/test_raft_paper.rs b/tests/integration_cases/test_raft_paper.rs index 9eecda728..9bf466096 100644 --- a/tests/integration_cases/test_raft_paper.rs +++ b/tests/integration_cases/test_raft_paper.rs @@ -25,14 +25,13 @@ // See the License for the specific language governing permissions and // limitations under the License. +use crate::test_util::*; use harness::*; -use protobuf::RepeatedField; use raft::eraftpb::*; use raft::storage::MemStorage; use raft::*; -use test_util::*; -fn commit_noop_entry(r: &mut Interface, s: &MemStorage) { +pub fn commit_noop_entry(r: &mut Interface, s: &MemStorage) { assert_eq!(r.state, StateRole::Leader); r.bcast_append(); // simulate the response of MsgAppend @@ -98,10 +97,10 @@ fn test_update_term_from_message(state: StateRole) { } let mut m = new_message(0, 0, MessageType::MsgAppend, 0); - m.set_term(2); + m.set_term(3); r.step(m).expect(""); - assert_eq!(r.term, 2); + assert_eq!(r.term, 3); assert_eq!(r.state, StateRole::Follower); } @@ -139,7 +138,7 @@ fn test_leader_bcast_beat() { let new_message_ext = |f, to| { let mut m = new_message(f, to, MessageType::MsgHeartbeat, 0); - m.set_term(1); + m.set_term(2); m.set_commit(0); m }; @@ -175,7 +174,7 @@ fn test_nonleader_start_election(state: StateRole) { let et = 10; let mut r = new_test_raft(1, vec![1, 2, 3], et, 1, new_storage()); match state { - StateRole::Follower => r.become_follower(1, 2), + StateRole::Follower => r.become_follower(2, 2), StateRole::Candidate => r.become_candidate(), _ => panic!("Only non-leader role is accepted."), } @@ -184,16 +183,16 @@ fn test_nonleader_start_election(state: StateRole) { r.tick(); } - assert_eq!(r.term, 2); + assert_eq!(r.term, 3); assert_eq!(r.state, StateRole::Candidate); assert!(r.votes[&r.id]); let mut msgs = r.read_messages(); msgs.sort_by_key(|m| format!("{:?}", m)); let new_message_ext = |f, to| { let mut m = new_message(f, to, MessageType::MsgRequestVote, 0); - m.set_term(2); - m.set_log_term(0); - m.set_index(0); + m.set_term(3); + m.set_log_term(1); + m.set_index(1); m }; let expect_msgs = vec![new_message_ext(1, 2), new_message_ext(1, 3)]; @@ -254,8 +253,8 @@ fn test_leader_election_in_one_round_rpc() { if r.state != state { panic!("#{}: state = {:?}, want {:?}", i, r.state, state); } - if r.term != 1 { - panic!("#{}: term = {}, want {}", i, r.term, 1); + if r.term != 2 { + panic!("#{}: term = {}, want {}", i, r.term, 2); } } } @@ -277,10 +276,12 @@ fn test_follower_vote() { for (i, (vote, nvote, wreject)) in tests.drain(..).enumerate() { let mut r = new_test_raft(1, vec![1, 2, 3], 10, 1, new_storage()); - r.load_state(&hard_state(1, 0, vote)); + r.load_state(&hard_state(1, 1, vote)); let mut m = new_message(nvote, 1, MessageType::MsgRequestVote, 0); m.set_term(1); + m.set_log_term(1); + m.set_index(1); r.step(m).expect(""); let msgs = r.read_messages(); @@ -307,7 +308,7 @@ fn test_candidate_fallback() { m.set_term(term); m }; - let mut tests = vec![new_message_ext(2, 1, 1), new_message_ext(2, 1, 2)]; + let mut tests = vec![new_message_ext(2, 1, 2), new_message_ext(2, 1, 3)]; for (i, m) in tests.drain(..).enumerate() { let mut r = new_test_raft(1, vec![1, 2, 3], 10, 1, new_storage()); r.step(new_message(1, 1, MessageType::MsgHup, 0)).expect(""); @@ -449,14 +450,14 @@ fn test_leader_start_replication() { assert_eq!(r.raft_log.committed, li); let mut msgs = r.read_messages(); msgs.sort_by_key(|m| format!("{:?}", m)); - let wents = vec![new_entry(1, li + 1, SOME_DATA)]; + let wents = vec![new_entry(2, li + 1, SOME_DATA)]; let new_message_ext = |f, to, ents| { let mut m = new_message(f, to, MessageType::MsgAppend, 0); - m.set_term(1); + m.set_term(2); m.set_index(li); - m.set_log_term(1); + m.set_log_term(2); m.set_commit(li); - m.set_entries(RepeatedField::from_vec(ents)); + m.set_entries(ents); m }; let expect_msgs = vec![ @@ -491,7 +492,7 @@ fn test_leader_commit_entry() { } assert_eq!(r.raft_log.committed, li + 1); - let wents = vec![new_entry(1, li + 1, SOME_DATA)]; + let wents = vec![new_entry(2, li + 1, SOME_DATA)]; assert_eq!(r.raft_log.next_entries(), Some(wents)); let mut msgs = r.read_messages(); msgs.sort_by_key(|m| format!("{:?}", m)); @@ -552,18 +553,22 @@ fn test_leader_commit_preceding_entries() { setup_for_test(); let mut tests = vec![ vec![], - vec![empty_entry(2, 1)], - vec![empty_entry(1, 1), empty_entry(2, 2)], - vec![empty_entry(1, 1)], + vec![empty_entry(2, 2)], + vec![empty_entry(1, 2), empty_entry(2, 3)], + vec![empty_entry(1, 2)], ]; for (i, mut tt) in tests.drain(..).enumerate() { - let s = new_storage(); - s.wl().append(&tt).expect(""); - let mut r = new_test_raft(1, vec![1, 2, 3], 10, 1, s); - r.load_state(&hard_state(2, 0, 0)); + let mut r = { + let store = MemStorage::new_with_conf_state((vec![1, 2, 3], vec![])); + store.wl().append(&tt).unwrap(); + let cfg = new_test_config(1, 10, 1); + new_test_raft_with_config(&cfg, store) + }; + r.load_state(&hard_state(2, 1, 0)); r.become_candidate(); r.become_leader(); + r.step(new_message(1, 1, MessageType::MsgPropose, 1)) .expect(""); @@ -573,8 +578,8 @@ fn test_leader_commit_preceding_entries() { let li = tt.len() as u64; tt.append(&mut vec![ - empty_entry(3, li + 1), - new_entry(3, li + 2, SOME_DATA), + empty_entry(3, li + 2), + new_entry(3, li + 3, SOME_DATA), ]); let g = r.raft_log.next_entries(); let wg = Some(tt); @@ -591,27 +596,27 @@ fn test_leader_commit_preceding_entries() { fn test_follower_commit_entry() { setup_for_test(); let mut tests = vec![ - (vec![new_entry(1, 1, SOME_DATA)], 1), + (vec![new_entry(1, 2, SOME_DATA)], 2), ( vec![ - new_entry(1, 1, SOME_DATA), - new_entry(1, 2, Some("somedata2")), + new_entry(1, 2, SOME_DATA), + new_entry(1, 3, Some("somedata2")), ], - 2, + 3, ), ( vec![ - new_entry(1, 1, Some("somedata2")), - new_entry(1, 2, SOME_DATA), + new_entry(1, 2, Some("somedata2")), + new_entry(1, 3, SOME_DATA), ], - 2, + 3, ), ( vec![ - new_entry(1, 1, SOME_DATA), - new_entry(1, 2, Some("somedata2")), + new_entry(1, 2, SOME_DATA), + new_entry(1, 3, Some("somedata2")), ], - 1, + 2, ), ]; @@ -621,8 +626,10 @@ fn test_follower_commit_entry() { let mut m = new_message(2, 1, MessageType::MsgAppend, 0); m.set_term(1); + m.set_log_term(1); + m.set_index(1); m.set_commit(commit); - m.set_entries(RepeatedField::from_vec(ents.clone())); + m.set_entries(ents.clone()); r.step(m).expect(""); if r.raft_log.committed != commit { @@ -631,7 +638,7 @@ fn test_follower_commit_entry() { i, r.raft_log.committed, commit ); } - let wents = Some(ents[..commit as usize].to_vec()); + let wents = Some(ents[..commit as usize - 1].to_vec()); let g = r.raft_log.next_entries(); if g != wents { panic!("#{}: next_ents = {:?}, want {:?}", i, g, wents); @@ -647,20 +654,20 @@ fn test_follower_commit_entry() { #[test] fn test_follower_check_msg_append() { setup_for_test(); - let ents = vec![empty_entry(1, 1), empty_entry(2, 2)]; + let ents = vec![empty_entry(1, 2), empty_entry(2, 3)]; let mut tests = vec![ // match with committed entries - (0, 0, 1, false, 0), - (ents[0].get_term(), ents[0].get_index(), 1, false, 0), + (1, 2, 2, false, 0), + (ents[0].get_term(), ents[0].get_index(), 2, false, 0), // match with uncommitted entries - (ents[1].get_term(), ents[1].get_index(), 2, false, 0), + (ents[1].get_term(), ents[1].get_index(), 3, false, 0), // unmatch with existing entry ( ents[0].get_term(), ents[1].get_index(), ents[1].get_index(), true, - 2, + 3, ), // unexisting entry ( @@ -668,14 +675,17 @@ fn test_follower_check_msg_append() { ents[1].get_index() + 1, ents[1].get_index() + 1, true, - 2, + 3, ), ]; for (i, (term, index, windex, wreject, wreject_hint)) in tests.drain(..).enumerate() { - let s = new_storage(); - s.wl().append(&ents).expect(""); - let mut r = new_test_raft(1, vec![1, 2, 3], 10, 1, s); - r.load_state(&hard_state(0, 1, 0)); + let mut r = { + let store = MemStorage::new_with_conf_state((vec![1, 2, 3], vec![])); + store.wl().append(&ents).unwrap(); + let cfg = new_test_config(1, 10, 1); + new_test_raft_with_config(&cfg, store) + }; + r.load_state(&hard_state(1, 1, 0)); r.become_follower(2, 2); let mut m = new_message(2, 1, MessageType::MsgAppend, 0); @@ -709,47 +719,51 @@ fn test_follower_append_entries() { setup_for_test(); let mut tests = vec![ ( + 3, 2, - 2, - vec![empty_entry(3, 3)], - vec![empty_entry(1, 1), empty_entry(2, 2), empty_entry(3, 3)], - vec![empty_entry(3, 3)], + vec![empty_entry(3, 4)], + vec![empty_entry(1, 2), empty_entry(2, 3), empty_entry(3, 4)], + vec![empty_entry(3, 4)], ), ( + 2, 1, - 1, - vec![empty_entry(3, 2), empty_entry(4, 3)], - vec![empty_entry(1, 1), empty_entry(3, 2), empty_entry(4, 3)], - vec![empty_entry(3, 2), empty_entry(4, 3)], + vec![empty_entry(3, 3), empty_entry(4, 4)], + vec![empty_entry(1, 2), empty_entry(3, 3), empty_entry(4, 4)], + vec![empty_entry(3, 3), empty_entry(4, 4)], ), ( - 0, - 0, - vec![empty_entry(1, 1)], - vec![empty_entry(1, 1), empty_entry(2, 2)], + 1, + 1, + vec![empty_entry(1, 2)], + vec![empty_entry(1, 2), empty_entry(2, 3)], vec![], ), ( - 0, - 0, - vec![empty_entry(3, 1)], - vec![empty_entry(3, 1)], - vec![empty_entry(3, 1)], + 1, + 1, + vec![empty_entry(3, 2)], + vec![empty_entry(3, 2)], + vec![empty_entry(3, 2)], ), ]; for (i, (index, term, ents, wents, wunstable)) in tests.drain(..).enumerate() { - let s = new_storage(); - s.wl() - .append(&[empty_entry(1, 1), empty_entry(2, 2)]) - .expect(""); - let mut r = new_test_raft(1, vec![1, 2, 3], 10, 1, s); + let mut r = { + let store = MemStorage::new_with_conf_state((vec![1, 2, 3], vec![])); + store + .wl() + .append(&[empty_entry(1, 2), empty_entry(2, 3)]) + .unwrap(); + let cfg = new_test_config(1, 10, 1); + new_test_raft_with_config(&cfg, store) + }; r.become_follower(2, 2); let mut m = new_message(2, 1, MessageType::MsgAppend, 0); m.set_term(2); m.set_log_term(term); m.set_index(index); - m.set_entries(RepeatedField::from_vec(ents)); + m.set_entries(ents); r.step(m).expect(""); let g = r.raft_log.all_entries(); @@ -775,8 +789,6 @@ fn test_follower_append_entries() { fn test_leader_sync_follower_log() { setup_for_test(); let ents = vec![ - empty_entry(0, 0), - empty_entry(1, 1), empty_entry(1, 2), empty_entry(1, 3), empty_entry(4, 4), @@ -790,8 +802,6 @@ fn test_leader_sync_follower_log() { let term = 8u64; let mut tests = vec![ vec![ - empty_entry(0, 0), - empty_entry(1, 1), empty_entry(1, 2), empty_entry(1, 3), empty_entry(4, 4), @@ -801,16 +811,8 @@ fn test_leader_sync_follower_log() { empty_entry(6, 8), empty_entry(6, 9), ], + vec![empty_entry(1, 2), empty_entry(1, 3), empty_entry(4, 4)], vec![ - empty_entry(0, 0), - empty_entry(1, 1), - empty_entry(1, 2), - empty_entry(1, 3), - empty_entry(4, 4), - ], - vec![ - empty_entry(0, 0), - empty_entry(1, 1), empty_entry(1, 2), empty_entry(1, 3), empty_entry(4, 4), @@ -823,8 +825,6 @@ fn test_leader_sync_follower_log() { empty_entry(6, 11), ], vec![ - empty_entry(0, 0), - empty_entry(1, 1), empty_entry(1, 2), empty_entry(1, 3), empty_entry(4, 4), @@ -838,8 +838,6 @@ fn test_leader_sync_follower_log() { empty_entry(7, 12), ], vec![ - empty_entry(0, 0), - empty_entry(1, 1), empty_entry(1, 2), empty_entry(1, 3), empty_entry(4, 4), @@ -848,8 +846,6 @@ fn test_leader_sync_follower_log() { empty_entry(4, 7), ], vec![ - empty_entry(0, 0), - empty_entry(1, 1), empty_entry(1, 2), empty_entry(1, 3), empty_entry(2, 4), @@ -863,15 +859,23 @@ fn test_leader_sync_follower_log() { ], ]; for (i, tt) in tests.drain(..).enumerate() { - let lead_store = new_storage(); - lead_store.wl().append(&ents).expect(""); - let mut lead = new_test_raft(1, vec![1, 2, 3], 10, 1, lead_store); + let mut lead = { + let store = MemStorage::new_with_conf_state((vec![1, 2, 3], vec![])); + store.wl().append(&ents).unwrap(); + let cfg = new_test_config(1, 10, 1); + new_test_raft_with_config(&cfg, store) + }; let last_index = lead.raft_log.last_index(); lead.load_state(&hard_state(term, last_index, 0)); - let follower_store = new_storage(); - follower_store.wl().append(&tt).expect(""); - let mut follower = new_test_raft(2, vec![1, 2, 3], 10, 1, follower_store); - follower.load_state(&hard_state(term - 1, 0, 0)); + + let mut follower = { + let store = MemStorage::new_with_conf_state((vec![1, 2, 3], vec![])); + store.wl().append(&tt).unwrap(); + let cfg = new_test_config(2, 10, 1); + new_test_raft_with_config(&cfg, store) + }; + follower.load_state(&hard_state(term - 1, 1, 0)); + // It is necessary to have a three-node cluster. // The second may have more up-to-date log than the first one, so the // first node needs the vote from the third node to become the leader. @@ -884,7 +888,7 @@ fn test_leader_sync_follower_log() { n.send(vec![m]); let mut m = new_message(1, 1, MessageType::MsgPropose, 0); - m.set_entries(RepeatedField::from_vec(vec![Entry::new()])); + m.set_entries(vec![Entry::new_()]); n.send(vec![m]); let lead_str = ltoa(&n.peers[&1].raft_log); let follower_str = ltoa(&n.peers[&2].raft_log); @@ -904,16 +908,16 @@ fn test_leader_sync_follower_log() { fn test_vote_request() { setup_for_test(); let mut tests = vec![ - (vec![empty_entry(1, 1)], 2), - (vec![empty_entry(1, 1), empty_entry(2, 2)], 3), + (vec![empty_entry(1, 2)], 2), + (vec![empty_entry(1, 2), empty_entry(2, 3)], 3), ]; for (j, (ents, wterm)) in tests.drain(..).enumerate() { let mut r = new_test_raft(1, vec![1, 2, 3], 10, 1, new_storage()); let mut m = new_message(2, 1, MessageType::MsgAppend, 0); m.set_term(wterm - 1); - m.set_log_term(0); - m.set_index(0); - m.set_entries(RepeatedField::from_vec(ents.clone())); + m.set_log_term(1); // log-term must be greater than 0. + m.set_index(1); + m.set_entries(ents.clone()); r.step(m).expect(""); r.read_messages(); @@ -968,22 +972,23 @@ fn test_voter() { setup_for_test(); let mut tests = vec![ // same logterm - (vec![empty_entry(1, 1)], 1, 1, false), - (vec![empty_entry(1, 1)], 1, 2, false), - (vec![empty_entry(1, 1), empty_entry(1, 2)], 1, 1, true), + (vec![empty_entry(1, 2)], 1, 2, false), + (vec![empty_entry(1, 2)], 1, 3, false), + (vec![empty_entry(1, 2), empty_entry(1, 3)], 1, 1, true), // candidate higher logterm - (vec![empty_entry(1, 1)], 2, 1, false), - (vec![empty_entry(1, 1)], 2, 2, false), - (vec![empty_entry(1, 1), empty_entry(1, 2)], 2, 1, false), + (vec![empty_entry(1, 2)], 2, 2, false), + (vec![empty_entry(1, 2)], 2, 3, false), + (vec![empty_entry(1, 2), empty_entry(1, 3)], 2, 2, false), // voter higher logterm - (vec![empty_entry(2, 1)], 1, 1, true), - (vec![empty_entry(2, 1)], 1, 2, true), - (vec![empty_entry(2, 1), empty_entry(1, 2)], 1, 1, true), + (vec![empty_entry(2, 2)], 1, 2, true), + (vec![empty_entry(2, 2)], 1, 3, true), + (vec![empty_entry(2, 2), empty_entry(1, 3)], 1, 2, true), ]; for (i, (ents, log_term, index, wreject)) in tests.drain(..).enumerate() { - let s = new_storage(); - s.wl().append(&ents).expect(""); - let mut r = new_test_raft(1, vec![1, 2], 10, 1, s); + let s = MemStorage::new_with_conf_state((vec![1, 2], vec![])); + s.wl().append(&ents).unwrap(); + let cfg = new_test_config(1, 10, 1); + let mut r = new_test_raft_with_config(&cfg, s); let mut m = new_message(2, 1, MessageType::MsgRequestVote, 0); m.set_term(3); @@ -1020,23 +1025,28 @@ fn test_voter() { #[test] fn test_leader_only_commits_log_from_current_term() { setup_for_test(); - let ents = vec![empty_entry(1, 1), empty_entry(2, 2)]; + let ents = vec![empty_entry(1, 2), empty_entry(2, 3)]; let mut tests = vec![ // do not commit log entries in previous terms - (1, 0), - (2, 0), + (1, 1), + (2, 1), // commit log in current term - (3, 3), + (4, 4), ]; for (i, (index, wcommit)) in tests.drain(..).enumerate() { - let store = new_storage(); - store.wl().append(&ents).expect(""); - let mut r = new_test_raft(1, vec![1, 2], 10, 1, store); - r.load_state(&hard_state(2, 0, 0)); + let mut r = { + let store = MemStorage::new_with_conf_state((vec![1, 2], vec![])); + store.wl().append(&ents).unwrap(); + let cfg = new_test_config(1, 10, 1); + new_test_raft_with_config(&cfg, store) + }; + r.load_state(&hard_state(2, 1, 0)); + // become leader at term 3 r.become_candidate(); r.become_leader(); r.read_messages(); + // propose a entry to current term r.step(new_message(1, 1, MessageType::MsgPropose, 1)) .expect(""); diff --git a/tests/integration_cases/test_raft_snap.rs b/tests/integration_cases/test_raft_snap.rs index 97924e0b1..aea94ef7a 100644 --- a/tests/integration_cases/test_raft_snap.rs +++ b/tests/integration_cases/test_raft_snap.rs @@ -25,9 +25,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -use harness::setup_for_test; +use crate::test_util::*; +use harness::{setup_for_test, Network}; use raft::eraftpb::*; -use test_util::*; fn testing_snap() -> Snapshot { new_snapshot(11, 11, vec![1, 2]) @@ -134,3 +134,20 @@ fn test_snapshot_abort() { assert_eq!(sm.prs().get(2).unwrap().pending_snapshot, 0); assert_eq!(sm.prs().get(2).unwrap().next_idx, 12); } + +// Initialized storage should be at term 1 instead of 0. Otherwise the case will fail. +#[test] +fn test_snapshot_with_min_term() { + setup_for_test(); + let do_test = |pre_vote: bool| { + let n1 = new_test_raft_with_prevote(1, vec![1, 2], 10, 1, new_storage(), pre_vote); + let n2 = new_test_raft_with_prevote(2, vec![], 10, 1, new_storage(), pre_vote); + let mut nt = Network::new(vec![Some(n1), Some(n2)]); + nt.send(vec![new_message(1, 1, MessageType::MsgHup, 0)]); + // 1 will be elected as leader, and then send a snapshot and an empty entry to 2. + assert_eq!(nt.peers[&2].raft_log.first_index(), 2); + assert_eq!(nt.peers[&2].raft_log.last_index(), 2); + }; + do_test(true); + do_test(false); +} diff --git a/tests/integration_cases/test_raw_node.rs b/tests/integration_cases/test_raw_node.rs index e253ccba8..d519d6092 100644 --- a/tests/integration_cases/test_raw_node.rs +++ b/tests/integration_cases/test_raw_node.rs @@ -26,53 +26,36 @@ // limitations under the License. use harness::*; -use protobuf::{self, ProtobufEnum}; +use prost::Message as ProstMsg; use raft::eraftpb::*; use raft::storage::MemStorage; use raft::*; -use test_util::*; -fn new_peer(id: u64) -> Peer { - Peer { - id, - ..Default::default() - } -} - -fn entry(t: EntryType, term: u64, i: u64, data: Option>) -> Entry { - let mut e = Entry::new(); - e.set_index(i); - e.set_term(term); - if let Some(d) = data { - e.set_data(d); - } - e.set_entry_type(t); - e -} +use crate::test_util::*; fn conf_change(t: ConfChangeType, node_id: u64) -> ConfChange { - let mut cc = ConfChange::new(); + let mut cc = ConfChange::new_(); cc.set_change_type(t); cc.set_node_id(node_id); cc } -fn cmp_ready( +fn must_cmp_ready( r: &Ready, ss: &Option, hs: &Option, entries: &[Entry], committed_entries: Vec, must_sync: bool, -) -> bool { - r.ss() == ss.as_ref() - && r.hs() == hs.as_ref() - && r.entries() == entries - && r.committed_entries == Some(committed_entries) - && r.must_sync() == must_sync - && r.read_states().is_empty() - && r.snapshot() == &Snapshot::default() - && r.messages.is_empty() +) { + assert_eq!(r.ss(), ss.as_ref()); + assert_eq!(r.hs(), hs.as_ref()); + assert_eq!(r.entries(), entries); + assert_eq!(r.committed_entries, Some(committed_entries)); + assert_eq!(r.must_sync(), must_sync); + assert!(r.read_states().is_empty()); + assert_eq!(r.snapshot(), &Snapshot::default()); + assert!(r.messages.is_empty()); } fn new_raw_node( @@ -81,23 +64,38 @@ fn new_raw_node( election: usize, heartbeat: usize, storage: MemStorage, - peer_nodes: Vec, ) -> RawNode { - RawNode::new( - &new_test_config(id, peers, election, heartbeat), - storage, - peer_nodes, - ) - .unwrap() + let config = new_test_config(id, election, heartbeat); + if storage.initial_state().unwrap().initialized() && peers.is_empty() { + panic!("new_raw_node with empty peers on initialized store"); + } + if !peers.is_empty() && !storage.initial_state().unwrap().initialized() { + storage.initialize_with_conf_state((peers, vec![])); + } + RawNode::new(&config, storage).unwrap() } // test_raw_node_step ensures that RawNode.Step ignore local message. #[test] fn test_raw_node_step() { setup_for_test(); - for msg_t in MessageType::values() { - let mut raw_node = new_raw_node(1, vec![], 10, 1, new_storage(), vec![new_peer(1)]); - let res = raw_node.step(new_message(0, 0, *msg_t, 0)); + for msg_t in 0..18 { + let msg_t = MessageType::from_i32(msg_t).unwrap(); + if vec![ + // Vote messages with term 0 will cause panics. + MessageType::MsgRequestVote, + MessageType::MsgRequestPreVote, + // MsgAppend and MsgSnapshot with log term 0 will cause test code panics. + MessageType::MsgAppend, + MessageType::MsgSnapshot, + ] + .contains(&msg_t) + { + continue; + } + + let mut raw_node = new_raw_node(1, vec![1], 10, 1, new_storage()); + let res = raw_node.step(new_message(0, 0, msg_t, 0)); // local msg should be ignored. if vec![ MessageType::MsgBeat, @@ -105,7 +103,7 @@ fn test_raw_node_step() { MessageType::MsgUnreachable, MessageType::MsgSnapStatus, ] - .contains(msg_t) + .contains(&msg_t) { assert_eq!(res, Err(Error::StepLocalMsg)); } @@ -125,7 +123,7 @@ fn test_raw_node_read_index_to_old_leader() { // elect r1 as leader nt.send(vec![new_message(1, 1, MessageType::MsgHup, 0)]); - let mut test_entries = Entry::new(); + let mut test_entries = Entry::new_(); test_entries.set_data(b"testdata".to_vec()); // send readindex request to r2(follower) @@ -180,10 +178,7 @@ fn test_raw_node_read_index_to_old_leader() { fn test_raw_node_propose_and_conf_change() { setup_for_test(); let s = new_storage(); - let mut raw_node = new_raw_node(1, vec![], 10, 1, s.clone(), vec![new_peer(1)]); - let rd = raw_node.ready(); - s.wl().append(rd.entries()).expect(""); - raw_node.advance(rd); + let mut raw_node = new_raw_node(1, vec![1], 10, 1, s.clone()); raw_node.campaign().expect(""); let mut proposed = false; let mut last_index; @@ -195,23 +190,24 @@ fn test_raw_node_propose_and_conf_change() { if !proposed && rd.ss().is_some() && rd.ss().unwrap().leader_id == raw_node.raft.id { raw_node.propose(vec![], b"somedata".to_vec()).expect(""); - let cc = conf_change(ConfChangeType::AddNode, 1); - ccdata = protobuf::Message::write_to_bytes(&cc).unwrap(); + let cc = conf_change(ConfChangeType::AddNode, 2); + ccdata.reserve_exact(ProstMsg::encoded_len(&cc)); + cc.encode(&mut ccdata).unwrap(); raw_node.propose_conf_change(vec![], cc).expect(""); proposed = true; } raw_node.advance(rd); - // Exit when we have four entries: one ConfChange, one no-op for the election, - // our proposed command and proposed ConfChange. + // Exit when we have 3 entries: one initial configuration, one no-op for the election + // and proposed ConfChange. last_index = s.last_index().unwrap(); - if last_index >= 4 { + if last_index >= 3 { break; } } - let entries = s.entries(last_index - 1, last_index + 1, NO_LIMIT).unwrap(); + let entries = s.entries(last_index - 1, last_index + 1, None).unwrap(); assert_eq!(entries.len(), 2); assert_eq!(entries[0].get_data(), b"somedata"); assert_eq!(entries[1].get_entry_type(), EntryType::EntryConfChange); @@ -224,11 +220,7 @@ fn test_raw_node_propose_and_conf_change() { fn test_raw_node_propose_add_duplicate_node() { setup_for_test(); let s = new_storage(); - let mut raw_node = new_raw_node(1, vec![], 10, 1, s.clone(), vec![new_peer(1)]); - let rd = raw_node.ready(); - s.wl().append(rd.entries()).expect(""); - raw_node.advance(rd); - + let mut raw_node = new_raw_node(1, vec![1], 10, 1, s.clone()); raw_node.campaign().expect(""); loop { let rd = raw_node.ready(); @@ -246,7 +238,7 @@ fn test_raw_node_propose_add_duplicate_node() { s.wl().append(rd.entries()).expect(""); for e in rd.committed_entries.as_ref().unwrap() { if e.get_entry_type() == EntryType::EntryConfChange { - let conf_change = protobuf::parse_from_bytes(e.get_data()).unwrap(); + let conf_change = ConfChange::decode(e.get_data()).unwrap(); raw_node.apply_conf_change(&conf_change).ok(); } } @@ -254,7 +246,8 @@ fn test_raw_node_propose_add_duplicate_node() { }; let cc1 = conf_change(ConfChangeType::AddNode, 1); - let ccdata1 = protobuf::Message::write_to_bytes(&cc1).unwrap(); + let mut ccdata1 = Vec::with_capacity(ProstMsg::encoded_len(&cc1)); + cc1.encode(&mut ccdata1).unwrap(); propose_conf_change_and_apply(cc1.clone()); // try to add the same node again @@ -262,13 +255,14 @@ fn test_raw_node_propose_add_duplicate_node() { // the new node join should be ok let cc2 = conf_change(ConfChangeType::AddNode, 2); - let ccdata2 = protobuf::Message::write_to_bytes(&cc2).unwrap(); + let mut ccdata2 = Vec::with_capacity(ProstMsg::encoded_len(&cc2)); + cc2.encode(&mut ccdata2).unwrap(); propose_conf_change_and_apply(cc2); let last_index = s.last_index().unwrap(); // the last three entries should be: ConfChange cc1, cc1, cc2 - let mut entries = s.entries(last_index - 2, last_index + 1, NO_LIMIT).unwrap(); + let mut entries = s.entries(last_index - 2, last_index + 1, None).unwrap(); assert_eq!(entries.len(), 3); assert_eq!(entries[0].take_data(), ccdata1); assert_eq!(entries[2].take_data(), ccdata2); @@ -278,7 +272,7 @@ fn test_raw_node_propose_add_duplicate_node() { fn test_raw_node_propose_add_learner_node() -> Result<()> { setup_for_test(); let s = new_storage(); - let mut raw_node = new_raw_node(1, vec![], 10, 1, s.clone(), vec![new_peer(1)]); + let mut raw_node = new_raw_node(1, vec![1], 10, 1, s.clone()); let rd = raw_node.ready(); s.wl().append(rd.entries()).expect(""); raw_node.advance(rd); @@ -307,7 +301,7 @@ fn test_raw_node_propose_add_learner_node() -> Result<()> { ); let e = &rd.committed_entries.as_ref().unwrap()[0]; - let conf_change = protobuf::parse_from_bytes(e.get_data()).unwrap(); + let conf_change = ConfChange::decode(e.get_data()).unwrap(); let conf_state = raw_node.apply_conf_change(&conf_change)?; assert_eq!(conf_state.nodes, vec![1]); assert_eq!(conf_state.learners, vec![2]); @@ -327,10 +321,7 @@ fn test_raw_node_read_index() { }]; let s = new_storage(); - let mut raw_node = new_raw_node(1, vec![], 10, 1, s.clone(), vec![new_peer(1)]); - let rd = raw_node.ready(); - s.wl().append(rd.entries()).expect(""); - raw_node.advance(rd); + let mut raw_node = new_raw_node(1, vec![1], 10, 1, s.clone()); raw_node.campaign().expect(""); loop { let rd = raw_node.ready(); @@ -358,41 +349,17 @@ fn test_raw_node_read_index() { assert!(raw_node.raft.read_states.is_empty()); } -// test_raw_node_start ensures that a node can be started correctly. The node should -// start with correct configuration change entries, and can accept and commit -// proposals. +// test_raw_node_start ensures that a node can be started correctly. #[test] fn test_raw_node_start() { setup_for_test(); - let cc = conf_change(ConfChangeType::AddNode, 1); - let ccdata = protobuf::Message::write_to_bytes(&cc).unwrap(); let store = new_storage(); - let mut raw_node = new_raw_node(1, vec![], 10, 1, store.clone(), vec![new_peer(1)]); - let rd = raw_node.ready(); - info!("rd {:?}", &rd); - assert!(cmp_ready( - &rd, - &None, - &Some(hard_state(1, 1, 0)), - &[entry( - EntryType::EntryConfChange, - 1, - 1, - Some(ccdata.clone()), - )], - vec![entry( - EntryType::EntryConfChange, - 1, - 1, - Some(ccdata.clone()), - )], - true, - )); - store.wl().append(rd.entries()).expect(""); - raw_node.advance(rd); + let mut raw_node = new_raw_node(1, vec![1], 10, 1, store.clone()); let rd = raw_node.ready(); - store.wl().append(rd.entries()).expect(""); + must_cmp_ready(&rd, &None, &None, &[], vec![], false); + + store.wl().append(rd.entries()).unwrap(); raw_node.advance(rd); raw_node.campaign().expect(""); @@ -402,14 +369,14 @@ fn test_raw_node_start() { raw_node.propose(vec![], b"foo".to_vec()).expect(""); let rd = raw_node.ready(); - assert!(cmp_ready( + must_cmp_ready( &rd, &None, &Some(hard_state(2, 3, 1)), &[new_entry(2, 3, Some("foo"))], vec![new_entry(2, 3, Some("foo"))], false, - )); + ); store.wl().append(rd.entries()).expect(""); raw_node.advance(rd); assert!(!raw_node.has_ready()); @@ -419,21 +386,16 @@ fn test_raw_node_start() { fn test_raw_node_restart() { setup_for_test(); let entries = vec![empty_entry(1, 1), new_entry(1, 2, Some("foo"))]; - let st = hard_state(1, 1, 0); - let store = new_storage(); - store.wl().set_hardstate(st); - store.wl().append(&entries).expect(""); - let mut raw_node = new_raw_node(1, vec![], 10, 1, store, vec![]); + let mut raw_node = { + let store = new_storage(); + store.wl().set_hardstate(hard_state(1, 1, 0)); + store.wl().append(&entries).unwrap(); + new_raw_node(1, vec![], 10, 1, store) + }; + let rd = raw_node.ready(); - assert!(cmp_ready( - &rd, - &None, - &None, - &[], - entries[..1].to_vec(), - false - )); + must_cmp_ready(&rd, &None, &None, &[], entries[..1].to_vec(), false); raw_node.advance(rd); assert!(!raw_node.has_ready()); } @@ -443,15 +405,18 @@ fn test_raw_node_restart_from_snapshot() { setup_for_test(); let snap = new_snapshot(2, 1, vec![1, 2]); let entries = vec![new_entry(1, 3, Some("foo"))]; - let st = hard_state(1, 3, 0); - let s = new_storage(); - s.wl().set_hardstate(st); - s.wl().apply_snapshot(snap).expect(""); - s.wl().append(&entries).expect(""); - let mut raw_node = new_raw_node(1, vec![], 10, 1, s, vec![]); + let mut raw_node = { + let raw_node = new_raw_node(1, vec![], 10, 1, new_storage()); + let store = raw_node.raft.raft_log.store; + store.wl().apply_snapshot(snap).unwrap(); + store.wl().append(&entries).unwrap(); + store.wl().set_hardstate(hard_state(1, 3, 0)); + RawNode::new(&new_test_config(1, 10, 1), store).unwrap() + }; + let rd = raw_node.ready(); - assert!(cmp_ready(&rd, &None, &None, &[], entries.clone(), false)); + must_cmp_ready(&rd, &None, &None, &[], entries.clone(), false); raw_node.advance(rd); assert!(!raw_node.has_ready()); } @@ -461,9 +426,10 @@ fn test_raw_node_restart_from_snapshot() { #[test] fn test_skip_bcast_commit() { setup_for_test(); - let mut config = new_test_config(1, vec![1, 2, 3], 10, 1); + let mut config = new_test_config(1, 10, 1); config.skip_bcast_commit = true; - let r1 = new_test_raft_with_config(&config, new_storage()); + let s = MemStorage::new_with_conf_state((vec![1, 2, 3], vec![])); + let r1 = new_test_raft_with_config(&config, s); let r2 = new_test_raft(2, vec![1, 2, 3], 10, 1, new_storage()); let r3 = new_test_raft(3, vec![1, 2, 3], 10, 1, new_storage()); let mut nt = Network::new(vec![Some(r1), Some(r2), Some(r3)]); @@ -472,41 +438,48 @@ fn test_skip_bcast_commit() { nt.send(vec![new_message(1, 1, MessageType::MsgHup, 0)]); // Without bcast commit, followers will not update its commit index immediately. - let mut test_entries = Entry::new(); + let mut test_entries = Entry::new_(); test_entries.set_data(b"testdata".to_vec()); let msg = new_message_with_entries(1, 1, MessageType::MsgPropose, vec![test_entries.clone()]); nt.send(vec![msg.clone()]); - assert_eq!(nt.peers[&1].raft_log.committed, 2); - assert_eq!(nt.peers[&2].raft_log.committed, 1); - assert_eq!(nt.peers[&3].raft_log.committed, 1); + assert_eq!(nt.peers[&1].raft_log.committed, 3); + assert_eq!(nt.peers[&2].raft_log.committed, 2); + assert_eq!(nt.peers[&3].raft_log.committed, 2); // After bcast heartbeat, followers will be informed the actual commit index. for _ in 0..nt.peers[&1].get_randomized_election_timeout() { nt.peers.get_mut(&1).unwrap().tick(); } nt.send(vec![new_message(1, 1, MessageType::MsgHup, 0)]); - assert_eq!(nt.peers[&2].raft_log.committed, 2); - assert_eq!(nt.peers[&3].raft_log.committed, 2); + assert_eq!(nt.peers[&2].raft_log.committed, 3); + assert_eq!(nt.peers[&3].raft_log.committed, 3); // The feature should be able to be adjusted at run time. nt.peers.get_mut(&1).unwrap().skip_bcast_commit(false); nt.send(vec![msg.clone()]); - assert_eq!(nt.peers[&1].raft_log.committed, 3); - assert_eq!(nt.peers[&2].raft_log.committed, 3); - assert_eq!(nt.peers[&3].raft_log.committed, 3); + assert_eq!(nt.peers[&1].raft_log.committed, 4); + assert_eq!(nt.peers[&2].raft_log.committed, 4); + assert_eq!(nt.peers[&3].raft_log.committed, 4); nt.peers.get_mut(&1).unwrap().skip_bcast_commit(true); // Later proposal should commit former proposal. nt.send(vec![msg.clone()]); nt.send(vec![msg]); - assert_eq!(nt.peers[&1].raft_log.committed, 5); - assert_eq!(nt.peers[&2].raft_log.committed, 4); - assert_eq!(nt.peers[&3].raft_log.committed, 4); + assert_eq!(nt.peers[&1].raft_log.committed, 6); + assert_eq!(nt.peers[&2].raft_log.committed, 5); + assert_eq!(nt.peers[&3].raft_log.committed, 5); // When committing conf change, leader should always bcast commit. - let mut cc_entry = Entry::new(); + let mut cc = ConfChange::new_(); + cc.set_change_type(ConfChangeType::RemoveNode); + cc.set_node_id(3); + let mut data = Vec::with_capacity(ProstMsg::encoded_len(&cc)); + data.reserve_exact(ProstMsg::encoded_len(&cc)); + cc.encode(&mut data).unwrap(); + let mut cc_entry = Entry::new_(); cc_entry.set_entry_type(EntryType::EntryConfChange); + cc_entry.set_data(data); nt.send(vec![new_message_with_entries( 1, 1, @@ -517,7 +490,7 @@ fn test_skip_bcast_commit() { assert!(nt.peers[&2].should_bcast_commit()); assert!(nt.peers[&3].should_bcast_commit()); - assert_eq!(nt.peers[&1].raft_log.committed, 6); - assert_eq!(nt.peers[&2].raft_log.committed, 6); - assert_eq!(nt.peers[&3].raft_log.committed, 6); + assert_eq!(nt.peers[&1].raft_log.committed, 7); + assert_eq!(nt.peers[&2].raft_log.committed, 7); + assert_eq!(nt.peers[&3].raft_log.committed, 7); } diff --git a/tests/test_util/mod.rs b/tests/test_util/mod.rs index 88f6b8a3b..0ee6b17b3 100644 --- a/tests/test_util/mod.rs +++ b/tests/test_util/mod.rs @@ -26,7 +26,6 @@ // limitations under the License. use harness::*; -use protobuf::RepeatedField; use raft::eraftpb::*; use raft::storage::MemStorage; use raft::*; @@ -47,19 +46,14 @@ pub fn new_storage() -> MemStorage { MemStorage::new() } -pub fn new_test_config( - id: u64, - peers: Vec, - election_tick: usize, - heartbeat_tick: usize, -) -> Config { +pub fn new_test_config(id: u64, election_tick: usize, heartbeat_tick: usize) -> Config { Config { id, - peers, election_tick, heartbeat_tick, max_size_per_msg: NO_LIMIT, max_inflight_msgs: 256, + tag: format!("{}", id), ..Default::default() } } @@ -71,7 +65,14 @@ pub fn new_test_raft( heartbeat: usize, storage: MemStorage, ) -> Interface { - Interface::new(Raft::new(&new_test_config(id, peers, election, heartbeat), storage).unwrap()) + let config = new_test_config(id, election, heartbeat); + if storage.initial_state().unwrap().initialized() && peers.is_empty() { + panic!("new_test_raft with empty peers on initialized store"); + } + if !peers.is_empty() && !storage.initial_state().unwrap().initialized() { + storage.initialize_with_conf_state((peers, vec![])); + } + new_test_raft_with_config(&config, storage) } pub fn new_test_raft_with_prevote( @@ -82,9 +83,33 @@ pub fn new_test_raft_with_prevote( storage: MemStorage, pre_vote: bool, ) -> Interface { - let mut config = new_test_config(id, peers, election, heartbeat); + let mut config = new_test_config(id, election, heartbeat); config.pre_vote = pre_vote; - config.tag = format!("{}", id); + if storage.initial_state().unwrap().initialized() && peers.is_empty() { + panic!("new_test_raft with empty peers on initialized store"); + } + if !peers.is_empty() && !storage.initial_state().unwrap().initialized() { + storage.initialize_with_conf_state((peers, vec![])); + } + new_test_raft_with_config(&config, storage) +} + +pub fn new_test_raft_with_logs( + id: u64, + peers: Vec, + election: usize, + heartbeat: usize, + storage: MemStorage, + logs: &[Entry], +) -> Interface { + let config = new_test_config(id, election, heartbeat); + if storage.initial_state().unwrap().initialized() && peers.is_empty() { + panic!("new_test_raft with empty peers on initialized store"); + } + if !peers.is_empty() && !storage.initial_state().unwrap().initialized() { + storage.initialize_with_conf_state((peers, vec![])); + } + storage.wl().append(logs).unwrap(); new_test_raft_with_config(&config, storage) } @@ -93,7 +118,7 @@ pub fn new_test_raft_with_config(config: &Config, storage: MemStorage) -> Interf } pub fn hard_state(t: u64, c: u64, v: u64) -> HardState { - let mut hs = HardState::new(); + let mut hs = HardState::new_(); hs.set_term(t); hs.set_commit(c); hs.set_vote(v); @@ -103,12 +128,12 @@ pub fn hard_state(t: u64, c: u64, v: u64) -> HardState { pub const SOME_DATA: Option<&'static str> = Some("somedata"); pub fn new_message_with_entries(from: u64, to: u64, t: MessageType, ents: Vec) -> Message { - let mut m = Message::new(); + let mut m = Message::new_(); m.set_from(from); m.set_to(to); m.set_msg_type(t); if !ents.is_empty() { - m.set_entries(RepeatedField::from_vec(ents)); + m.set_entries(ents); } m } @@ -120,13 +145,13 @@ pub fn new_message(from: u64, to: u64, t: MessageType, n: usize) -> Message { for _ in 0..n { ents.push(new_entry(0, 0, SOME_DATA)); } - m.set_entries(RepeatedField::from_vec(ents)); + m.set_entries(ents); } m } pub fn new_entry(term: u64, index: u64, data: Option<&str>) -> Entry { - let mut e = Entry::new(); + let mut e = Entry::new_(); e.set_index(index); e.set_term(term); if let Some(d) = data { @@ -140,7 +165,7 @@ pub fn empty_entry(term: u64, index: u64) -> Entry { } pub fn new_snapshot(index: u64, term: u64, nodes: Vec) -> Snapshot { - let mut s = Snapshot::new(); + let mut s = Snapshot::new_(); s.mut_metadata().set_index(index); s.mut_metadata().set_term(term); s.mut_metadata().mut_conf_state().set_nodes(nodes); diff --git a/tests/tests.rs b/tests/tests.rs index 4fc218e8e..3664c2fae 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -16,16 +16,12 @@ #[macro_use] extern crate log; -extern crate protobuf; -extern crate raft; -extern crate rand; + #[cfg(feature = "failpoint")] #[macro_use] extern crate lazy_static; #[cfg(feature = "failpoint")] extern crate fail; -extern crate harness; -extern crate hashbrown; /// Get the count of macro's arguments. ///