Files
solana/src/write_stage.rs

101 lines
3.4 KiB
Rust
Raw Normal View History

2018-06-06 11:24:24 -06:00
//! The `write_stage` module implements the TPU's write stage. It
//! writes entries to the given writer, which is typically a file or
//! stdout, and then sends the Entry to its output channel.
use bank::Bank;
2018-07-17 15:54:58 -07:00
use counter::Counter;
use crdt::Crdt;
use entry::Entry;
use entry_writer::EntryWriter;
2018-07-01 09:15:19 -07:00
use ledger::Block;
2018-06-27 12:33:56 -06:00
use packet::BlobRecycler;
2018-07-05 15:29:19 -06:00
use result::{Error, Result};
use service::Service;
2018-07-01 09:15:19 -07:00
use std::collections::VecDeque;
2018-07-01 10:08:37 -07:00
use std::io::Write;
2018-07-17 15:54:58 -07:00
use std::sync::atomic::AtomicUsize;
2018-07-05 15:29:19 -06:00
use std::sync::mpsc::{channel, Receiver, RecvTimeoutError};
use std::sync::{Arc, RwLock};
use std::thread::{self, Builder, JoinHandle};
2018-07-01 09:15:19 -07:00
use std::time::Duration;
use streamer::{BlobReceiver, BlobSender};
use voting::entries_to_votes;
pub struct WriteStage {
thread_hdl: JoinHandle<()>,
}
impl WriteStage {
2018-07-05 13:02:25 -06:00
/// Process any Entry items that have been published by the RecordStage.
2018-07-01 09:15:19 -07:00
/// continuosly broadcast blobs of entries out
pub fn write_and_send_entries<W: Write>(
crdt: &Arc<RwLock<Crdt>>,
2018-07-01 14:31:13 -06:00
entry_writer: &mut EntryWriter<W>,
2018-07-01 09:15:19 -07:00
blob_sender: &BlobSender,
blob_recycler: &BlobRecycler,
entry_receiver: &Receiver<Vec<Entry>>,
) -> Result<()> {
let entries = entry_receiver.recv_timeout(Duration::new(1, 0))?;
let votes = entries_to_votes(&entries);
2018-07-11 14:40:46 -06:00
crdt.write().unwrap().insert_votes(&votes);
2018-07-01 14:25:21 -06:00
entry_writer.write_and_register_entries(&entries)?;
2018-07-01 09:15:19 -07:00
trace!("New blobs? {}", entries.len());
let mut blobs = VecDeque::new();
entries.to_blobs(blob_recycler, &mut blobs);
if !blobs.is_empty() {
2018-07-17 15:54:58 -07:00
inc_new_counter!("write_stage-broadcast_vote-count", votes.len());
inc_new_counter!("write_stage-broadcast_blobs-count", blobs.len());
2018-07-01 09:15:19 -07:00
trace!("broadcasting {}", blobs.len());
blob_sender.send(blobs)?;
}
Ok(())
}
2018-07-05 13:02:25 -06:00
/// Create a new WriteStage for writing and broadcasting entries.
pub fn new<W: Write + Send + 'static>(
bank: Arc<Bank>,
crdt: Arc<RwLock<Crdt>>,
2018-06-27 12:33:56 -06:00
blob_recycler: BlobRecycler,
2018-07-01 10:55:16 -07:00
writer: W,
entry_receiver: Receiver<Vec<Entry>>,
) -> (Self, BlobReceiver) {
let (blob_sender, blob_receiver) = channel();
2018-05-30 13:38:15 -07:00
let thread_hdl = Builder::new()
.name("solana-writer".to_string())
2018-07-01 10:55:16 -07:00
.spawn(move || {
2018-07-01 14:31:13 -06:00
let mut entry_writer = EntryWriter::new(&bank, writer);
2018-07-01 10:55:16 -07:00
loop {
2018-07-05 15:29:19 -06:00
if let Err(e) = Self::write_and_send_entries(
&crdt,
2018-07-01 14:31:13 -06:00
&mut entry_writer,
2018-07-01 10:55:16 -07:00
&blob_sender,
&blob_recycler,
&entry_receiver,
2018-07-05 15:29:19 -06:00
) {
match e {
Error::RecvTimeoutError(RecvTimeoutError::Disconnected) => break,
2018-07-05 15:41:53 -06:00
Error::RecvTimeoutError(RecvTimeoutError::Timeout) => (),
2018-07-17 15:55:56 -07:00
_ => {
inc_new_counter!("write_stage-error", 1);
error!("{:?}", e);
}
2018-07-05 15:29:19 -06:00
}
};
2018-05-30 13:38:15 -07:00
}
})
.unwrap();
(WriteStage { thread_hdl }, blob_receiver)
}
}
impl Service for WriteStage {
fn thread_hdls(self) -> Vec<JoinHandle<()>> {
vec![self.thread_hdl]
}
fn join(self) -> thread::Result<()> {
self.thread_hdl.join()
}
}