Skip to main content

prolly/prolly/
range.rs

1//! Range iteration operations for Prolly trees
2//!
3//! This module handles range queries and iteration over key-value pairs
4//! within specified bounds. It provides efficient traversal of the tree
5//! in lexicographic order with support for start and end bounds.
6//!
7//! # Overview
8//!
9//! Range iteration allows traversing key-value pairs in sorted order within
10//! a specified key range. The iterator efficiently navigates the tree structure,
11//! handling node boundaries transparently.
12//!
13//! # Iteration Behavior
14//!
15//! ## Start Bound (Inclusive)
16//!
17//! The iterator begins at the first key greater than or equal to the start bound.
18//! If the start key exists, iteration begins there. If not, iteration begins at
19//! the next key in lexicographic order.
20//!
21//! Use an empty slice (`&[]`) to start from the beginning of the tree.
22//!
23//! ## End Bound (Exclusive)
24//!
25//! The iterator stops before reaching the end bound. Keys equal to or greater
26//! than the end bound are not yielded.
27//!
28//! Use `None` to iterate to the end of the tree.
29//!
30//! # Implementation Details
31//!
32//! The iterator maintains a stack of (node, index) pairs representing the
33//! current position in the tree. This allows efficient traversal across
34//! node boundaries without restarting from the root.
35//!
36//! ## Traversal Algorithm
37//!
38//! 1. **Initial positioning**: Find the path to the start key
39//! 2. **Leaf iteration**: Yield entries from the current leaf
40//! 3. **Node advancement**: When a leaf is exhausted, backtrack to find the next leaf
41//! 4. **Bound checking**: Stop when the end bound is reached
42//!
43//! # Example
44//!
45//! ```rust
46//! use prolly::{Prolly, MemStore, Config};
47//!
48//! let store = MemStore::new();
49//! let prolly = Prolly::new(store, Config::default());
50//! let mut tree = prolly.create();
51//!
52//! // Insert some data
53//! tree = prolly.put(&tree, b"a".to_vec(), b"1".to_vec()).unwrap();
54//! tree = prolly.put(&tree, b"b".to_vec(), b"2".to_vec()).unwrap();
55//! tree = prolly.put(&tree, b"c".to_vec(), b"3".to_vec()).unwrap();
56//! tree = prolly.put(&tree, b"d".to_vec(), b"4".to_vec()).unwrap();
57//!
58//! // Iterate over all keys
59//! for result in prolly.range(&tree, &[], None).unwrap() {
60//!     let (key, val) = result.unwrap();
61//!     println!("{:?} -> {:?}", key, val);
62//! }
63//!
64//! // Iterate over range [b, d) - yields "b" and "c"
65//! for result in prolly.range(&tree, b"b", Some(b"d")).unwrap() {
66//!     let (key, val) = result.unwrap();
67//!     println!("{:?} -> {:?}", key, val);
68//! }
69//! ```
70//!
71//! # Performance
72//!
73//! - **Initial seek**: O(log n) to find the starting position
74//! - **Per-entry**: O(1) amortized for sequential access within a leaf
75//! - **Node transitions**: O(log n) worst case, but typically O(1) amortized
76//!
77//! The iterator is lazy and only loads nodes as needed, making it memory-efficient
78//! for large trees.
79
80use super::error::Error;
81use super::node::ReadNode;
82use super::read::EntryRef;
83use super::store::Store;
84use super::tree::Tree;
85
86use super::Prolly;
87use super::{store::AsyncStore, AsyncProlly};
88use futures_util::stream::{self, Stream};
89use serde::{Deserialize, Serialize};
90use std::sync::Arc;
91
92type RangeItem = Result<(Vec<u8>, Vec<u8>), Error>;
93type LeafEntry = (Vec<u8>, Vec<u8>);
94pub(crate) const RANGE_CHILD_PREFETCH_PARALLELISM: usize = 16;
95
96/// Stable cursor token for resumable range scans.
97///
98/// The token is independent of in-memory traversal state: it records the last
99/// emitted key, and the next scan resumes strictly after that key. This makes it
100/// suitable for checkpointing background indexing or sync jobs for an immutable
101/// tree snapshot.
102#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
103pub struct RangeCursor {
104    after_key: Option<Vec<u8>>,
105}
106
107impl RangeCursor {
108    /// Start scanning from the beginning of the requested range.
109    pub fn start() -> Self {
110        Self { after_key: None }
111    }
112
113    /// Resume scanning strictly after `key`.
114    pub fn after_key(key: impl Into<Vec<u8>>) -> Self {
115        Self {
116            after_key: Some(key.into()),
117        }
118    }
119
120    /// Return the key this cursor resumes after, if any.
121    pub fn after(&self) -> Option<&[u8]> {
122        self.after_key.as_deref()
123    }
124
125    /// Whether this cursor represents the beginning of a range.
126    pub fn is_start(&self) -> bool {
127        self.after_key.is_none()
128    }
129}
130
131/// A bounded page of range-scan results.
132///
133/// `next_cursor` is `Some` when another call should resume after the last entry
134/// in this page. It is `None` when the scan reached the end bound or the end of
135/// the tree.
136#[derive(Clone, Debug, Default, PartialEq, Eq)]
137pub struct RangePage {
138    pub entries: Vec<(Vec<u8>, Vec<u8>)>,
139    pub next_cursor: Option<RangeCursor>,
140}
141
142/// Stable cursor token for resumable reverse scans.
143///
144/// The token records the next exclusive upper bound. A start cursor scans from
145/// the end of the requested range; a resumed cursor scans keys strictly before
146/// `before_key`.
147#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
148pub struct ReverseCursor {
149    before_key: Option<Vec<u8>>,
150}
151
152impl ReverseCursor {
153    /// Start scanning from the end of the requested range.
154    pub fn end() -> Self {
155        Self { before_key: None }
156    }
157
158    /// Resume scanning strictly before `key`.
159    pub fn before_key(key: impl Into<Vec<u8>>) -> Self {
160        Self {
161            before_key: Some(key.into()),
162        }
163    }
164
165    /// Return the key this cursor resumes before, if any.
166    pub fn before(&self) -> Option<&[u8]> {
167        self.before_key.as_deref()
168    }
169
170    /// Whether this cursor represents the end of a range.
171    pub fn is_end(&self) -> bool {
172        self.before_key.is_none()
173    }
174}
175
176/// A bounded page of reverse-scan results.
177///
178/// Entries are returned in descending key order. `next_cursor` is `Some` when
179/// another call should resume before the last entry in this page.
180#[derive(Clone, Debug, Default, PartialEq, Eq)]
181pub struct ReversePage {
182    pub entries: Vec<(Vec<u8>, Vec<u8>)>,
183    pub next_cursor: Option<ReverseCursor>,
184}
185
186/// Bounded result for a stateless cursor seek.
187///
188/// `position_key`/`position_value` report where the internal cursor lands for
189/// the requested seek key. This is the exact key when `found` is true; otherwise
190/// it is the closest leaf entry chosen by cursor navigation. `entries` are the
191/// forward window starting at the first key greater than or equal to the seek
192/// key, and `next_cursor` resumes after the last emitted entry.
193#[derive(Clone, Debug, Default, PartialEq, Eq)]
194pub struct CursorWindow {
195    pub position_key: Option<Vec<u8>>,
196    pub position_value: Option<Vec<u8>>,
197    pub found: bool,
198    pub entries: Vec<(Vec<u8>, Vec<u8>)>,
199    pub next_cursor: Option<RangeCursor>,
200}
201
202/// Backward-compatible name for async range pages.
203pub type AsyncRangePage = RangePage;
204
205/// Backward-compatible name for async reverse range pages.
206pub type AsyncReversePage = ReversePage;
207
208/// Create a range iterator over key-value pairs.
209///
210/// Returns an iterator that yields `(key, value)` pairs in lexicographic order,
211/// starting from `start` (inclusive) up to `end` (exclusive).
212///
213/// # Arguments
214/// * `prolly` - Reference to the Prolly tree manager
215/// * `tree` - The tree to iterate over
216/// * `start` - The starting key (inclusive). Use `&[]` to start from the beginning.
217/// * `end` - Optional ending key (exclusive). Use `None` to iterate to the end.
218///
219/// # Returns
220/// * `Ok(RangeIter)` - An iterator over the range
221/// * `Err` on storage or deserialization errors during path finding
222pub fn create_range_iter<'a, S: Store>(
223    prolly: &'a Prolly<S>,
224    tree: &Tree,
225    start: &[u8],
226    end: Option<&[u8]>,
227) -> Result<RangeIter<'a, S>, Error> {
228    let ready_store = prolly.engine.store.clone();
229    let future = create_async_range_iter(&prolly.engine, tree, start, end);
230    let inner = super::engine::ready::run_ready(ready_store.ready(future))?;
231    Ok(RangeIter { inner })
232}
233
234/// Create a range iterator that starts strictly after `after_key`.
235pub fn create_range_after_iter<'a, S: Store>(
236    prolly: &'a Prolly<S>,
237    tree: &Tree,
238    after_key: &[u8],
239    end: Option<&[u8]>,
240) -> Result<RangeIter<'a, S>, Error> {
241    let ready_store = prolly.engine.store.clone();
242    let future = create_async_range_after_iter(&prolly.engine, tree, after_key, end);
243    let inner = super::engine::ready::run_ready(ready_store.ready(future))?;
244    Ok(RangeIter { inner })
245}
246
247/// Create an async range iterator over key-value pairs.
248pub async fn create_async_range_iter<'a, S>(
249    prolly: &'a AsyncProlly<S>,
250    tree: &Tree,
251    start: &[u8],
252    end: Option<&[u8]>,
253) -> Result<AsyncRangeIter<'a, S>, Error>
254where
255    S: AsyncStore,
256    S::Error: Send + Sync,
257{
258    if end.is_some_and(|end| end <= start) {
259        return Ok(AsyncRangeIter::new(prolly, Vec::new(), start, end));
260    }
261
262    let path = prolly.find_read_path_arcs(tree, start).await?;
263    Ok(AsyncRangeIter::new(prolly, path, start, end))
264}
265
266/// Create an async range iterator that starts strictly after `after_key`.
267pub async fn create_async_range_after_iter<'a, S>(
268    prolly: &'a AsyncProlly<S>,
269    tree: &Tree,
270    after_key: &[u8],
271    end: Option<&[u8]>,
272) -> Result<AsyncRangeIter<'a, S>, Error>
273where
274    S: AsyncStore,
275    S::Error: Send + Sync,
276{
277    if end.is_some_and(|end| end <= after_key) {
278        return Ok(AsyncRangeIter::new_after(
279            prolly,
280            Vec::new(),
281            after_key,
282            end,
283        ));
284    }
285
286    let path = prolly.find_read_path_arcs(tree, after_key).await?;
287    Ok(AsyncRangeIter::new_after(prolly, path, after_key, end))
288}
289
290/// Iterator over key-value pairs in a range.
291///
292/// Created by [`Prolly::range`]. Yields `(key, value)` pairs in lexicographic
293/// order.
294///
295/// Maintains a stack of (node, index) pairs to track the current position in the tree
296/// and supports optional end bounds for range queries.
297pub struct RangeIter<'a, S: Store> {
298    inner: AsyncRangeIter<'a, super::store::SyncStoreAsAsync<Arc<S>>>,
299}
300
301impl<S: Store> RangeIter<'_, S> {
302    /// Return a resumable cursor for the last key yielded by this iterator.
303    pub fn resume_cursor(&self) -> RangeCursor {
304        self.inner.resume_cursor()
305    }
306}
307
308impl<S: Store> Iterator for RangeIter<'_, S> {
309    type Item = RangeItem;
310
311    fn next(&mut self) -> Option<Self::Item> {
312        if let (Some((node, index)), Some(leaf_end)) =
313            (self.inner.stack.last_mut(), self.inner.leaf_end)
314        {
315            if node.is_leaf() && *index < leaf_end {
316                let entry_index = *index;
317                *index += 1;
318                if let Some((_, last_index)) = self.inner.last_location.as_mut() {
319                    *last_index = entry_index;
320                }
321                return Some(node.entry_owned(entry_index).ok_or(Error::InvalidNode));
322            }
323        }
324
325        loop {
326            match self.inner.ready_step() {
327                RangeStep::Entry => {
328                    let Some((node, index)) = self.inner.last_location.as_ref() else {
329                        return Some(Err(Error::InvalidNode));
330                    };
331                    return Some(node.entry_owned(*index).ok_or(Error::InvalidNode));
332                }
333                RangeStep::NeedsChild => {
334                    let ready_store = self.inner.prolly.store.clone();
335                    let future = self.inner.descend_next_child();
336                    if let Err(error) = super::engine::ready::run_ready(ready_store.ready(future)) {
337                        return Some(Err(error));
338                    }
339                }
340                RangeStep::Finished => return None,
341                RangeStep::Error(error) => return Some(Err(error)),
342            }
343        }
344    }
345}
346
347enum RangeStep {
348    Entry,
349    NeedsChild,
350    Finished,
351    Error(Error),
352}
353/// Async iterator over key-value pairs in a range.
354///
355/// Created by [`AsyncProlly::range`](crate::AsyncProlly::range). Call
356/// [`AsyncRangeIter::next`] to lazily read one item at a time, or
357/// [`AsyncRangeIter::into_stream`] to adapt it to a `futures_util::Stream`.
358pub struct AsyncRangeIter<'a, S: AsyncStore> {
359    prolly: &'a AsyncProlly<S>,
360    stack: Vec<(Arc<ReadNode>, usize)>,
361    end: Option<Vec<u8>>,
362    started: bool,
363    start_key: Vec<u8>,
364    skip_start_key: bool,
365    last_location: Option<(Arc<ReadNode>, usize)>,
366    leaf_end: Option<usize>,
367}
368impl<'a, S> AsyncRangeIter<'a, S>
369where
370    S: AsyncStore,
371    S::Error: Send + Sync,
372{
373    pub(crate) fn new(
374        prolly: &'a AsyncProlly<S>,
375        stack: Vec<(Arc<ReadNode>, usize)>,
376        start: &[u8],
377        end: Option<&[u8]>,
378    ) -> Self {
379        Self {
380            prolly,
381            stack,
382            end: end.map(|e| e.to_vec()),
383            started: false,
384            start_key: start.to_vec(),
385            skip_start_key: false,
386            last_location: None,
387            leaf_end: None,
388        }
389    }
390
391    pub(crate) fn new_after(
392        prolly: &'a AsyncProlly<S>,
393        stack: Vec<(Arc<ReadNode>, usize)>,
394        after_key: &[u8],
395        end: Option<&[u8]>,
396    ) -> Self {
397        Self {
398            prolly,
399            stack,
400            end: end.map(|e| e.to_vec()),
401            started: false,
402            start_key: after_key.to_vec(),
403            skip_start_key: true,
404            last_location: None,
405            leaf_end: None,
406        }
407    }
408
409    /// Return the next key-value pair in lexicographic order.
410    pub async fn next(&mut self) -> Option<RangeItem> {
411        if let (Some((node, index)), Some(leaf_end)) = (self.stack.last_mut(), self.leaf_end) {
412            if node.is_leaf() && *index < leaf_end {
413                let entry_index = *index;
414                *index += 1;
415                if let Some((_, last_index)) = self.last_location.as_mut() {
416                    *last_index = entry_index;
417                }
418                return Some(node.entry_owned(entry_index).ok_or(Error::InvalidNode));
419            }
420        }
421
422        loop {
423            match self.ready_step() {
424                RangeStep::Entry => {
425                    let Some((node, index)) = self.last_location.as_ref() else {
426                        return Some(Err(Error::InvalidNode));
427                    };
428                    return Some(node.entry_owned(*index).ok_or(Error::InvalidNode));
429                }
430                RangeStep::NeedsChild => {
431                    if let Err(error) = self.descend_next_child().await {
432                        return Some(Err(error));
433                    }
434                }
435                RangeStep::Finished => return None,
436                RangeStep::Error(error) => return Some(Err(error)),
437            }
438        }
439    }
440
441    /// Visit the next entry without copying its key or value.
442    ///
443    /// The callback is synchronous and runs after any required child load has
444    /// completed, so its borrowed entry cannot cross an `.await` boundary.
445    pub async fn next_with<R>(
446        &mut self,
447        read: impl for<'entry> FnOnce(EntryRef<'entry>) -> R,
448    ) -> Option<Result<R, Error>> {
449        let mut read = Some(read);
450
451        if let (Some((node, index)), Some(leaf_end)) = (self.stack.last_mut(), self.leaf_end) {
452            if node.is_leaf() && *index < leaf_end {
453                let entry_index = *index;
454                *index += 1;
455                if let Some((_, last_index)) = self.last_location.as_mut() {
456                    *last_index = entry_index;
457                }
458                let Some((key, value)) = node.entry(entry_index) else {
459                    return Some(Err(Error::InvalidNode));
460                };
461                return Some(Ok(read
462                    .take()
463                    .expect("async range callback is invoked at most once")(
464                    EntryRef::new(key, value),
465                )));
466            }
467        }
468
469        loop {
470            match self.ready_step() {
471                RangeStep::Entry => {
472                    let Some((node, index)) = self.last_location.as_ref() else {
473                        return Some(Err(Error::InvalidNode));
474                    };
475                    let Some((key, value)) = node.entry(*index) else {
476                        return Some(Err(Error::InvalidNode));
477                    };
478                    return Some(Ok(read
479                        .take()
480                        .expect("async range callback is invoked at most once")(
481                        EntryRef::new(key, value),
482                    )));
483                }
484                RangeStep::NeedsChild => {
485                    if let Err(error) = self.descend_next_child().await {
486                        return Some(Err(error));
487                    }
488                }
489                RangeStep::Finished => return None,
490                RangeStep::Error(error) => return Some(Err(error)),
491            }
492        }
493    }
494
495    /// Collect all remaining range entries into memory.
496    pub async fn collect(mut self) -> Result<Vec<LeafEntry>, Error> {
497        let mut entries = Vec::new();
498        while let Some(item) = self.next().await {
499            entries.push(item?);
500        }
501        Ok(entries)
502    }
503
504    /// Return a resumable cursor for the last key yielded by this iterator.
505    ///
506    /// If the iterator has not yielded an item yet, this returns
507    /// [`RangeCursor::start`].
508    pub fn resume_cursor(&self) -> RangeCursor {
509        self.last_location
510            .as_ref()
511            .and_then(|(node, index)| node.key(*index))
512            .map(<[u8]>::to_vec)
513            .map(RangeCursor::after_key)
514            .unwrap_or_else(RangeCursor::start)
515    }
516
517    /// Convert this iterator into a `futures_util::Stream`.
518    pub fn into_stream(self) -> impl Stream<Item = RangeItem> + 'a {
519        stream::unfold(self, |mut iter| async move {
520            iter.next().await.map(|item| (item, iter))
521        })
522    }
523
524    fn position_at_start(&mut self) {
525        if self.started {
526            return;
527        }
528
529        self.started = true;
530        let Some((node, idx)) = self.stack.last_mut() else {
531            return;
532        };
533
534        if node.is_leaf() {
535            *idx = match node.search(&self.start_key) {
536                Ok(i) if self.skip_start_key => i.saturating_add(1),
537                Ok(i) | Err(i) => i,
538            };
539            self.leaf_end = Some(self.end.as_deref().map_or(node.len(), |end| {
540                node.search(end).unwrap_or_else(|index| index)
541            }));
542        }
543    }
544
545    fn ready_step(&mut self) -> RangeStep {
546        self.position_at_start();
547
548        loop {
549            let Some((node, idx)) = self.stack.last_mut() else {
550                return RangeStep::Finished;
551            };
552
553            if *idx >= node.len() {
554                match self.advance_to_next_sibling() {
555                    Ok(true) => continue,
556                    Ok(false) => return RangeStep::Finished,
557                    Err(error) => return RangeStep::Error(error),
558                }
559            }
560
561            if node.is_leaf() {
562                let entering_leaf = self.leaf_end.is_none();
563                let leaf_end = match self.leaf_end {
564                    Some(leaf_end) => leaf_end,
565                    None => {
566                        let leaf_end = self.end.as_deref().map_or(node.len(), |end| {
567                            node.search(end).unwrap_or_else(|index| index)
568                        });
569                        self.leaf_end = Some(leaf_end);
570                        leaf_end
571                    }
572                };
573                if *idx >= leaf_end {
574                    return RangeStep::Finished;
575                }
576                let index = *idx;
577                *idx += 1;
578                match self.last_location.as_mut() {
579                    Some((_, last_index)) if !entering_leaf => *last_index = index,
580                    _ => self.last_location = Some((node.clone(), index)),
581                }
582                return RangeStep::Entry;
583            }
584
585            return match child_starts_at_or_after_end(self.end.as_deref(), node, *idx) {
586                Ok(true) => RangeStep::Finished,
587                Ok(false) => RangeStep::NeedsChild,
588                Err(error) => RangeStep::Error(error),
589            };
590        }
591    }
592
593    async fn descend_next_child(&mut self) -> Result<(), Error> {
594        let (node, index) = self
595            .stack
596            .last()
597            .map(|(node, index)| (node.clone(), *index))
598            .ok_or(Error::InvalidNode)?;
599        let child = self.load_child_for_descent(&node, index).await?;
600        self.stack.push((child, 0));
601        self.leaf_end = None;
602        Ok(())
603    }
604
605    fn advance_to_next_sibling(&mut self) -> Result<bool, Error> {
606        loop {
607            self.stack.pop();
608            self.leaf_end = None;
609            let Some((parent, parent_idx)) = self.stack.last_mut() else {
610                return Ok(false);
611            };
612
613            *parent_idx += 1;
614
615            if *parent_idx < parent.len() {
616                if child_starts_at_or_after_end(self.end.as_deref(), parent, *parent_idx)? {
617                    return Ok(false);
618                }
619                return Ok(true);
620            }
621        }
622    }
623
624    async fn load_child_for_descent(
625        &self,
626        node: &ReadNode,
627        idx: usize,
628    ) -> Result<Arc<ReadNode>, Error> {
629        let child_cid = node.child_cid(idx)?;
630
631        if !self.prolly.store().prefers_batch_reads() {
632            return self.prolly.load_read_arc(&child_cid).await;
633        }
634
635        let max_child_idx = node
636            .len()
637            .min(idx.saturating_add(RANGE_CHILD_PREFETCH_PARALLELISM));
638        let mut child_cids = Vec::with_capacity(max_child_idx.saturating_sub(idx));
639        child_cids.push(child_cid);
640
641        for child_idx in idx + 1..max_child_idx {
642            if child_starts_at_or_after_end(self.end.as_deref(), node, child_idx).unwrap_or(true) {
643                break;
644            }
645
646            match node.child_cid(child_idx) {
647                Ok(cid) => child_cids.push(cid),
648                Err(_) => break,
649            }
650        }
651
652        if child_cids.len() == 1 {
653            return self.prolly.load_read_arc(&child_cids[0]).await;
654        }
655
656        let children = self.prolly.load_many_read_ordered(&child_cids).await?;
657        children.into_iter().next().ok_or(Error::InvalidNode)
658    }
659}
660
661fn child_starts_at_or_after_end(
662    end: Option<&[u8]>,
663    node: &ReadNode,
664    child_index: usize,
665) -> Result<bool, Error> {
666    let Some(end) = end else {
667        return Ok(false);
668    };
669
670    let first_key = node.key(child_index).ok_or(Error::InvalidNode)?;
671    Ok(first_key >= end)
672}