solana/src/tpu.rs

150 lines
4.8 KiB
Rust
Raw Normal View History

//! The `tpu` module implements the Transaction Processing Unit, a
//! 5-stage transaction processing pipeline in software.
2018-03-29 11:20:54 -07:00
2018-05-09 13:56:34 -07:00
use accounting_stage::AccountingStage;
2018-04-28 00:31:20 -07:00
use crdt::{Crdt, ReplicatedData};
use entry_writer::EntryWriter;
2018-03-26 21:07:11 -07:00
use packet;
use result::Result;
use sig_verify_stage::SigVerifyStage;
2018-05-11 11:38:52 -07:00
use std::io::Write;
use std::net::UdpSocket;
2018-03-22 13:05:23 -07:00
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::channel;
2018-04-18 12:02:54 -07:00
use std::sync::{Arc, Mutex, RwLock};
use std::thread::{spawn, JoinHandle};
use streamer;
use thin_client_service::{RequestProcessor, ThinClientService};
2018-02-28 09:07:54 -08:00
pub struct Tpu {
accounting_stage: Arc<AccountingStage>,
request_processor: Arc<RequestProcessor>,
}
impl Tpu {
/// Create a new Tpu that wraps the given Accountant.
2018-05-09 15:14:40 -07:00
pub fn new(accounting_stage: AccountingStage) -> Self {
2018-05-11 22:07:44 -07:00
let request_processor = RequestProcessor::new(accounting_stage.accountant.clone());
Tpu {
accounting_stage: Arc::new(accounting_stage),
request_processor: Arc::new(request_processor),
}
}
2018-05-11 19:50:50 -07:00
pub fn write_service<W: Write + Send + 'static>(
2018-05-11 22:51:35 -07:00
accounting_stage: Arc<AccountingStage>,
request_processor: Arc<RequestProcessor>,
2018-04-28 00:31:20 -07:00
exit: Arc<AtomicBool>,
broadcast: streamer::BlobSender,
blob_recycler: packet::BlobRecycler,
2018-05-09 14:27:33 -07:00
writer: Mutex<W>,
2018-05-07 20:44:44 -07:00
) -> JoinHandle<()> {
spawn(move || loop {
2018-05-11 22:51:35 -07:00
let entry_writer = EntryWriter::new(&accounting_stage, &request_processor);
let _ = entry_writer.write_and_send_entries(&broadcast, &blob_recycler, &writer);
2018-05-07 20:44:44 -07:00
if exit.load(Ordering::Relaxed) {
2018-05-11 19:18:04 -07:00
info!("broadcat_service exiting");
2018-05-07 20:44:44 -07:00
break;
}
})
}
2018-05-11 22:51:35 -07:00
pub fn drain_service(
accounting_stage: Arc<AccountingStage>,
request_processor: Arc<RequestProcessor>,
exit: Arc<AtomicBool>,
) -> JoinHandle<()> {
spawn(move || {
2018-05-11 22:51:35 -07:00
let entry_writer = EntryWriter::new(&accounting_stage, &request_processor);
loop {
let _ = entry_writer.drain_entries();
if exit.load(Ordering::Relaxed) {
info!("drain_service exiting");
break;
}
2018-04-28 00:31:20 -07:00
}
})
2018-02-28 13:16:50 -08:00
}
/// Create a UDP microservice that forwards messages the given Tpu.
2018-04-17 19:26:19 -07:00
/// This service is the network leader
2018-03-29 11:20:54 -07:00
/// Set `exit` to shutdown its threads.
2018-04-28 00:31:20 -07:00
pub fn serve<W: Write + Send + 'static>(
2018-05-11 23:19:12 -07:00
&self,
2018-04-28 00:31:20 -07:00
me: ReplicatedData,
2018-05-11 15:41:35 -07:00
requests_socket: UdpSocket,
_events_socket: UdpSocket,
2018-04-28 00:31:20 -07:00
gossip: UdpSocket,
2018-03-22 13:05:23 -07:00
exit: Arc<AtomicBool>,
2018-04-28 00:31:20 -07:00
writer: W,
2018-03-23 20:49:28 -07:00
) -> Result<Vec<JoinHandle<()>>> {
2018-04-28 00:31:20 -07:00
let crdt = Arc::new(RwLock::new(Crdt::new(me)));
let t_gossip = Crdt::gossip(crdt.clone(), exit.clone());
let t_listen = Crdt::listen(crdt.clone(), gossip, exit.clone());
// make sure we are on the same interface
2018-05-11 15:41:35 -07:00
let mut local = requests_socket.local_addr()?;
local.set_port(0);
2018-02-28 09:07:54 -08:00
let packet_recycler = packet::PacketRecycler::default();
let (packet_sender, packet_receiver) = channel();
2018-05-11 15:41:35 -07:00
let t_receiver = streamer::receiver(
requests_socket,
exit.clone(),
packet_recycler.clone(),
packet_sender,
)?;
2018-03-26 21:07:11 -07:00
let sig_verify_stage = SigVerifyStage::new(exit.clone(), packet_receiver);
2018-03-26 21:07:11 -07:00
2018-05-11 19:50:50 -07:00
let blob_recycler = packet::BlobRecycler::default();
let thin_client_service = ThinClientService::new(
2018-05-11 23:19:12 -07:00
self.request_processor.clone(),
self.accounting_stage.clone(),
2018-05-11 19:50:50 -07:00
exit.clone(),
sig_verify_stage.output,
2018-05-11 19:50:50 -07:00
packet_recycler.clone(),
blob_recycler.clone(),
);
2018-04-28 00:31:20 -07:00
let (broadcast_sender, broadcast_receiver) = channel();
2018-05-11 19:50:50 -07:00
let t_write = Self::write_service(
2018-05-11 23:19:12 -07:00
self.accounting_stage.clone(),
self.request_processor.clone(),
2018-05-11 19:11:25 -07:00
exit.clone(),
broadcast_sender,
blob_recycler.clone(),
Mutex::new(writer),
);
2018-04-28 00:31:20 -07:00
let broadcast_socket = UdpSocket::bind(local)?;
let t_broadcast = streamer::broadcaster(
broadcast_socket,
exit.clone(),
crdt.clone(),
blob_recycler.clone(),
broadcast_receiver,
);
2018-05-11 19:50:50 -07:00
let respond_socket = UdpSocket::bind(local.clone())?;
2018-05-11 19:11:25 -07:00
let t_responder = streamer::responder(
respond_socket,
2018-04-28 00:31:20 -07:00
exit.clone(),
blob_recycler.clone(),
thin_client_service.output,
2018-04-28 00:31:20 -07:00
);
let mut threads = vec![
2018-04-28 00:31:20 -07:00
t_receiver,
t_responder,
thin_client_service.thread_hdl,
2018-05-11 19:50:50 -07:00
t_write,
2018-04-28 00:31:20 -07:00
t_gossip,
t_listen,
t_broadcast,
];
threads.extend(sig_verify_stage.thread_hdls.into_iter());
Ok(threads)
2018-03-26 21:07:11 -07:00
}
2018-04-11 13:05:29 -07:00
}