Skip to main content

lsm_db/
scan.rs

1//! Range iteration.
2//!
3//! [`Lsm::scan`](crate::Lsm::scan) merges the in-memory buffer and the on-disk
4//! run into one ascending key stream and returns a [`Scan`] over the entries
5//! that fall in the requested range.
6//!
7//! For the foundation release the merge is materialised under the read lock that
8//! `scan` takes: the returned [`Scan`] is a consistent point-in-time snapshot of
9//! the range, decoupled from later writes, and iterating it never blocks writers.
10//! Streaming the merge lazily is a later optimisation (see the roadmap); the
11//! snapshot semantics it provides are part of the contract and will not change.
12
13/// An ascending iterator over a key range, returned by
14/// [`Lsm::scan`](crate::Lsm::scan).
15///
16/// Yields `(key, value)` pairs in ascending key order. Deleted keys are already
17/// resolved away — a tombstone in the buffer hides the matching on-disk value,
18/// and neither appears in the stream.
19///
20/// # Examples
21///
22/// ```
23/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
24/// let dir = tempfile::tempdir()?;
25/// let db = lsm_db::Lsm::open(dir.path())?;
26/// db.put(b"a", b"1")?;
27/// db.put(b"b", b"2")?;
28/// db.put(b"c", b"3")?;
29///
30/// let pairs: Vec<_> = db.scan(b"a".to_vec()..b"c".to_vec())?.collect();
31/// assert_eq!(pairs, vec![(b"a".to_vec(), b"1".to_vec()), (b"b".to_vec(), b"2".to_vec())]);
32/// # Ok(())
33/// # }
34/// ```
35#[derive(Debug)]
36pub struct Scan {
37    inner: std::vec::IntoIter<(Vec<u8>, Vec<u8>)>,
38}
39
40impl Scan {
41    /// Wrap a materialised, already-sorted set of live entries.
42    pub(crate) fn new(entries: Vec<(Vec<u8>, Vec<u8>)>) -> Self {
43        Scan {
44            inner: entries.into_iter(),
45        }
46    }
47}
48
49impl Iterator for Scan {
50    type Item = (Vec<u8>, Vec<u8>);
51
52    #[inline]
53    fn next(&mut self) -> Option<Self::Item> {
54        self.inner.next()
55    }
56
57    #[inline]
58    fn size_hint(&self) -> (usize, Option<usize>) {
59        self.inner.size_hint()
60    }
61}
62
63impl ExactSizeIterator for Scan {
64    #[inline]
65    fn len(&self) -> usize {
66        self.inner.len()
67    }
68}
69
70impl DoubleEndedIterator for Scan {
71    #[inline]
72    fn next_back(&mut self) -> Option<Self::Item> {
73        self.inner.next_back()
74    }
75}