solana/src/ledger_write_stage.rs

95 lines
3.0 KiB
Rust

//! The `ledger_write_stage` module implements the ledger write stage. It
//! writes entries to the given writer, which is typically a file
use counter::Counter;
use entry::{EntryReceiver, EntrySender};
use ledger::LedgerWriter;
use log::Level;
use result::{Error, Result};
use service::Service;
use solana_sdk::timing::duration_as_ms;
use std::sync::atomic::AtomicUsize;
use std::sync::mpsc::{channel, RecvTimeoutError};
use std::thread::{self, Builder, JoinHandle};
use std::time::{Duration, Instant};
pub struct LedgerWriteStage {
write_thread: JoinHandle<()>,
}
impl LedgerWriteStage {
pub fn write(
ledger_writer: Option<&mut LedgerWriter>,
entry_receiver: &EntryReceiver,
entry_sender: &EntrySender,
) -> Result<()> {
let mut ventries = Vec::new();
let mut received_entries = entry_receiver.recv_timeout(Duration::new(1, 0))?;
let mut num_new_entries = 0;
let now = Instant::now();
loop {
num_new_entries += received_entries.len();
ventries.push(received_entries);
if let Ok(n) = entry_receiver.try_recv() {
received_entries = n;
} else {
break;
}
}
if let Some(ledger_writer) = ledger_writer {
ledger_writer.write_entries(ventries.iter().flatten())?;
}
inc_new_counter_info!("ledger_writer_stage-entries_received", num_new_entries);
for entries in ventries {
entry_sender.send(entries)?;
}
inc_new_counter_info!(
"ledger_writer_stage-time_ms",
duration_as_ms(&now.elapsed()) as usize
);
Ok(())
}
#[allow(clippy::new_ret_no_self)]
pub fn new(ledger_path: Option<&str>, entry_receiver: EntryReceiver) -> (Self, EntryReceiver) {
let mut ledger_writer = ledger_path.map(|p| LedgerWriter::open(p, false).unwrap());
let (entry_sender, entry_forwarder) = channel();
let write_thread = Builder::new()
.name("solana-ledger-writer".to_string())
.spawn(move || loop {
if let Err(e) = Self::write(ledger_writer.as_mut(), &entry_receiver, &entry_sender)
{
match e {
Error::RecvTimeoutError(RecvTimeoutError::Disconnected) => {
break;
}
Error::RecvTimeoutError(RecvTimeoutError::Timeout) => (),
_ => {
inc_new_counter_info!(
"ledger_writer_stage-write_and_send_entries-error",
1
);
error!("{:?}", e);
}
}
};
})
.unwrap();
(Self { write_thread }, entry_forwarder)
}
}
impl Service for LedgerWriteStage {
type JoinReturnType = ();
fn join(self) -> thread::Result<()> {
self.write_thread.join()
}
}