Skip to content

Commit 6899ae8

Browse files
committed
docs: clarify iterator API selection and fix cargo doc warnings
- Rewrite doc comments for iter(), iter_with_options(), iter_with_range(), and iter_with_prefix() to clearly explain when to use each API - Add pruning comparison table (range pruning vs bloom filter pruning) - Update README.md API reference with the same guidance - Fix rustdoc warnings: escape brackets in types.rs, wrap Arc<TableReader> in backticks in db.rs
1 parent b981cf8 commit 6899ae8

3 files changed

Lines changed: 90 additions & 23 deletions

File tree

README.md

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -190,13 +190,34 @@ impl DB {
190190
pub fn write_with_options(&self, batch: WriteBatch, options: &WriteOptions) -> Result<()>;
191191
pub fn iter(&self) -> Result<DBIterator>;
192192

193-
/// Prefix-optimized iteration. Uses prefix bloom filters to skip entire SST
194-
/// files that don't contain `prefix`. Supports bounds via ReadOptions.
193+
/// Prefix-bounded iteration — the fastest option for prefix-scoped queries.
194+
///
195+
/// Applies two levels of SST pruning:
196+
/// 1. Range pruning — skips files whose key range doesn't overlap the prefix.
197+
/// 2. Bloom filter — skips files that don't contain the prefix (finer-grained).
198+
///
199+
/// Use this when all target keys share a common prefix (e.g. `b"orders:"`).
200+
/// For a sub-range within the prefix, set ReadOptions bounds.
195201
pub fn iter_with_prefix(&self, prefix: &[u8], options: &ReadOptions) -> Result<DBIterator>;
196202

197-
/// Full-scan iteration with optional key-range bounds.
198-
/// WARNING: Does NOT use prefix bloom filters. For prefix-scoped queries,
199-
/// prefer `iter_with_prefix()` which is significantly faster.
203+
/// Arbitrary key-range iteration with SST range pruning.
204+
///
205+
/// Skips SST files whose `[smallest, largest]` key range does not overlap
206+
/// `[lower, upper)` — but does NOT use bloom filters.
207+
///
208+
/// Use this when the scan range spans multiple prefixes and cannot be
209+
/// expressed as a single `iter_with_prefix()` call (e.g. `[b"m", b"z")`).
210+
/// For full-database scans, prefer `iter()` / `iter_with_options()`.
211+
///
212+
/// Explicit bounds are merged with any bounds in ReadOptions (tighter wins).
213+
///
214+
/// ## Pruning comparison
215+
///
216+
/// | Method | SST range pruning | Bloom filter pruning |
217+
/// |----------------------|:-----------------:|:--------------------:|
218+
/// | `iter()` | ✗ | ✗ |
219+
/// | `iter_with_range()` | ✓ | ✗ |
220+
/// | `iter_with_prefix()` | ✓ | ✓ |
200221
pub fn iter_with_range(&self, options: &ReadOptions, lower: Option<&[u8]>, upper: Option<&[u8]>) -> Result<DBIterator>;
201222

202223
/// RAII snapshot — automatically released on drop.

src/db.rs

Lines changed: 63 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ fn pool_take() -> Option<DBIterator> {
5454
}
5555

5656
/// Return a DBIterator to the global pool for reuse.
57-
/// The iterator's sources are cleared to release Arc<TableReader> references,
57+
/// The iterator's sources are cleared to release `Arc<TableReader>` references,
5858
/// preventing stale SST files from being kept alive by pooled iterators.
5959
pub fn pool_return(mut iter: DBIterator) {
6060
iter.reset(Vec::new(), 0);
@@ -826,28 +826,59 @@ impl DB {
826826
Ok(None)
827827
}
828828

829-
/// Create a forward iterator over the database.
829+
/// Create a forward iterator over the entire database.
830+
///
831+
/// Scans all keys in order. No SST pruning is applied.
832+
/// Equivalent to `iter_with_options(&ReadOptions::default())`.
833+
///
834+
/// Prefer `iter_with_prefix()` or `iter_with_range()` when only a subset of
835+
/// keys is needed — both can skip irrelevant SST files.
830836
pub fn iter(&self) -> Result<DBIterator> {
831837
self.iter_with_options(&ReadOptions::default())
832838
}
833839

834-
/// Create a forward iterator with options.
840+
/// Create a forward iterator over the entire database with options.
835841
///
836-
/// Uses streaming TableIterators for SST files (O(1 block) memory per SST)
837-
/// instead of loading entire tables into memory.
842+
/// Uses streaming `TableIterator`s for SST files (O(1 block) memory per SST).
843+
/// No SST pruning is applied; all files are visited.
844+
///
845+
/// Use `ReadOptions::iterate_lower_bound` / `iterate_upper_bound` to restrict
846+
/// the key range returned, but note that SST files are still opened for the
847+
/// full scan. For query-time SST pruning use `iter_with_range()` or
848+
/// `iter_with_prefix()`.
838849
pub fn iter_with_options(&self, options: &ReadOptions) -> Result<DBIterator> {
839850
self.iter_with_range(options, None, None)
840851
}
841852

842-
/// Create a forward iterator that only includes sources overlapping [lower_bound, upper_bound].
843-
/// SST files outside this range are skipped entirely, avoiding costly block reads.
844-
/// `None` bounds mean unbounded in that direction.
853+
/// Create a forward iterator for an arbitrary key range `[lower_bound, upper_bound)`.
854+
///
855+
/// SST files whose key range does not overlap `[lower_bound, upper_bound)` are
856+
/// skipped entirely at construction time, avoiding unnecessary block reads.
857+
/// `None` means unbounded in that direction.
858+
///
859+
/// # When to use
860+
///
861+
/// Use this when the scan range **does not align to a single key prefix** —
862+
/// for example `[b"m", b"z")` spans many prefixes and cannot be expressed as
863+
/// a single `iter_with_prefix()` call.
864+
///
865+
/// If your range *does* align to a prefix (e.g. all keys starting with
866+
/// `b"user:"`), prefer `iter_with_prefix()`: it additionally uses bloom
867+
/// filters to skip SST files that don't contain the prefix, which is more
868+
/// precise than range-metadata pruning alone.
845869
///
846-
/// **WARNING**: Does NOT use prefix bloom filters. For prefix-scoped queries,
847-
/// prefer `iter_with_prefix()` which is significantly faster.
870+
/// # Pruning comparison
848871
///
849-
/// Bounds from `ReadOptions::iterate_lower_bound` / `iterate_upper_bound` are
850-
/// also applied if set, using the tighter of the two.
872+
/// | Method | SST range pruning | Bloom filter pruning |
873+
/// |---------------------|:-----------------:|:--------------------:|
874+
/// | `iter()` | ✗ | ✗ |
875+
/// | `iter_with_range()` | ✓ | ✗ |
876+
/// | `iter_with_prefix()`| ✓ | ✓ |
877+
///
878+
/// # Bound merging
879+
///
880+
/// Explicit `lower_bound`/`upper_bound` parameters are merged with any bounds
881+
/// already set in `ReadOptions`, using the tighter of the two.
851882
pub fn iter_with_range(
852883
&self,
853884
options: &ReadOptions,
@@ -1017,12 +1048,27 @@ impl DB {
10171048

10181049
/// Create a prefix-bounded iterator with full options support.
10191050
///
1020-
/// Uses prefix bloom filters to skip SST files that don't contain the prefix,
1021-
/// and stops iteration as soon as the prefix boundary is crossed.
1022-
/// Significantly faster than `iter_with_range()` for prefix-scoped queries.
1051+
/// Iterates over all keys that start with `prefix` in order.
1052+
///
1053+
/// # When to use
1054+
///
1055+
/// Use this whenever your query is naturally prefix-scoped — for example,
1056+
/// all keys under a tenant (`b"tenant_42:"`), a table (`b"orders:"`), etc.
1057+
/// It is the fastest iterator variant because it applies **two levels of
1058+
/// SST pruning**:
1059+
///
1060+
/// 1. **Range pruning** — skips SST files whose `[smallest, largest]` key
1061+
/// range does not overlap the prefix.
1062+
/// 2. **Bloom filter pruning** — among the remaining files, skips those
1063+
/// whose per-block bloom filters report that `prefix` is absent.
1064+
///
1065+
/// For cross-prefix ranges (e.g. `[b"m", b"z")`) use `iter_with_range()`
1066+
/// instead, as there is no single prefix that covers the query.
1067+
///
1068+
/// # Sub-range within a prefix
10231069
///
1024-
/// Supports `ReadOptions::iterate_lower_bound` / `iterate_upper_bound` for
1025-
/// sub-range queries within a prefix, and `snapshot` for historical reads.
1070+
/// Set `ReadOptions::iterate_lower_bound` / `iterate_upper_bound` to further
1071+
/// restrict iteration to a sub-range inside the prefix.
10261072
pub fn iter_with_prefix(&self, prefix: &[u8], options: &ReadOptions) -> Result<DBIterator> {
10271073
let seq = options.snapshot.unwrap_or_else(|| self.current_sequence());
10281074
self.iter_with_prefix_inner(prefix, seq, options)

src/types.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Core data types: InternalKey, ValueType, SequenceNumber.
22
//!
33
//! Encoding follows RocksDB convention:
4-
//! InternalKey = [user_key bytes][packed: seq << 8 | type] (last 8 bytes)
4+
//! InternalKey = \[user_key bytes\]\[packed: seq << 8 | type\] (last 8 bytes)
55
//! Sort order: user_key ASC, sequence DESC, value_type DESC
66
77
use std::cmp::Ordering;

0 commit comments

Comments
 (0)