pallas/pallas-hardano/src/storage/immutable/chunk.rs

121 lines
3.2 KiB
Rust

use std::{
fs::File,
io::{BufReader, Read, Seek},
path::Path,
};
use immutable::secondary;
use tracing::trace;
use crate::storage::immutable;
pub type SecondaryIndex = super::secondary::Reader;
pub type SecondaryEntry = super::secondary::Entry;
pub struct Reader {
inner: BufReader<File>,
index: SecondaryIndex,
current: Option<Result<SecondaryEntry, std::io::Error>>,
next: Option<Result<SecondaryEntry, std::io::Error>>,
}
impl Reader {
fn open(mut index: SecondaryIndex, chunks: File) -> Result<Self, std::io::Error> {
let inner = BufReader::new(chunks);
let current = index.next();
let next = index.next();
Ok(Self {
inner,
index,
current,
next,
})
}
fn read_middle_block(
file: &mut BufReader<File>,
next_offset: u64,
) -> Result<Vec<u8>, std::io::Error> {
let start = file.stream_position()?;
let delta = next_offset - start;
trace!(start, delta, "reading chunk middle block");
let mut buf = vec![0u8; delta as usize];
file.read_exact(&mut buf)?;
Ok(buf)
}
fn read_last_block(file: &mut BufReader<File>) -> Result<Vec<u8>, std::io::Error> {
let start = file.stream_position()?;
trace!(start, "reading chunk last block");
let mut buf = vec![];
file.read_to_end(&mut buf)?;
Ok(buf)
}
}
impl Iterator for Reader {
type Item = Result<Vec<u8>, std::io::Error>;
fn next(&mut self) -> Option<Self::Item> {
match (self.current.take(), self.next.take()) {
(None, _) => None,
(_, Some(Err(next))) => {
self.current = None;
self.next = None;
Some(Err(next))
}
(Some(_), Some(Ok(next))) => {
let block = Self::read_middle_block(&mut self.inner, next.block_offset);
self.current = Some(Ok(next));
self.next = self.index.next();
Some(block)
}
(Some(_), None) => {
let block = Self::read_last_block(&mut self.inner);
self.current = None;
self.next = None;
Some(block)
}
}
}
}
pub fn read_blocks(dir: &Path, name: &str) -> Result<Reader, std::io::Error> {
let primary = dir.join(name).with_extension("primary");
let primary = std::fs::File::open(primary)?;
let primary = immutable::primary::Reader::open(primary)?;
let secondary = dir.join(name).with_extension("secondary");
let secondary = std::fs::File::open(secondary)?;
let secondary = secondary::Reader::open(primary, secondary)?;
let chunk = dir.join(name).with_extension("chunk");
let chunk = std::fs::File::open(chunk)?;
Reader::open(secondary, chunk)
}
#[cfg(test)]
mod tests {
use std::path::Path;
#[test]
fn it_can_decode_all_blocks() {
let chunk = super::read_blocks(Path::new("../test_data"), "01285").unwrap();
for block in chunk {
let block = block.unwrap();
pallas_traverse::MultiEraBlock::decode(&block).unwrap();
}
}
}