lsm_tree/segment/
scanner.rs

1use super::value_block::ValueBlock;
2use crate::InternalValue;
3use std::{collections::VecDeque, fs::File, io::BufReader, path::Path};
4
5/// Segment reader that is optimized for consuming an entire segment
6pub struct Scanner {
7    reader: BufReader<File>,
8
9    block_count: usize,
10    read_count: usize,
11
12    buffer: VecDeque<InternalValue>,
13}
14
15impl Scanner {
16    pub fn new(path: &Path, block_count: usize) -> crate::Result<Self> {
17        // TODO: a larger buffer size may be better for HDD
18        let reader = BufReader::with_capacity(8 * 4_096, File::open(path)?);
19
20        Ok(Self {
21            reader,
22            block_count,
23            read_count: 0,
24            buffer: VecDeque::new(),
25        })
26    }
27}
28
29impl Iterator for Scanner {
30    type Item = crate::Result<InternalValue>;
31
32    fn next(&mut self) -> Option<Self::Item> {
33        loop {
34            if let Some(item) = self.buffer.pop_front() {
35                return Some(Ok(item));
36            }
37
38            if self.read_count >= self.block_count {
39                return None;
40            }
41
42            let block = ValueBlock::from_reader(&mut self.reader);
43            let block = fail_iter!(block);
44
45            // TODO: 1.80? IntoIter impl for Box<[T]>
46            self.buffer.extend(block.items.into_vec());
47
48            self.read_count += 1;
49        }
50    }
51}
52
53pub type CompactionReader<'a> = Box<dyn Iterator<Item = crate::Result<InternalValue>> + 'a>;