2018-03-19 10:12:20 -07:00
|
|
|
//! Comms task structure. A comms task communicates with a remote node through a
|
|
|
|
//! socket. Local communication with coordinating threads is made via
|
2018-04-04 04:49:11 -07:00
|
|
|
//! `crossbeam_channel::unbounded()`.
|
2018-03-19 10:12:20 -07:00
|
|
|
use std::fmt::Debug;
|
2018-03-20 09:32:19 -07:00
|
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
use crossbeam;
|
2018-04-02 13:26:40 -07:00
|
|
|
use crossbeam_channel as channel;
|
2018-03-20 09:32:19 -07:00
|
|
|
|
2018-03-19 10:12:20 -07:00
|
|
|
use proto::Message;
|
|
|
|
use task;
|
|
|
|
|
|
|
|
/// A communication task connects a remote node to the thread that manages the
|
|
|
|
/// consensus algorithm.
|
2018-04-03 04:53:59 -07:00
|
|
|
pub struct CommsTask<'a, 'b, 'c, T: 'a + 'c + Send + Sync +
|
2018-04-02 13:26:40 -07:00
|
|
|
From<Vec<u8>> + Into<Vec<u8>>>
|
2018-03-19 10:12:20 -07:00
|
|
|
where Vec<u8>: From<T>
|
|
|
|
{
|
|
|
|
/// The transmit side of the multiple producer channel from comms threads.
|
2018-04-03 15:08:26 -07:00
|
|
|
tx: &'a channel::Sender<(usize, Message<T>)>,
|
2018-03-19 10:12:20 -07:00
|
|
|
/// The receive side of the multiple consumer channel to comms threads.
|
2018-04-02 13:26:40 -07:00
|
|
|
rx: &'a channel::Receiver<Message<T>>,
|
2018-04-03 04:53:59 -07:00
|
|
|
/// The receive side of the private channel to the comms thread.
|
|
|
|
rx_priv: &'c channel::Receiver<Message<T>>,
|
2018-03-19 10:12:20 -07:00
|
|
|
/// The socket IO task.
|
2018-04-03 04:53:59 -07:00
|
|
|
task: task::Task<'b>,
|
2018-04-03 15:08:26 -07:00
|
|
|
/// The index of this comms task for identification against its remote node.
|
|
|
|
pub node_index: usize
|
2018-03-19 10:12:20 -07:00
|
|
|
}
|
|
|
|
|
2018-04-03 04:53:59 -07:00
|
|
|
impl<'a, 'b, 'c, T: Debug + Send + Sync + From<Vec<u8>> + Into<Vec<u8>>>
|
|
|
|
CommsTask<'a, 'b, 'c, T>
|
2018-03-19 10:12:20 -07:00
|
|
|
where Vec<u8>: From<T>
|
|
|
|
{
|
2018-04-03 15:08:26 -07:00
|
|
|
pub fn new(tx: &'a channel::Sender<(usize, Message<T>)>,
|
2018-04-02 13:26:40 -07:00
|
|
|
rx: &'a channel::Receiver<Message<T>>,
|
2018-04-03 04:53:59 -07:00
|
|
|
rx_priv: &'c channel::Receiver<Message<T>>,
|
2018-04-03 15:08:26 -07:00
|
|
|
stream: &'b ::std::net::TcpStream,
|
|
|
|
node_index: usize) ->
|
|
|
|
Self
|
|
|
|
{
|
2018-04-04 04:18:57 -07:00
|
|
|
debug!("Creating comms task #{} for {:?}", node_index,
|
|
|
|
stream.peer_addr().unwrap());
|
|
|
|
|
2018-03-19 10:12:20 -07:00
|
|
|
CommsTask {
|
|
|
|
tx: tx,
|
|
|
|
rx: rx,
|
2018-04-03 04:53:59 -07:00
|
|
|
rx_priv: rx_priv,
|
2018-04-03 15:08:26 -07:00
|
|
|
task: task::Task::new(stream),
|
|
|
|
node_index: node_index
|
2018-03-19 10:12:20 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The main socket IO loop and an asynchronous thread responding to manager
|
|
|
|
/// thread requests.
|
|
|
|
pub fn run(&mut self) {
|
2018-03-20 09:32:19 -07:00
|
|
|
// Borrow parts of `self` before entering the thread binding scope.
|
2018-04-02 13:26:40 -07:00
|
|
|
let tx = Arc::new(self.tx);
|
|
|
|
let rx = Arc::new(self.rx);
|
2018-04-03 04:53:59 -07:00
|
|
|
let rx_priv = Arc::new(self.rx_priv);
|
2018-03-20 09:32:19 -07:00
|
|
|
let task = Arc::new(Mutex::new(&mut self.task));
|
2018-04-03 15:08:26 -07:00
|
|
|
let node_index = self.node_index;
|
2018-03-20 09:32:19 -07:00
|
|
|
|
|
|
|
crossbeam::scope(|scope| {
|
|
|
|
// Make a further copy of `task` for the thread stack.
|
|
|
|
let task1 = task.clone();
|
2018-03-19 10:12:20 -07:00
|
|
|
|
2018-03-20 09:32:19 -07:00
|
|
|
// Local comms receive loop thread.
|
|
|
|
scope.spawn(move || {
|
2018-04-04 04:49:11 -07:00
|
|
|
select_loop! {
|
2018-04-03 04:53:59 -07:00
|
|
|
// Receive a multicast message from the manager thread.
|
2018-04-04 04:49:11 -07:00
|
|
|
recv(rx, message) => {
|
2018-04-04 04:18:57 -07:00
|
|
|
debug!("Node {} <- {:?}", node_index, message);
|
2018-04-03 04:53:59 -07:00
|
|
|
// Forward the message to the remote node.
|
|
|
|
task1.lock().unwrap().send_message(message).unwrap();
|
2018-04-04 04:49:11 -07:00
|
|
|
},
|
2018-04-03 04:53:59 -07:00
|
|
|
// Receive a private message from the manager thread.
|
2018-04-04 04:49:11 -07:00
|
|
|
recv(rx_priv, message) => {
|
2018-04-04 04:18:57 -07:00
|
|
|
debug!("Node {} <- {:?}", node_index, message);
|
2018-04-03 04:53:59 -07:00
|
|
|
// Forward the message to the remote node.
|
|
|
|
task1.lock().unwrap().send_message(message).unwrap();
|
|
|
|
}
|
2018-04-04 04:49:11 -07:00
|
|
|
}
|
2018-03-20 09:32:19 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
// Remote comms receive loop.
|
|
|
|
loop {
|
|
|
|
match task.lock().unwrap().receive_message() {
|
2018-04-04 04:18:57 -07:00
|
|
|
Ok(message) => {
|
|
|
|
debug!("Node {} -> {:?}", node_index, message);
|
|
|
|
tx.send((node_index, message)).unwrap()
|
|
|
|
},
|
2018-03-20 09:32:19 -07:00
|
|
|
Err(task::Error::ProtobufError(e)) =>
|
|
|
|
warn!("Protobuf error {}", e),
|
|
|
|
Err(e) => {
|
|
|
|
warn!("Critical error {:?}", e);
|
|
|
|
break;
|
|
|
|
}
|
2018-03-19 10:12:20 -07:00
|
|
|
}
|
|
|
|
}
|
2018-03-20 09:32:19 -07:00
|
|
|
});
|
2018-03-19 10:12:20 -07:00
|
|
|
}
|
|
|
|
}
|