pub struct Db {
pub objects: ObjectStore,
pub id_index: IdIndex,
pub sorted_indexes: SortedIndexes,
pub graph: GraphStore,
pub root: PathBuf,
pub seq: Atomic<u64>,
pub startup_ready: Arc<Atomic<bool>>,
/* private fields */
}Fields§
§objects: ObjectStore§id_index: IdIndex§sorted_indexes: SortedIndexes§graph: GraphStore§root: PathBuf§seq: Atomic<u64>§startup_ready: Arc<Atomic<bool>>True once startup is fully ready (MANIFEST loaded or cold scan complete). Warm starts set this true before returning from open(). Cold starts set this true in the background thread when scan completes. Writes are held with 503 until this is true; reads always proceed.
Implementations§
Source§impl Db
impl Db
Sourcepub fn in_memory() -> Db
pub fn in_memory() -> Db
Create a pure in-memory database — no disk I/O, no migration, instant startup. Perfect for tests, hot-cache layers, and ephemeral sessions. All data is lost when the Db is dropped.
Sourcepub fn open(db_root: &Path, dek: Option<Dek>) -> Result<Db, Error>
pub fn open(db_root: &Path, dek: Option<Dek>) -> Result<Db, Error>
Open (or create) a database. Runs v1→v2 migration automatically if log.aof is present.
Sourcepub fn start_cold_scan(self_arc: Arc<Db>)
pub fn start_cold_scan(self_arc: Arc<Db>)
Call this from Manager::open_all() after Arc::new(db). Spawns the cold scan background thread with stable heap addresses. No-op if startup is already complete (warm start).
Sourcepub fn put(
&self,
coll: &str,
id: &str,
data: Value,
caused_by: Vec<String>,
valid_from: Option<String>,
valid_to: Option<String>,
) -> Result<Node, Error>
pub fn put( &self, coll: &str, id: &str, data: Value, caused_by: Vec<String>, valid_from: Option<String>, valid_to: Option<String>, ) -> Result<Node, Error>
Write a document. Returns the new node with its content hash set.
Sourcepub fn put_batch(
&self,
ops: Vec<(String, String, Value, Vec<String>, Option<String>, Option<String>)>,
) -> Result<Vec<Node>, Error>
pub fn put_batch( &self, ops: Vec<(String, String, Value, Vec<String>, Option<String>, Option<String>)>, ) -> Result<Vec<Node>, Error>
Batch put: write N documents in parallel, preserving monotonic seq ordering. Pre-allocates N seq numbers atomically, then parallelises object writes and id-index updates via Rayon. Each op is independent — safe to parallelise. Returns nodes in input order with assigned seq numbers.
Sourcepub fn compact(&self) -> Result<CompactStats, Error>
pub fn compact(&self) -> Result<CompactStats, Error>
Compact the v3 packed object store: keep the CURRENT version of every
document (from the id-index) and reclaim everything else. No-op unless
running with the v3 segment substrate (--dag-v3 / NEDB_DAG_V3).
This is a PRUNING operation: superseded/historical object versions are dropped, so AS OF / TRACE over pruned versions is discarded — that is what reclaims the space. Flushes first so all data is durable on disk before the old segments are deleted.
Sourcepub fn flush_manifest_if_dirty(&self)
pub fn flush_manifest_if_dirty(&self)
Flush MANIFEST to disk if dirty. No-op for in-memory databases.
Sourcepub fn flush_manifest(&self)
pub fn flush_manifest(&self)
Atomically persist current seq+head to MANIFEST. No-op for in-memory databases.
Sourcepub fn start_manifest_ticker(self_arc: Arc<Db>, interval_ms: u64)
pub fn start_manifest_ticker(self_arc: Arc<Db>, interval_ms: u64)
Start a background thread that flushes both the id-index WAL and MANIFEST
every interval_ms milliseconds.
Call this after Arc::new(db) — the Arc keeps Db alive for the thread’s lifetime.
Sourcepub fn delete(&self, coll: &str, id: &str) -> Result<bool, Error>
pub fn delete(&self, coll: &str, id: &str) -> Result<bool, Error>
Delete a document — writes a tombstone node and removes the id from the index. The object history is preserved in the DAG; only the live id pointer is cleared.
Sourcepub fn get(&self, coll: &str, id: &str) -> Option<Node>
pub fn get(&self, coll: &str, id: &str) -> Option<Node>
Get the current version of a document by id.
Sourcepub fn get_by_hash(&self, hash: &str) -> Option<Node>
pub fn get_by_hash(&self, hash: &str) -> Option<Node>
Get a specific version of a document by object hash.
Sourcepub fn get_as_of(&self, coll: &str, id: &str, target_seq: u64) -> Option<Node>
pub fn get_as_of(&self, coll: &str, id: &str, target_seq: u64) -> Option<Node>
Get a document AS OF a specific sequence number. Walks the version chain (prev links) backward until seq <= target.
Sourcepub fn list(&self, coll: &str) -> Vec<Node>
pub fn list(&self, coll: &str) -> Vec<Node>
List all documents in a collection, returning current versions.
Sourcepub fn order_by_asc(&self, coll: &str, field: &str, limit: usize) -> Vec<Node>
pub fn order_by_asc(&self, coll: &str, field: &str, limit: usize) -> Vec<Node>
ORDER BY field ASC LIMIT n — uses sorted index if available, else falls back to full scan.
Sourcepub fn order_by_desc(&self, coll: &str, field: &str, limit: usize) -> Vec<Node>
pub fn order_by_desc(&self, coll: &str, field: &str, limit: usize) -> Vec<Node>
ORDER BY field DESC LIMIT n
Sourcepub fn trace(&self, hash: &str, reverse: bool, limit: usize) -> Vec<Node>
pub fn trace(&self, hash: &str, reverse: bool, limit: usize) -> Vec<Node>
TRACE caused_by — walk causal graph from a node.
Sourcepub fn create_sorted_index(&self, coll: &str, field: &str)
pub fn create_sorted_index(&self, coll: &str, field: &str)
Create a sorted index for a (coll, field) pair.
Sourcepub fn get_hash_by_seq(&self, seq: u64) -> Option<String>
pub fn get_hash_by_seq(&self, seq: u64) -> Option<String>
Resolve a sequence number to its content hash (v1 compatibility). Only covers nodes written in the current process session + cold-scan nodes.
Sourcepub fn tip(&self) -> Option<Node>
pub fn tip(&self) -> Option<Node>
The tip — the most recently written node (highest seq), or None if the
database is empty. O(1): self.seq is the next-to-assign counter, so the
latest write sits at seq - 1; we resolve it through the same
seq_index → object-store path a normal read uses, so the returned Node is
byte-identical to one fetched by id or hash (it carries its own seq, hash,
causal links, and valid-time). This is the cheap “give me the latest write”
primitive — the head of the log, not an aggregate.
Sourcepub fn tip_collection(&self, coll: &str) -> Option<Node>
pub fn tip_collection(&self, coll: &str) -> Option<Node>
The collection-local tip — the most recent write into coll (highest seq in
that collection), or None if the collection has no writes. Scans the seq
index backward from the head until a node in coll is found, resolving
through the same seq_index → object-store path as a normal read; bounded by
how recently coll was written. Conceptually a different index than the
global tip() (global head vs collection head), kept as a separate method
so each is explicit — parity with the Python reference’s tip(coll). Lets a
consumer resume one chain (e.g. blocks / tx / utxo) without pulling global
tip and filtering.
Sourcepub fn since(&self, after_seq: u64, limit: usize) -> SinceBatch
pub fn since(&self, after_seq: u64, limit: usize) -> SinceBatch
Changefeed page: up to limit nodes written AFTER after_seq (EXCLUSIVE),
ascending by seq, wrapped in a SinceBatch cursor envelope. after_seq is
the cursor you last applied (a prior tip() seq or to_seq). limit bounds
the page — 0 means DEFAULT_SINCE_LIMIT, so the engine primitive can never
materialize an unbounded batch even when embedders call it directly (the
safety is here, not only in the HTTP layer). Drain by paging while
has_more, advancing your cursor to to_seq, then hand off to the live
subscribe edge. The append-only log IS the changefeed, so this is an
O(page) walk; unresolved seqs (outside seq_index coverage — see
scan_status()) are skipped rather than faked.
Sourcepub fn scan_status(&self) -> ScanStatus
pub fn scan_status(&self) -> ScanStatus
Replication readiness — see ScanStatus. scan_complete gates safe
historical catch-up: a consumer pulling an old cursor right after a cold
start must wait for it, or since() may hand back a partial page that looks
like “caught up”. Computes the indexed range by scanning the in-memory seq
index (O(index)) — intended for periodic status polls, not the per-write
hot path.
Sourcepub fn link(&self, frm: &str, rel: &str, to: &str) -> Result<(), Error>
pub fn link(&self, frm: &str, rel: &str, to: &str) -> Result<(), Error>
Add an explicit named relation edge between two documents. Add an explicit named relation between two “coll:id” nodes. Relations stored as links documents — NQL-queryable, time-travelable, consistent with the PyO3 binding which uses the same links convention.
Source§impl Db
impl Db
Sourcepub fn install_exit_flush(self_arc: Arc<Db>)
pub fn install_exit_flush(self_arc: Arc<Db>)
Flush this durable database’s buffered state on SIGINT/SIGTERM
(Ctrl+C, kill, orchestrator shutdown) — the flush-on-close contract
extended to hard exits that never run Drop.
Call once, after the database is wrapped in an Arc (the registry holds a
Weak, so this never keeps the Db alive). Idempotent; safe to call from
multiple databases. A no-op for in-memory (:memory:) databases.
let db = Arc::new(Db::open(std::path::Path::new("/data/mydb"), None)?);
Db::install_exit_flush(Arc::clone(&db)); // durable across Ctrl+C / SIGTERMTrait Implementations§
Source§impl Drop for Db
impl Drop for Db
Source§fn drop(&mut self)
fn drop(&mut self)
Flush buffered state when the database is closed so a write-then-drop
sequence is durable without an explicit flush_all().
IdIndex::set only stages updates in the in-memory WAL write_buf;
disk persistence happens in flush_write_buf(), normally driven by the
manifest ticker. A short-lived Db (a library user’s { let db = Db::open(p)?; db.put(..)?; } block, or a test) has no ticker, so without
this its writes would be silently lost on reopen. Flushing on drop
mirrors the flush-on-close contract of other embedded stores (sled,
RocksDB).
In production this is a harmless safety net, not the primary durability
path: the manifest ticker thread holds an Arc<Db> for the process
lifetime, so Drop only fires once every owning handle is gone. No-op
for in-memory databases (flush_all short-circuits on :memory:).
Auto Trait Implementations§
impl !Freeze for Db
impl !RefUnwindSafe for Db
impl !UnwindSafe for Db
impl Send for Db
impl Sync for Db
impl Unpin for Db
impl UnsafeUnpin for Db
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<A, B, T> HttpServerConnExec<A, B> for Twhere
B: Body,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
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 more