Expand description
Tokio-friendly async wrapper around spg-embedded.
§Why this crate exists
spg-embedded’s Database::execute(&mut self, sql) is sync
and may block on WAL fsync or cold-tier I/O. Called from
inside a tokio::main runtime that triggers the
block_in_place warning and ties up a worker thread until the
call returns. mailrs’s cement (entirely tokio-based) is the
load-bearing consumer that surfaced this.
v7.18 — AsyncDatabase holds a tokio::sync::RwLock<Database>
(upgraded from Mutex). Writer calls take the write lock —
the engine is still single-writer, that invariant hasn’t
changed. Snapshot-taking (read_handle init / refresh) only
needs read access to clone_snapshot, so it takes the read
lock and concurrent snapshot refreshes do not serialise.
spawn_blocking insulates the runtime’s worker pool from
disk stalls the same way it did under Mutex.
§Why a separate crate
spg-embedded keeps the workspace’s “0 external dependencies”
policy. tokio is the largest external dep we’d ever pull,
and gating it behind a Cargo feature flag still surfaces
tokio in downstream consumers’ Cargo.lock. A separate
adapter crate is the clean answer: anyone who wants the
tokio shape opts in by adding spg-embedded-tokio; everyone
else stays untouched.
Structs§
- Async
Database - Tokio-friendly handle to an embedded SPG database. Clone-cheap
(
Arcinside); every clone shares the same underlying engine. - Async
Read Handle - v7.11.2 — read-only handle backed by a frozen
CatalogSnapshot. Multiple handles can run concurrently; they don’t acquire the writer lock at query time. Refresh-on-demand — the contract is that the handle reflects committed state at the moment of construction or the lastrefresh(). - Async
Statement - v7.16.0 — Tokio-flavoured prepared-statement handle. Wraps
the sync
spg_embedded::Statementin anArcso the AST is shared (not cloned) acrossexecute_prepared/query_preparedcalls, and so the handle isClone + Sendwithout copying the AST per bind. The engine’s per-bind internal clone still happens — that’s where placeholder substitution lands — but the spg-embedded-tokio surface avoids the second clone the naive shape would force. - Catalog
Snapshot - v7.11.0 — frozen read-only view of the engine’s committed state.
Constructed via
Engine::clone_snapshot. Holds clones of the catalog, statistics, clock function, and row-cap config — the four fields theexecute_readonlypath actually reads. Cheap toClone(each clone shares the underlyingPersistentVecrow storage; only the trie root pointers copy). Send + Sync so a snapshot can be moved acrosstokio::task::spawn_blockingboundaries without coordination. - Column
Schema - Database
- Embedded SPG database handle. Owns an
Engine+ provides ergonomic wrappers aroundexecuteandquery. Drops the engine onDrop— no WAL flush / fsync, because v6.10.3 is in-memory only. - Statement
- v7.16.0 — handle for a parsed-and-planned SQL statement.
Hand off to
Database::execute_prepared/Database::query_preparedwith a&[Value]slice carrying the bind parameters (PG-style$1,$2, … positional). Cheap toClone; the underlying AST is shared by handle copies and cloned per bind call by the engine’s executor.
Enums§
- Data
Type - Runtime type tags.
Vector { dim, encoding }/Varchar(max)/Char(size)are parameterised; the parameter travels with both the column schema and the on-wire serialised representation. - Engine
Error - All errors the engine can return.
- Parsed
Statement - Query
Result - Result of executing one statement.
- Value
- A row-cell value, including SQL
NULL.Floatusesf64; NaN compares non-equal to itself (PG behaviour) —PartialEqis derived so callers must opt into NaN-aware comparison if they need stronger guarantees.