The embeddable, in-process Quiver database handle.
[Database] composes the storage engine ([quiver_core::Store]) with a
per-collection vector index and payload filtering ([quiver_query::Filter])
into one handle. It exposes the same logical operations the server speaks
(docs/api/wire-protocol.md), so library mode and server mode exercise
identical engine semantics — the server is a thin transport/policy shell.
Index lifecycle
The store is the source of truth. Each collection chooses its index via the
descriptor's [IndexSpec] (default in-memory HNSW); the index is built from
the store on open. HNSW applies new-id inserts incrementally; once an IVF
index is built it applies inserts, in-place updates, and deletes
incrementally with LIRE rebalancing (ADR-0023). The Vamana / disk graph
family is maintained the FreshDiskANN way (ADR-0033): the batch-built graph
is a read-only base, recent inserts land in an in-memory delta graph, and
deletes are tombstoned, so writes are size-independent; when the pending work
grows past a fixed fraction of the base the next access consolidates by
rebuilding from the store. All indexes stay derived (rebuilt from the store
on open), so the crash gate never sees an index write.
Filtered (hybrid) search
A search may carry a [quiver_query::Filter] over the payload. The planner
decomposes it into the predicates the collection's secondary indexes can
answer; when those narrow the query to a small candidate set it scans that
set exactly (perfect recall, no filtered-ANN cliff), and otherwise it
over-fetches from the ANN index and post-filters. Both arms re-check the full
filter, so results are exact regardless of which path runs.
Concurrency (ADR-0057 / ADR-0062)
Single-writer. Writes take &mut self. Reads come in two flavors: the
&mut self convenience methods (search, hybrid_search,
search_multi_vector) rebuild a stale index in place and so give embedded,
single-threaded callers read-your-writes; the &self *_snapshot methods
read the current immutable snapshot and run concurrently, serving the
prior snapshot when a write deferred a rebuild (snapshot-isolated, slightly
stale). A server therefore serves concurrent reads behind a reader–writer lock,
and rebuilds off the exclusive lock (ADR-0062): it captures the rebuild
inputs under the shared lock ([Database::snapshot_rebuild_inputs]), builds the
new index with no lock held ([RebuildInputs::build]), and installs it under a
brief write lock ([Database::commit_rebuild]) — so a rebuild never stalls
concurrent readers.