From 27098d15f6928396311930d61af84489e5a2d99f Mon Sep 17 00:00:00 2001 From: Georgy Moshkin <gmoshkin@picodata.io> Date: Wed, 21 Sep 2022 18:21:46 +0300 Subject: [PATCH] refactor(storage): peer or peer_field by generic impl PeerId --- src/traft/error.rs | 5 +++- src/traft/storage.rs | 54 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/src/traft/error.rs b/src/traft/error.rs index 4dbf27263d..7459e495b6 100644 --- a/src/traft/error.rs +++ b/src/traft/error.rs @@ -1,3 +1,4 @@ +use crate::traft::InstanceId; use crate::traft::RaftId; use ::tarantool::tlua::LuaError; use raft::StorageError; @@ -28,7 +29,9 @@ pub enum Error { Tarantool(#[from] ::tarantool::error::Error), #[error("peer with id {0} not found")] NoPeerWithRaftId(RaftId), - #[error("other error")] + #[error(r#"peer with id "{0}" not found"#)] + NoPeerWithInstanceId(InstanceId), + #[error("other error: {0}")] Other(Box<dyn std::error::Error>), } diff --git a/src/traft/storage.rs b/src/traft/storage.rs index cfb2dd54c0..6c3b46b455 100644 --- a/src/traft/storage.rs +++ b/src/traft/storage.rs @@ -297,19 +297,25 @@ impl Peers { /// Find a peer by `raft_id` and return a single field specified by `F` /// (see `PeerFieldDef` & `peer_field` module). - #[inline] - pub fn field_by_raft_id<F>(&self, raft_id: RaftId) -> Result<F::Type, TraftError> + #[inline(always)] + #[allow(dead_code)] + pub fn peer<F>(&self, id: &impl PeerId) -> Result<F::Type, TraftError> where F: PeerFieldDef, { - if raft_id == INVALID_ID { - unreachable!("peer_by_raft_id called with invalid id ({})", INVALID_ID); - } + let res = id.find_in(self)?.decode().expect("failed to decode peer"); + Ok(res) + } - let res = self - .index_raft_id - .get(&[raft_id])? - .ok_or(TraftError::NoPeerWithRaftId(raft_id))? + /// Find a peer by `id` (see `PeerId`) and return a single field + /// specified by `F` (see `PeerFieldDef` & `peer_field` module). + #[inline(always)] + pub fn peer_field<F>(&self, id: &impl PeerId) -> Result<F::Type, TraftError> + where + F: PeerFieldDef, + { + let res = id + .find_in(self)? .get(F::NAME) .expect("peer fields are not nullable"); Ok(res) @@ -477,6 +483,36 @@ pub trait PeerFieldDef { const TYPE: tarantool::space::FieldType; } +//////////////////////////////////////////////////////////////////////////////// +// PeerId +//////////////////////////////////////////////////////////////////////////////// + +/// Types implementing this trait can be used to identify a `Peer` when +/// accessing storage. +pub trait PeerId: serde::Serialize { + fn find_in(&self, peers: &Peers) -> Result<Tuple, TraftError>; +} + +impl PeerId for RaftId { + #[inline(always)] + fn find_in(&self, peers: &Peers) -> Result<Tuple, TraftError> { + peers + .index_raft_id + .get(&[self])? + .ok_or(TraftError::NoPeerWithRaftId(*self)) + } +} + +impl PeerId for traft::InstanceId { + #[inline(always)] + fn find_in(&self, peers: &Peers) -> Result<Tuple, TraftError> { + peers + .index_instance_id + .get(&[self])? + .ok_or_else(|| TraftError::NoPeerWithInstanceId(self.clone())) + } +} + //////////////////////////////////////////////////////////////////////////////// // tests //////////////////////////////////////////////////////////////////////////////// -- GitLab