pub struct Tree(/* private fields */);Expand description
A log-structured merge tree (LSM-tree/LSMT)
Clones share one tree. Background work of the tree (the table file pool,
the file deleter) may still touch its directory after a handle drops; to
remove the directory, close the tree and wait for the
returned TreeClose: once it fires, the tree writes
nothing into its directory any more.
Implementations§
Source§impl Tree
impl Tree
Sourcepub fn columnar_scan<R: RangeBounds<UserKey>>(
&self,
projection: impl Into<Projection>,
predicate: Option<&ColumnRangePredicate>,
seqno: SeqNo,
range: R,
) -> Result<ColumnarScan>
pub fn columnar_scan<R: RangeBounds<UserKey>>( &self, projection: impl Into<Projection>, predicate: Option<&ColumnRangePredicate>, seqno: SeqNo, range: R, ) -> Result<ColumnarScan>
Runs a projected columnar scan across the whole tree.
Reads every source intersecting range at snapshot seqno: the
memtables, the row-oriented tables and the columnar ones. It applies
deletions and range tombstones from any source to the keys of every
other, resolves merge chains as a read does, applies the optional
predicate (zone-map block-skip + row filter, after the newest version
of each key is chosen) and yields projected [ColumnBatch]es in
ascending key order, one row per key: its newest visible version. A
columnar segment no other source overlaps streams without merge
overhead.
range bounds the result at row granularity: a segment that only
partially overlaps range contributes only the rows whose keys fall
inside it (the inclusive / exclusive sense of each bound is honored). A
fully unbounded range keeps the zero-copy fast path for an all-visible
segment.
projection names the columns each batch carries, in its order: column
ids (the intrinsic [COL_USER_KEY] / seqno / value-type columns, or a
value column typed by what the tables store), converted from a slice of
ids, or a Projection of declared fields,
which says what a field a row lacks reads as and carries the projector
the fields are read out of whole values through. Every other column of a
columnar table is stepped over without decoding.
§Errors
Returns Error::Projection when the projection names one column id
twice or the highest id, and, lazily, while iterating, when a row
returned stores its value whole and no projector is set to read its
declared fields, or when the data does not satisfy the projection.
Returns an error on a block read
or decode failure, or on a failed point read resolving a merge chain.
§Examples
use lsm_tree::table::columnar::COL_USER_KEY;
use lsm_tree::{AbstractTree, Config, SeqNo};
let folder = tempfile::tempdir()?;
let tree = Config::new(folder, Default::default(), Default::default()).open()?;
// Rows in the memtable are read like any other source.
tree.insert("a", "1", 0);
tree.insert("b", "2", 1);
let rows: u32 = tree
.columnar_scan(&[COL_USER_KEY], None, SeqNo::MAX, ..)?
.map(|batch| batch.map(|b| b.row_count))
.sum::<lsm_tree::Result<u32>>()?;
assert_eq!(rows, 2);Source§impl Tree
impl Tree
Sourcepub fn close(self) -> TreeClose
pub fn close(self) -> TreeClose
Gives up this handle and returns the signal of the tree being closed.
The tree is closed once nothing of it owns a file of its directory or works in it any more: other strong handles, iterators, snapshots and pins keep it open until they drop, and the table file pool and the background deleter finish what they started. Once closed, the tree writes nothing into its directory and removing the directory is safe.
From this call on no WeakTree raises the tree
again; strong handles already held keep working until dropped.
§Examples
use lsm_tree::{AbstractTree, AnyTree};
let AnyTree::Standard(tree) = lsm_tree::Config::new(
folder.path(),
lsm_tree::SequenceNumberCounter::default(),
lsm_tree::SequenceNumberCounter::default(),
)
.open()?
else {
unreachable!("no key-value separation configured");
};
let monitor = tree.downgrade();
let closed = tree.close();
assert!(monitor.upgrade().is_none());
closed.wait();
std::fs::remove_dir_all(folder.path())?;Source§impl Tree
impl Tree
Sourcepub fn register_zstd_dictionary(&self, dict: Arc<ZstdDictionary>) -> Result<()>
pub fn register_zstd_dictionary(&self, dict: Arc<ZstdDictionary>) -> Result<()>
Stores dict in the tree and records it in the current version, so it
resolves after a reopen with no dictionary supplied in the config.
Additive: tables already written keep resolving to the dictionary they were written against, which is what makes it safe to introduce a dictionary on a tree that already holds data, and to replace one (both are this same operation). Registering an id the tree already holds is a no-op, since the id is derived from the bytes.
The file is written BEFORE the version edit that references it. The other order would publish an id whose bytes a crash could still lose, and the tables written against it would then fail to open; this order can only leave an unreferenced file, which the next collection removes.
Both steps happen under the version lock, which is what serializes this
against Self::collect_unreferenced_dictionaries. Taking the lock only
for the edit would leave the file published in the window the collector
scans, and it would be unlinked as an orphan before the edit that names
it ever landed.
§Errors
Propagates the store’s write failures and the version install’s.
Sourcepub fn zstd_dictionaries(&self) -> ZstdDictionaries
pub fn zstd_dictionaries(&self) -> ZstdDictionaries
The dictionaries this tree can decompress against, as of this call.
Sourcepub fn collect_unreferenced_dictionaries(&self) -> Result<usize>
pub fn collect_unreferenced_dictionaries(&self) -> Result<usize>
Drops every dictionary nothing references any more, returning how many files were removed.
The current version first stops REGISTERING an id nothing references (a version edit, costing an install and nothing on disk), and the file goes in the same pass once the installed version no longer names it. A reader still holding an older version is unaffected: its tables and blob files pinned their dictionaries when they were opened.
REFERENCED means both directions: the files that already exist (tables
and blob files alike), and the ids the compression policies name for
what is written next. Counting only the first would unregister a
dictionary before its first table is written, and nothing puts the id
back afterwards, so a later pass would unlink the file while live
tables are compressed against it. What is written next includes the
writers already running: a flush or compaction started under a policy
Self::update_runtime_config has since replaced still writes against
the dictionary that policy named, so it is spared until their files are
installed and name it themselves.
The whole pass holds the version lock. Registration takes the same lock before it writes anything, so the two cannot interleave: without that, a registration’s file could land between this scan and its removals and be unlinked as an orphan while the edit naming it was still to come.
§Errors
Propagates the version install and the store’s removal failures.
Sourcepub fn scan_since_seqno(
&self,
target_seqno: SeqNo,
) -> Result<impl Iterator<Item = ScanSinceEvent> + use<>>
pub fn scan_since_seqno( &self, target_seqno: SeqNo, ) -> Result<impl Iterator<Item = ScanSinceEvent> + use<>>
Iterate change events with seqno >= target_seqno.
Returns every change committed at or after target_seqno as a stream
of ScanSinceEvents in increasing seqno order. This is the canonical
change-data-capture primitive: a downstream consumer (replica, Kafka
connector, Debezium-style pipeline) replays the events in order to
reconstruct the source’s history. Superseded versions are not collapsed
(a key written three times after the target yields three events).
§Concurrency
The result is a snapshot of the tree as of the call: the active memtable is captured with writers excluded, so a batch committed concurrently is either wholly in the result or wholly absent, never split across it. This holds even for a caller-chosen sequence number at or below the reported watermark, which the seqno bound alone would not exclude. Writers are blocked only while that capture runs — the sealed memtables and SSTs the scan then reads are immutable.
§History retention
The stream carries what the tree still PHYSICALLY HOLDS. A compaction
run with a GC watermark (the gc_watermark passed to
compact /
major_compact) drops shadowed
versions and evicted tombstones below that watermark and may fold
merge chains and zero bottommost seqnos — history a later scan cannot
resurrect. The result is therefore complete only for a target_seqno
at or above the highest GC watermark ever applied: a deployment
replaying this stream (an external-WAL consumer, a CDC replica) must
keep its compaction watermark at or below the lowest cursor it may
still rewind to, exactly as docs/external-wal.md section 4’s
GC-coordination rules require. The watermark is caller-supplied and
not persisted, so this method cannot detect a violation for you.
§Block-skip
On SSTs written with the seqno_bounds section (seqno_in_index), data
blocks whose bounds cannot overlap the target window are skipped without
being read; SSTs without the section are read and filtered per entry, so
mixed trees are handled transparently.
§KV-separation
Standard trees never store blob-indirected values. On the inner tree of
a KV-separated (blob) tree this returns an Err for indirected entries:
blob resolution into ScanSinceEvent::Insert is provided by the
blob-tree scan path, which owns the blob files.
§Corruption resilience
The per-block seqno-bounds used for skipping live in the optional
seqno_bounds SST section, a Block covered by XXH3-128 (+ optional Page
ECC) and verified when it is loaded at open, plus a decode that rejects
non-ascending offsets and inverted bounds, so a corrupted bound is caught
rather than trusted. Even in the impossible case of a fault bypassing
those checks, a bad bound can only cause a missed record, never a wrong
one. Callers who want defense against that hypothetical can use
Self::scan_since_seqno_full_scan, which reads every block (slower, no
skip).
§Panics
Panics if the internal version-history lock is poisoned.
§Errors
Returns Err if reading the index or a data block fails, or if an entry
is a KV-separated value (see above).
Sourcepub fn scan_since_seqno_full_scan(
&self,
target_seqno: SeqNo,
) -> Result<impl Iterator<Item = ScanSinceEvent> + use<>>
pub fn scan_since_seqno_full_scan( &self, target_seqno: SeqNo, ) -> Result<impl Iterator<Item = ScanSinceEvent> + use<>>
Paranoid variant of Self::scan_since_seqno that disables the
per-block seqno-bounds skip: every data block is read and filtered per
entry, even on seqno-indexed SSTs.
§When to use
The fast Self::scan_since_seqno trusts each block’s recorded
[seqno_min, seqno_max] to skip blocks that cannot hold a qualifying
record. Those bounds live in the seqno_bounds SST section, a Block
covered by XXH3-128 (and optional Page ECC) and verified at open, so
on-disk corruption is caught, not silently trusted. This method exists
for callers who
want defense even against a fault that somehow bypassed those checks: a
corrupted seqno_max can only ever cause a missed record (never a
wrong one), and a full scan cannot miss. It is slower (no skip), so
prefer Self::scan_since_seqno unless you specifically need this
guarantee.
§Panics
Panics if the internal version-history lock is poisoned.
§Errors
Same as Self::scan_since_seqno.
Sourcepub fn scan_since_seqno_in_range<K: AsRef<[u8]>, R: RangeBounds<K>>(
&self,
target_seqno: SeqNo,
range: R,
) -> Result<impl Iterator<Item = ScanSinceEvent> + use<K, R>>
pub fn scan_since_seqno_in_range<K: AsRef<[u8]>, R: RangeBounds<K>>( &self, target_seqno: SeqNo, range: R, ) -> Result<impl Iterator<Item = ScanSinceEvent> + use<K, R>>
Range-scoped variant of Self::scan_since_seqno: delivers only
events whose key falls within range (in the tree comparator’s
order); range-deletion events are delivered when their span OVERLAPS
it, since a tombstone reaching into the range affects replay within
it. SSTs whose key range cannot intersect the bounds are skipped
without a single block read.
This is the presence-check primitive for reconciling an external
write-ahead log after a repair: RepairReport::lost_coverage names
the affected key ranges, and deciding which retained WAL records to
re-apply (in particular, which merge operands SURVIVED and must not be
folded twice) only needs the events inside those ranges. See
docs/external-wal.md § Replay after repair.
The history-retention caveat of Self::scan_since_seqno applies
unchanged: the stream is complete only for a target_seqno at or
above the highest compaction GC watermark ever applied.
§Panics
Panics if the internal version-history lock is poisoned.
§Errors
Same as Self::scan_since_seqno.
Sourcepub fn update_runtime_config<F>(&self, mutator: F) -> Result<()>where
F: FnOnce(&mut RuntimeConfig),
pub fn update_runtime_config<F>(&self, mutator: F) -> Result<()>where
F: FnOnce(&mut RuntimeConfig),
Update the live crate::runtime_config::RuntimeConfig.
Mutator runs on a clone of the current snapshot; the new snapshot
is then atomically swapped in. Subsequent calls to
Self::runtime_config observe the new snapshot.
§Semantics
- Write paths (flush, compaction, ingestion) take one snapshot when they start and use it throughout, so a change applies to the next one and never splits a single file between two configurations.
- Existing on-disk data remains in its original format and reads transparently: every block, manifest and blob file is self-describing via its own header or descriptor. That includes the compression policies, so changing one rewrites nothing.
- Compaction acts as the live-migration mechanism: source blocks are rewritten per the current snapshot over subsequent cycles, so all data converges to the current settings without stop-the-world coordination.
§Concurrency
Reader atomicity: concurrent readers observe either the old or the new snapshot, never a torn intermediate state.
Writer semantics: last-writer-wins. Two update calls racing
from the same starting snapshot will have the second store
overwrite the first — the first writer’s mutation is lost. There
is no CAS / RCU merge. Callers that need lost-update avoidance
(e.g. two threads concurrently toggling different fields) MUST
serialize their update_runtime_config calls, typically via a
Mutex around the call site.
§Errors
Returns crate::Error::PageEccUnsupported when the mutator
leaves page_ecc = true on a binary built without the
page_ecc cargo feature, and
crate::Error::ZstdDictMismatch when a compression policy names a
dictionary the tree does not hold (register it first with
Self::register_zstd_dictionary). The live snapshot stays at its
pre-mutation value on error.
Sourcepub fn runtime_config(&self) -> Arc<RuntimeConfig> ⓘ
pub fn runtime_config(&self) -> Arc<RuntimeConfig> ⓘ
Snapshot of the current runtime config. Cheap atomic load — safe to call on hot paths.
Sourcepub fn heal_hints(&self) -> Arc<HealHints> ⓘ
pub fn heal_hints(&self) -> Arc<HealHints> ⓘ
Shared handle to this tree’s ECC heal-hint queue.
A read that recovers a block from Page-ECC parity records the owning SST
here (when the on-disk fault is confirmed persistent). Pass the handle to
compaction::EccHeal and run that strategy
via Tree::compact — leader-only in a
clustered deployment — to rewrite the flagged SSTs clean. Check
HealHints::is_empty to skip
the pass when nothing is queued.
§Examples
use lsm_tree::{AbstractTree, AnyTree, Config, SequenceNumberCounter, compaction::EccHeal};
use std::sync::Arc;
let AnyTree::Standard(tree) = Config::new(
"/tmp/db",
SequenceNumberCounter::default(),
SequenceNumberCounter::default(),
)
.open()?
else {
return Ok(());
};
// Opt into rewrite scheduling; reads that recover a block from parity now
// flag its SST for healing.
tree.update_runtime_config(|c| c.auto_heal = true)?;
// Drain the queue, rewriting each flagged SST clean (leader-only in a
// clustered deployment).
let hints = tree.heal_hints();
while !hints.is_empty() {
tree.compact(Arc::new(EccHeal::new(tree.heal_hints(), u64::MAX)), 0)?;
}Sourcepub fn start_multi_get<K: Into<UserKey>>(
&self,
keys: impl IntoIterator<Item = K>,
seqno: SeqNo,
) -> Result<Step>
pub fn start_multi_get<K: Into<UserKey>>( &self, keys: impl IntoIterator<Item = K>, seqno: SeqNo, ) -> Result<Step>
Starts a multi-get of keys at seqno that its caller drives: the
read hands out its block reads and jobs instead of carrying them out,
so the calling thread is never parked inside it. It answers what
AbstractTree::multi_get answers at the moment it starts: what is
written while it is suspended is not part of its answer, even at a
ceiling such as SeqNo::MAX.
§Errors
Returns crate::Error::SnapshotBelowRetention when seqno is below
what the tree retains.
§Examples
Driving the read on the calling thread:
use lsm_tree::resumable::Step;
use lsm_tree::{AbstractTree, Config, SequenceNumberCounter};
let tree = Config::new(&folder, SequenceNumberCounter::default(), SequenceNumberCounter::default()).open()?;
tree.insert("a", "1", 0);
tree.flush_active_memtable(0)?;
let mut step = tree.start_multi_get(["a", "b"], 1)?;
let values = loop {
let mut read = match step {
Step::Done(values) => break values?,
Step::Pending(read) => read,
};
for job in read.take_jobs() {
let outcome = job.run();
read.complete_job(outcome);
}
for mut block in read.take_reads() {
let result = block.file.read_at(&mut block.buf, block.offset).and_then(|n| {
if n == block.buf.len() { Ok(()) } else { Err(lsm_tree::io::ErrorKind::UnexpectedEof.into()) }
});
read.complete_read(block.tag, result, block.buf);
}
step = read.resume();
};
assert_eq!(values, [Some("1".as_bytes().into()), None]);Trait Implementations§
Source§impl AbstractTree for Tree
impl AbstractTree for Tree
Source§fn tombstone_count(&self) -> u64
fn tombstone_count(&self) -> u64
Returns the number of tombstones in the tree.
Source§fn weak_tombstone_count(&self) -> u64
fn weak_tombstone_count(&self) -> u64
Returns the number of weak tombstones (single deletes) in the tree.
Source§fn weak_tombstone_reclaimable_count(&self) -> u64
fn weak_tombstone_reclaimable_count(&self) -> u64
Returns the number of value entries that become reclaimable once weak tombstones can be GC’d.
Source§fn table_file_cache_size(&self) -> usize
fn table_file_cache_size(&self) -> usize
Source§fn persist_flushes(&self) -> Result<()>
fn persist_flushes(&self) -> Result<()>
FlushDurability::Deferred:
the tables and blob files those flushes wrote are synced, then their
folders, then the manifest is written. Once it returns Ok a caller
may drop its own log up to the writes those flushes held; under
SyncMode::Barrier after
sync_devices as well. A no-op when nothing is
pending, and under FlushDurability::Synced
every flush is durable when it returns. Read moreSource§fn blob_file_count(&self) -> usize
fn blob_file_count(&self) -> usize
Source§fn create_checkpoint(&self, target_path: &Path) -> Result<CheckpointInfo>
fn create_checkpoint(&self, target_path: &Path) -> Result<CheckpointInfo>
target_path for point-in-time recovery (PITR) backup. Read moreSource§fn pin(&self) -> PinnedVersion
fn pin(&self) -> PinnedVersion
PinnedVersion holding the sealed memtables,
tables, blob files and dictionaries as they are now. Read moreSource§fn acknowledge_repair_report(&self, id: u128) -> Result<bool>
fn acknowledge_repair_report(&self, id: u128) -> Result<bool>
RepairReport::id, installing a version
that no longer carries it: no later
Config::open_or_repair hands it out. Read moreSource§fn storage_stats(&self) -> Result<StorageStats>
fn storage_stats(&self) -> Result<StorageStats>
StorageStats::estimated_remaining_entries). Read moreSource§fn write_admission(&self) -> Result<()>
fn write_admission(&self) -> Result<()>
Ok(()) if a write may proceed, or
Error::StorageFull if the tree is
over budget and should be treated as read-only. Read moreSource§fn write_backpressure(&self, strategy: &dyn CompactionStrategy) -> Backpressure
fn write_backpressure(&self, strategy: &dyn CompactionStrategy) -> Backpressure
RuntimeConfig::backpressure
thresholds. Read moreSource§fn get_flush_lock(&self) -> MutexGuard<'_, ()>
fn get_flush_lock(&self) -> MutexGuard<'_, ()>
Tree::flush.Source§fn cache_stats(&self) -> CacheStats
fn cache_stats(&self) -> CacheStats
CacheStats snapshot of block-cache
effectiveness (cumulative hit / miss counts and rate) and occupancy
(current size against capacity). Read moreSource§fn prefix<K: AsRef<[u8]>>(
&self,
prefix: K,
seqno: SeqNo,
index: Option<(Arc<Memtable>, SeqNo)>,
) -> Box<dyn DoubleEndedIterator<Item = IterGuardImpl> + Send + 'static>
fn prefix<K: AsRef<[u8]>>( &self, prefix: K, seqno: SeqNo, index: Option<(Arc<Memtable>, SeqNo)>, ) -> Box<dyn DoubleEndedIterator<Item = IterGuardImpl> + Send + 'static>
Source§fn range<K: AsRef<[u8]>, R: RangeBounds<K>>(
&self,
range: R,
seqno: SeqNo,
index: Option<(Arc<Memtable>, SeqNo)>,
) -> Box<dyn DoubleEndedIterator<Item = IterGuardImpl> + Send + 'static>
fn range<K: AsRef<[u8]>, R: RangeBounds<K>>( &self, range: R, seqno: SeqNo, index: Option<(Arc<Memtable>, SeqNo)>, ) -> Box<dyn DoubleEndedIterator<Item = IterGuardImpl> + Send + 'static>
Source§fn range_seekable<K: AsRef<[u8]>, R: RangeBounds<K>>(
&self,
range: R,
seqno: SeqNo,
index: Option<(Arc<Memtable>, SeqNo)>,
) -> Box<dyn SeekableGuardIter + 'static>
fn range_seekable<K: AsRef<[u8]>, R: RangeBounds<K>>( &self, range: R, seqno: SeqNo, index: Option<(Arc<Memtable>, SeqNo)>, ) -> Box<dyn SeekableGuardIter + 'static>
Source§fn batch_range_scan<K: AsRef<[u8]>, R: RangeBounds<K> + 'static, I: IntoIterator<Item = R>>(
&self,
intervals: I,
seqno: SeqNo,
index: Option<(Arc<Memtable>, SeqNo)>,
) -> Box<dyn Iterator<Item = IterGuardImpl> + Send + 'static>
fn batch_range_scan<K: AsRef<[u8]>, R: RangeBounds<K> + 'static, I: IntoIterator<Item = R>>( &self, intervals: I, seqno: SeqNo, index: Option<(Arc<Memtable>, SeqNo)>, ) -> Box<dyn Iterator<Item = IterGuardImpl> + Send + 'static>
Source§fn l0_run_count(&self) -> usize
fn l0_run_count(&self) -> usize
Source§fn size_of<K: AsRef<[u8]>>(&self, key: K, seqno: SeqNo) -> Result<Option<u32>>
fn size_of<K: AsRef<[u8]>>(&self, key: K, seqno: SeqNo) -> Result<Option<u32>>
Source§fn filter_size(&self) -> u64
fn filter_size(&self) -> u64
Source§fn pinned_filter_size(&self) -> usize
fn pinned_filter_size(&self) -> usize
Source§fn filter_memory(&self) -> FilterMemory
fn filter_memory(&self) -> FilterMemory
FilterAdvisor
budget. Read moreSource§fn pinned_block_index_size(&self) -> usize
fn pinned_block_index_size(&self) -> usize
Source§fn sealed_memtable_count(&self) -> usize
fn sealed_memtable_count(&self) -> usize
Source§fn register_tables(
&self,
tables: &[Table],
blob_files: Option<&[BlobFile]>,
frag_map: Option<FragmentationMap>,
sealed_memtables_to_delete: &[MemtableId],
gc_watermark: SeqNo,
collected_below_watermark: bool,
) -> Result<()>
fn register_tables( &self, tables: &[Table], blob_files: Option<&[BlobFile]>, frag_map: Option<FragmentationMap>, sealed_memtables_to_delete: &[MemtableId], gc_watermark: SeqNo, collected_below_watermark: bool, ) -> Result<()>
Source§fn clear_active_memtable(&self)
fn clear_active_memtable(&self)
Source§fn compact(
&self,
strategy: Arc<dyn CompactionStrategy>,
gc_watermark: SeqNo,
) -> Result<CompactionResult>
fn compact( &self, strategy: Arc<dyn CompactionStrategy>, gc_watermark: SeqNo, ) -> Result<CompactionResult>
Source§fn get_next_table_id(&self) -> TableId
fn get_next_table_id(&self) -> TableId
Source§fn tree_config(&self) -> &Config
fn tree_config(&self) -> &Config
Source§fn table_count(&self) -> usize
fn table_count(&self) -> usize
Source§fn level_table_count(&self, idx: usize) -> Option<usize>
fn level_table_count(&self, idx: usize) -> Option<usize>
levels[idx]. Read moreSource§fn approximate_len(&self) -> usize
fn approximate_len(&self) -> usize
Source§fn disk_space(&self) -> u64
fn disk_space(&self) -> u64
Source§fn approximate_range_stats<K: AsRef<[u8]>, R: RangeBounds<K>>(
&self,
range: R,
seqno: SeqNo,
) -> Result<ApproximateRangeStats>
fn approximate_range_stats<K: AsRef<[u8]>, R: RangeBounds<K>>( &self, range: R, seqno: SeqNo, ) -> Result<ApproximateRangeStats>
range at
seqno, WITHOUT reading any data block. Read moreSource§fn approximate_range_cardinality<K: AsRef<[u8]>, R: RangeBounds<K>>(
&self,
range: R,
seqno: SeqNo,
) -> Result<RangeCardinality>
fn approximate_range_cardinality<K: AsRef<[u8]>, R: RangeBounds<K>>( &self, range: R, seqno: SeqNo, ) -> Result<RangeCardinality>
range at seqno,
WITHOUT reading any data block. Read moreSource§fn get_highest_memtable_seqno(&self) -> Option<SeqNo>
fn get_highest_memtable_seqno(&self) -> Option<SeqNo>
Source§fn get_highest_seqno(&self) -> Option<SeqNo>
fn get_highest_seqno(&self) -> Option<SeqNo>
Source§fn get_highest_persisted_seqno(&self) -> Option<SeqNo>
fn get_highest_persisted_seqno(&self) -> Option<SeqNo>
Source§fn oldest_retained_seqno(&self) -> SeqNo
fn oldest_retained_seqno(&self) -> SeqNo
Source§fn retention_floor(&self) -> SeqNo
fn retention_floor(&self) -> SeqNo
oldest_retained_seqno. Read moreSource§fn lower_retention_floor(&self, floor: SeqNo) -> Result<()>
fn lower_retention_floor(&self, floor: SeqNo) -> Result<()>
floor, so snapshots above it
are served again, now and after a reopen. Read moreSource§fn compaction_rate_limiter(&self) -> Arc<RateLimiter> ⓘ
fn compaction_rate_limiter(&self) -> Arc<RateLimiter> ⓘ
Config::compaction_rate_limiter,
which other trees may share, or the tree’s own built from
Config::compaction_rate_limit. Read moreSource§fn write_rate_limiter(&self) -> Arc<RateLimiter> ⓘ
fn write_rate_limiter(&self) -> Arc<RateLimiter> ⓘ
Config::write_rate_limiter, else
the tree’s own. Retune it live with
RateLimiter::set_rate;
0 turns byte pacing off.Source§fn get<K: AsRef<[u8]>>(&self, key: K, seqno: SeqNo) -> Result<Option<UserValue>>
fn get<K: AsRef<[u8]>>(&self, key: K, seqno: SeqNo) -> Result<Option<UserValue>>
Source§fn contains_key<K: AsRef<[u8]>>(&self, key: K, seqno: SeqNo) -> Result<bool>
fn contains_key<K: AsRef<[u8]>>(&self, key: K, seqno: SeqNo) -> Result<bool>
true if the tree contains the specified key. Read moreSource§fn contains_prefix<K: AsRef<[u8]>>(
&self,
prefix: K,
seqno: SeqNo,
index: Option<(Arc<Memtable>, SeqNo)>,
) -> Result<bool>
fn contains_prefix<K: AsRef<[u8]>>( &self, prefix: K, seqno: SeqNo, index: Option<(Arc<Memtable>, SeqNo)>, ) -> Result<bool>
true if the tree contains any key with the given prefix. Read moreSource§fn is_empty(
&self,
seqno: SeqNo,
index: Option<(Arc<Memtable>, SeqNo)>,
) -> Result<bool>
fn is_empty( &self, seqno: SeqNo, index: Option<(Arc<Memtable>, SeqNo)>, ) -> Result<bool>
true if the tree is empty. Read moreSource§fn len(
&self,
seqno: SeqNo,
index: Option<(Arc<Memtable>, SeqNo)>,
) -> Result<usize>
fn len( &self, seqno: SeqNo, index: Option<(Arc<Memtable>, SeqNo)>, ) -> Result<usize>
Source§fn get_pinned<K: AsRef<[u8]>>(
&self,
key: K,
seqno: SeqNo,
) -> Result<Option<PinnableSlice>>
fn get_pinned<K: AsRef<[u8]>>( &self, key: K, seqno: SeqNo, ) -> Result<Option<PinnableSlice>>
PinnableSlice. Read moreSource§fn multi_get<K: AsRef<[u8]>>(
&self,
keys: impl IntoIterator<Item = K>,
seqno: SeqNo,
) -> Result<Vec<Option<UserValue>>>
fn multi_get<K: AsRef<[u8]>>( &self, keys: impl IntoIterator<Item = K>, seqno: SeqNo, ) -> Result<Vec<Option<UserValue>>>
Source§fn apply_batch(&self, batch: WriteBatch, seqno: SeqNo) -> Result<(u64, u64)>
fn apply_batch(&self, batch: WriteBatch, seqno: SeqNo) -> Result<(u64, u64)>
WriteBatch with the given sequence number. Read moreSource§fn insert<K: Into<UserKey>, V: Into<UserValue>>(
&self,
key: K,
value: V,
seqno: SeqNo,
) -> (u64, u64)
fn insert<K: Into<UserKey>, V: Into<UserValue>>( &self, key: K, value: V, seqno: SeqNo, ) -> (u64, u64)
Source§fn merge<K: Into<UserKey>, V: Into<UserValue>>(
&self,
key: K,
operand: V,
seqno: SeqNo,
) -> (u64, u64)
fn merge<K: Into<UserKey>, V: Into<UserValue>>( &self, key: K, operand: V, seqno: SeqNo, ) -> (u64, u64)
Source§fn remove<K: Into<UserKey>>(&self, key: K, seqno: SeqNo) -> (u64, u64)
fn remove<K: Into<UserKey>>(&self, key: K, seqno: SeqNo) -> (u64, u64)
Source§fn remove_range<K: Into<UserKey>>(&self, start: K, end: K, seqno: SeqNo) -> u64
fn remove_range<K: Into<UserKey>>(&self, start: K, end: K, seqno: SeqNo) -> u64
[start, end) by inserting a range tombstone. Read moreSource§fn level_segment_stats(&self) -> Result<Vec<LevelStats>>
fn level_segment_stats(&self) -> Result<Vec<LevelStats>>
Source§fn compaction_debt(&self, strategy: &dyn CompactionStrategy) -> u64
fn compaction_debt(&self, strategy: &dyn CompactionStrategy) -> u64
strategy: on-disk data above
its level’s target that must eventually be rewritten downward (a RocksDB
estimate-pending-compaction-bytes analog), a compaction-debt signal for a
scheduler / tiering consumer. Read moreSource§fn write_backpressure_for(
&self,
strategy: &dyn CompactionStrategy,
bytes: u64,
) -> Backpressure
fn write_backpressure_for( &self, strategy: &dyn CompactionStrategy, bytes: u64, ) -> Backpressure
bytes: write_backpressure,
except that a slowdown on a tree with a write rate limit (see
Config::write_rate_limit) debits
bytes from the tree’s write limiter and suggests waiting until they,
and every byte debited before them, are paid off at its rate. Writes
honouring it are then bounded by the rate in bytes per second, large
and small alike, however many writers share the limiter. Outside the
slowdown tier nothing is debited. Read moreSource§fn is_read_only(&self) -> bool
fn is_read_only(&self) -> bool
true when the admission gate is currently closed (see
write_admission). Convenience for callers that
want a boolean rather than a Result. Always false unless admission
control is enabled and the tree is over budget. Read moreSource§fn verify_checksum(&self) -> BlockVerifyReportwhere
Self: Sized,
fn verify_checksum(&self) -> BlockVerifyReportwhere
Self: Sized,
Source§fn verify_checksum_with(&self, options: &VerifyOptions) -> BlockVerifyReportwhere
Self: Sized,
fn verify_checksum_with(&self, options: &VerifyOptions) -> BlockVerifyReportwhere
Self: Sized,
Self::verify_checksum but with configurable parallelism and
I/O throttle (see VerifyOptions).Source§fn flush_active_memtable(&self, gc_watermark: SeqNo) -> Result<()>
fn flush_active_memtable(&self, gc_watermark: SeqNo) -> Result<()>
Source§fn sync_devices(&self) -> Result<()>
fn sync_devices(&self) -> Result<()>
Source§fn flush(
&self,
_lock: &MutexGuard<'_, ()>,
gc_watermark: SeqNo,
) -> Result<Option<u64>>
fn flush( &self, _lock: &MutexGuard<'_, ()>, gc_watermark: SeqNo, ) -> Result<Option<u64>>
Source§fn iter(
&self,
seqno: SeqNo,
index: Option<(Arc<Memtable>, SeqNo)>,
) -> Box<dyn DoubleEndedIterator<Item = IterGuardImpl> + Send + 'static>
fn iter( &self, seqno: SeqNo, index: Option<(Arc<Memtable>, SeqNo)>, ) -> Box<dyn DoubleEndedIterator<Item = IterGuardImpl> + Send + 'static>
Source§fn major_compact(
&self,
target_size: u64,
gc_watermark: SeqNo,
) -> Result<CompactionResult>
fn major_compact( &self, target_size: u64, gc_watermark: SeqNo, ) -> Result<CompactionResult>
Source§fn stale_blob_bytes(&self) -> u64
fn stale_blob_bytes(&self) -> u64
Source§fn flush_to_tables(
&self,
stream: impl Iterator<Item = Result<InternalValue>>,
) -> Result<Option<(Vec<Table>, Option<Vec<BlobFile>>, WritePin)>>
fn flush_to_tables( &self, stream: impl Iterator<Item = Result<InternalValue>>, ) -> Result<Option<(Vec<Table>, Option<Vec<BlobFile>>, WritePin)>>
Source§fn first_key_value(
&self,
seqno: SeqNo,
index: Option<(Arc<Memtable>, SeqNo)>,
) -> Option<IterGuardImpl>
fn first_key_value( &self, seqno: SeqNo, index: Option<(Arc<Memtable>, SeqNo)>, ) -> Option<IterGuardImpl>
Source§fn last_key_value(
&self,
seqno: SeqNo,
index: Option<(Arc<Memtable>, SeqNo)>,
) -> Option<IterGuardImpl>
fn last_key_value( &self, seqno: SeqNo, index: Option<(Arc<Memtable>, SeqNo)>, ) -> Option<IterGuardImpl>
Source§fn try_insert<K: Into<UserKey>, V: Into<UserValue>>(
&self,
key: K,
value: V,
seqno: SeqNo,
) -> Result<(u64, u64)>
fn try_insert<K: Into<UserKey>, V: Into<UserValue>>( &self, key: K, value: V, seqno: SeqNo, ) -> Result<(u64, u64)>
insert: consults
write_admission first and declines with
Error::StorageFull when the tree is over
budget, otherwise inserts and returns the same (added_bytes, memtable_size) tuple. This is the write entry a space-aware caller uses
so over-budget writes are refused up front rather than failing a flush
later; bare insert stays infallible for callers that
do not opt into admission control. Read moreSource§fn try_merge<K: Into<UserKey>, V: Into<UserValue>>(
&self,
key: K,
operand: V,
seqno: SeqNo,
) -> Result<(u64, u64)>
fn try_merge<K: Into<UserKey>, V: Into<UserValue>>( &self, key: K, operand: V, seqno: SeqNo, ) -> Result<(u64, u64)>
Auto Trait Implementations§
impl !RefUnwindSafe for Tree
impl !UnwindSafe for Tree
impl Freeze for Tree
impl Send for Tree
impl Sync for Tree
impl Unpin for Tree
impl UnsafeUnpin for Tree
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> Pointable for T
impl<T> Pointable for T
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<T> StorageStatistics for Twhere
T: AbstractTree + ?Sized,
impl<T> StorageStatistics for Twhere
T: AbstractTree + ?Sized,
Source§fn storage_stats(&self) -> Result<StorageStats, Error>
fn storage_stats(&self) -> Result<StorageStats, Error>
StorageStatus. See
StorageStats::estimated_remaining_entries for a budget projection. Read moreSource§fn level_segment_stats(&self) -> Result<Vec<LevelStats>, Error>
fn level_segment_stats(&self) -> Result<Vec<LevelStats>, Error>
Source§fn compaction_debt(&self, strategy: &dyn CompactionStrategy) -> u64
fn compaction_debt(&self, strategy: &dyn CompactionStrategy) -> u64
strategy: on-disk data above
its level’s target that must eventually be rewritten downward (a RocksDB
estimate-pending-compaction-bytes analog), a compaction-debt signal for a
scheduler / tiering consumer. Read moreSource§fn cache_stats(&self) -> CacheStats
fn cache_stats(&self) -> CacheStats
CacheStats snapshot of block-cache
effectiveness (cumulative hit / miss counts and rate) and occupancy
(current size against capacity). Read more