TessariDBDocs
  • 0.35.3latest
  • 0.35.2
  • 0.35.1
  • 0.35.0
  • 0.34.4
  • 0.34.3-beta
  • 0.34.2-beta
  • 0.34.1-beta
  • 0.34.0-beta
  • 0.33.4-beta
  • 0.33.3-beta
  • 0.33.2-beta
  • 0.33.1-beta
  • 0.33.0-beta
  • 0.32.0-beta

Reads and snapshots

Point reads, many-key reads, paged scans, many-range scans and bounded iterators — each at one consistent snapshot — plus held snapshots and the read options.

Every read sees one snapshot: the database as it was at one sequence number. A read never sees half of a batch, and a read that spans many keys sees them all at the same moment.

One key

use tessarikv::{Db, KeyspaceId, ReadOptions};

async fn stock(db: &Db) -> tessarikv::Result<Option<Vec<u8>>> {
    db.get(KeyspaceId::DEFAULT, b"sku:1001", &ReadOptions::default()).await
}

get returns None for a key that is absent or deleted.

Many keys

multi_get reads many keys at one snapshot and returns the values in the order the keys were given.

use tessarikv::{Db, KeyspaceId, ReadOptions};

async fn stock_of_three(db: &Db) -> tessarikv::Result<Vec<Option<Vec<u8>>>> {
    let keys: [&[u8]; 3] = [b"sku:1001", b"sku:1002", b"sku:1003"];
    db.multi_get(KeyspaceId::DEFAULT, keys, &ReadOptions::default()).await
}

A range, page by page

scan(keyspace, start, end, limit, options) returns a ScanPage: up to limit pairs, ascending by key, from start up to but not including end (None reaches the end of the keyspace). When the page stopped at its limit, page.next is the key the next page starts at.

use tessarikv::{Db, KeyspaceId, ReadOptions};

async fn every_sku(db: &Db) -> tessarikv::Result<usize> {
    let options = ReadOptions::default();
    let mut start = b"sku:".to_vec();
    let mut seen = 0;
    loop {
        let page = db.scan(KeyspaceId::DEFAULT, &start, Some(b"sku;"), 100, &options).await?;
        seen += page.entries.len();
        match page.next {
            Some(next) => start = next,
            None => return Ok(seen),
        }
    }
}

Each page is read at its own snapshot. To read several pages at one moment, take a snapshot and scan through it.

multi_scan reads several ranges, each a ScanRange { start, end, limit }, at one snapshot and returns one page per range.

Iterators

Db::iter(keyspace, options) returns a DbIterator positioned nowhere. Seek first, then step:

  • seek_to_first, seek_to_last, seek(key) (first key at or after key), seek_for_prev(key) (last key at or before key);
  • next, prev;
  • valid, key, value.
use tessarikv::{Db, KeyspaceId, ReadOptions};

async fn users(db: &Db) -> tessarikv::Result<Vec<Vec<u8>>> {
    // Bounds the iterator to the keys that start with "user/".
    let options = ReadOptions::default().with_prefix(b"user/");
    let mut iterator = db.iter(KeyspaceId::DEFAULT, &options)?;
    let mut keys = Vec::new();
    iterator.seek_to_first().await?;
    while iterator.valid() {
        keys.push(iterator.key().to_vec());
        iterator.next().await?;
    }
    Ok(keys)
}

An iterator holds its snapshot for as long as it lives.

Snapshots

Db::snapshot() returns a Snapshot that keeps one moment readable. It offers the same reads as the database: get, multi_get, scan, multi_scan and iter. sequence() is the sequence number it reads at.

use tessarikv::{Db, KeyspaceId, ReadOptions};

async fn consistent_pair(db: &Db) -> tessarikv::Result<(Option<Vec<u8>>, Option<Vec<u8>>)> {
    let snapshot = db.snapshot()?;
    let options = ReadOptions::default();
    let order = snapshot.get(KeyspaceId::DEFAULT, b"order:9", &options).await?;
    let stock = snapshot.get(KeyspaceId::DEFAULT, b"sku:1001", &options).await?;
    Ok((order, stock))
}

The snapshot is released when it is dropped. While it lives, compaction keeps every version it can see, so a forgotten snapshot keeps old data on disk. Db::oldest_snapshot() reports the sequence of the oldest one still held, by a snapshot, an iterator or a transaction. Watch it as a metric; it walks every registered snapshot, so do not call it per request.

Read options

FieldDefaultEffect
verify_checksumstrueverify the checksum of every block read from a table; off, a corrupt block decodes to an error or to wrong data instead of a Corruption error
fill_cachetruekeep the blocks this read loads in the block cache; a one-off scan sets it to false so it does not evict the working set
lower_boundNonethe least key an iterator shows, inclusive
upper_boundNonethe key an iterator stops before, exclusive

The bounds apply to iterators only. Point reads and scans take their range as arguments. with_prefix(prefix) sets both bounds to the keys that start with prefix.

Size of a range

Db::approximate_size(keyspace, start, end) estimates the bytes a range takes in table files, from the table indexes, without reading data blocks.