From d87dd4cabff6ef5ec0af866da96c2eb998427ff0 Mon Sep 17 00:00:00 2001 From: VS <v@s> Date: Fri, 27 May 2022 17:29:12 +0300 Subject: [PATCH] fix: represent node leader_id as Option --- src/discovery.rs | 19 +++++++++++++------ src/main.rs | 36 ++++++++++++++++++++---------------- src/traft/node.rs | 15 +++++++++++---- src/traft/storage.rs | 5 +++-- 4 files changed, 47 insertions(+), 28 deletions(-) diff --git a/src/discovery.rs b/src/discovery.rs index 54d945782a..d023f89b78 100644 --- a/src/discovery.rs +++ b/src/discovery.rs @@ -203,12 +203,19 @@ fn proc_discover<'a>( ) -> Result<Cow<'a, Response>, Box<dyn StdError>> { if let Ok(node) = traft::node::global() { let status = node.status(); - let leader = traft::Storage::peer_by_raft_id(status.leader_id)? - .ok_or("leader id is present, but it's address is unknown")?; - Ok(Cow::Owned(Response::Done(Role::new( - leader.peer_address, - status.am_leader(), - )))) + match status.leader_id { + Some(leader_id) => { + let leader = traft::Storage::peer_by_raft_id(leader_id)?.ok_or(format!( + "leader_id is present ({}) but it's address is unknown for node {}", + leader_id, status.id + ))?; + Ok(Cow::Owned(Response::Done(Role::new( + leader.peer_address, + status.am_leader(), + )))) + } + None => return Err(format!("leader_id is unknown for node {}", status.id).into()), + } } else { let discovery = discovery.as_mut().ok_or("discovery uninitialized")?; Ok(Cow::Borrowed(discovery.handle_request(request, request_to))) diff --git a/src/main.rs b/src/main.rs index 367e35d4ed..356cd60ba2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -561,7 +561,7 @@ fn postjoin(args: &args::Run) { ..tarantool::cfg().unwrap() }); - while node.status().leader_id == 0 { + while node.status().leader_id == None { node.wait_status(); } @@ -594,22 +594,26 @@ fn postjoin(args: &args::Run) { advertise_address: args.advertise_address(), }; - let leader_id = node.status().leader_id; - let leader = traft::Storage::peer_by_raft_id(leader_id).unwrap().unwrap(); - - use traft::node::raft_join; - let fn_name = stringify_cfunc!(raft_join); - let now = Instant::now(); - match tarantool::net_box_call(&leader.peer_address, fn_name, &req, timeout) { - Err(e) => { - tlog!(Error, "failed to promote myself: {e}"); - fiber::sleep(timeout.saturating_sub(now.elapsed())); - continue; - } - Ok(traft::JoinResponse { .. }) => { - break; + match node.status().leader_id { + None => (), + Some(leader_id) => { + let leader = traft::Storage::peer_by_raft_id(leader_id).unwrap().unwrap(); + + use traft::node::raft_join; + let fn_name = stringify_cfunc!(raft_join); + let now = Instant::now(); + match tarantool::net_box_call(&leader.peer_address, fn_name, &req, timeout) { + Err(e) => { + tlog!(Error, "failed to promote myself: {e}"); + fiber::sleep(timeout.saturating_sub(now.elapsed())); + continue; + } + Ok(traft::JoinResponse { .. }) => { + break; + } + }; } - }; + } } node.mark_as_ready(); diff --git a/src/traft/node.rs b/src/traft/node.rs index 55a8d2ba1a..0465b51716 100644 --- a/src/traft/node.rs +++ b/src/traft/node.rs @@ -8,6 +8,7 @@ use ::raft::prelude as raft; use ::raft::Error as RaftError; use ::raft::StateRole as RaftStateRole; +use ::raft::INVALID_ID; use ::tarantool::error::TransactionError; use ::tarantool::fiber; use ::tarantool::proc; @@ -54,14 +55,17 @@ pub struct Status { /// `raft_id` of the current instance pub id: u64, /// `raft_id` of the leader instance - pub leader_id: u64, + pub leader_id: Option<u64>, pub raft_state: String, pub is_ready: bool, } impl Status { pub fn am_leader(&self) -> bool { - self.id == self.leader_id + match self.leader_id { + Some(id) => self.id == id, + None => false, + } } } @@ -118,7 +122,7 @@ impl Node { let raw_node = RawNode::new(cfg, Storage, &tlog::root())?; let status = Rc::new(RefCell::new(Status { id: cfg.id, - leader_id: 0, + leader_id: None, raft_state: "Follower".into(), is_ready: false, })); @@ -567,7 +571,10 @@ fn raft_main_loop( if let Some(ss) = ready.ss() { let mut status = status.borrow_mut(); - status.leader_id = ss.leader_id; + status.leader_id = match ss.leader_id { + INVALID_ID => None, + id => Some(id), + }; status.raft_state = format!("{:?}", ss.raft_state); status_cond.broadcast(); } diff --git a/src/traft/storage.rs b/src/traft/storage.rs index d854310d70..b935ec986c 100644 --- a/src/traft/storage.rs +++ b/src/traft/storage.rs @@ -3,6 +3,7 @@ use std::convert::TryFrom; use ::raft::prelude as raft; use ::raft::Error as RaftError; use ::raft::StorageError; +use ::raft::INVALID_ID; use ::tarantool::index::IteratorType; use ::tarantool::space::Space; use ::tarantool::tuple::Tuple; @@ -130,8 +131,8 @@ impl Storage { } pub fn peer_by_raft_id(raft_id: u64) -> Result<Option<traft::Peer>, StorageError> { - if raft_id == 0 { - return Ok(None); + if raft_id == INVALID_ID { + unreachable!("peer_by_raft_id called with invalid id ({})", INVALID_ID); } let tuple = Storage::space(RAFT_GROUP)? -- GitLab