Skip to main content

Database

Struct Database 

Source
pub struct Database<S> { /* private fields */ }
Expand description

Owns the graph store and orchestrates parse → analyze → compile → execute.

Optionally drives a write-ahead log: when constructed via Database::open_with_wal or Database::recover the database holds an Arc<WalRecorder> that brackets every query with begin → mutations → commit/abort → flush while the store write lock is held, so the WAL order is exactly the in-memory commit order. When constructed via Database::in_memory / Database::from_graph the WAL handle is None and the engine pays only the existing MutationRecorder::record null-pointer check per mutation.

Implementations§

Source§

impl Database<InMemoryGraph>

Source

pub fn in_memory() -> Self

Convenience constructor: a fresh, empty in-memory graph database.

Source

pub fn open_with_wal(wal_config: WalConfig) -> Result<Self>

Open or create a WAL-enabled in-memory database from a fresh graph.

WalConfig::Disabled falls back to Database::in_memory. Otherwise, opens the WAL directory, replays any committed events into a fresh graph, installs a WalRecorder on the graph, and returns a database ready to serve queries.

To restore from a snapshot in addition to the WAL, use Database::recover instead.

Source

pub fn open_named( database_name: impl AsRef<str>, options: DatabaseOpenOptions, ) -> Result<Self>

Open or create a named portable database rooted under options.database_dir.

The database name may be either a portable basename (app or app.loradb) or a safe relative path (tenant/app). It is resolved under options.database_dir before the WAL archive backend opens.

Source

pub fn begin_transaction( &self, mode: TransactionMode, ) -> Result<Transaction<'_>>

Start an explicit transaction.

Read-only transactions hold a shared read lock for their lifetime; read-write transactions hold the write lock. The staging clone is lazy — it only happens when a TransactionMode::ReadWrite transaction sees its first mutating statement. Materialized read-only statements run straight against the live graph; tx-bound streams may still clone so their cursors can own a stable view. ReadWrite transactions that perform only materialized reads (or commit empty) pay nothing for staging.

Source

pub fn sync(&self) -> Result<()>

Force any pending WAL bytes to durable storage and, for archive-backed databases, refresh the portable .loradb file before returning.

Source

pub fn recover( snapshot_path: impl AsRef<Path>, wal_config: WalConfig, ) -> Result<Self>

Restore from a snapshot file then replay any WAL records past it.

The snapshot’s wal_lsn (when set) becomes the replay fence — events at or below that LSN are already represented in the loaded snapshot and are skipped. A missing snapshot file is treated as “fresh start” so operators can pass the same path on every boot.

If the WAL contains a checkpoint marker newer than the snapshot’s wal_lsn, a one-line warning is printed to stderr — the snapshot is stale relative to a more recent checkpoint the operator is presumably aware of. Recovery still proceeds from the snapshot’s fence (replay re-applies every record above it, which is conservative-correct); a tighter contract is deferred to v2 because verifying that the marker’s snapshot file actually exists and is loadable is a separate observability concern.

Source

pub fn stream(&self, query: &str) -> Result<QueryStream<'_>>

Execute a query and return an owning row stream.

Source

pub fn stream_with_params( &self, query: &str, params: BTreeMap<String, LoraValue>, ) -> Result<QueryStream<'_>>

Execute a parameterised query and return an owning row stream.

The compiled plan is classified at open time. Read-only queries run directly off the live store and yield a buffered cursor with plan-derived columns. Mutating queries are routed through a hidden read-write Transaction: full cursor exhaustion calls tx.commit (publishing staged changes and replaying the tx-local WAL buffer); a premature drop or any error from next_row calls tx.rollback so the live store and the WAL stay untouched.

Source

pub unsafe fn stream_with_params_owned( self: &Arc<Self>, query: &str, params: BTreeMap<String, LoraValue>, ) -> Result<QueryStream<'static>>

Open a stream whose lifetime can be carried by an outer owner that also retains an Arc<Database>.

§Safety

The returned stream may contain lock guards that borrow from the database’s internal RwLock. The caller must keep this exact Arc alive until the stream is dropped. This is intended for language bindings that store both the Arc<Database> and the QueryStream in the same opaque stream handle.

Source§

impl<S> Database<S>

Source

pub fn new(store: Arc<RwLock<S>>) -> Self

Build a database from a pre-wrapped, shared store.

Source

pub fn from_graph(graph: S) -> Self

Build a database by taking ownership of a bare graph store.

Source

pub fn wal(&self) -> Option<&Arc<WalRecorder>>

Handle to the installed WAL recorder, if any. Exposed for admin paths (checkpoint, truncate, observability) that need to drive the WAL outside the standard query lifecycle.

Source

pub fn store(&self) -> &Arc<RwLock<S>>

Handle to the underlying shared store — useful for callers that need to snapshot or share the graph across multiple databases.

Source

pub fn parse(&self, query: &str) -> Result<Document>

Parse a query string into an AST without executing it.

Source

pub fn execute( &self, query: &str, options: Option<ExecuteOptions>, ) -> Result<QueryResult>

Execute a query and return its result.

Source

pub fn execute_with_timeout( &self, query: &str, options: Option<ExecuteOptions>, timeout: Duration, ) -> Result<QueryResult>

Execute a query with a cooperative deadline. The timeout is checked at executor operator boundaries and hot scan loops; if it fires, the query returns an error and any WAL-backed mutating query is aborted through the existing failure path.

Source

pub fn execute_with_params( &self, query: &str, options: Option<ExecuteOptions>, params: BTreeMap<String, LoraValue>, ) -> Result<QueryResult>

Execute a query with bound parameters.

When a WAL is attached the call is bracketed by a transaction:

  1. recorder.arm() after analyze + compile (so a parse / semantic / compile error never opens a tx that has to be immediately aborted). Arming is cheap: no record is appended to the WAL yet, so a pure read query that completes here pays nothing for the WAL hot path.
  2. The executor runs; every primitive mutation fires MutationRecorder::record, which buffers events in memory.
  3. On Ok, recorder.commit() writes TxBegin, one batched mutation record, and TxCommit only when mutations occurred; the surrounding recorder.flush() runs only in that case so a read-only query never pays an fsync.
  4. On Err, recorder.abort() clears the pending batch. The engine has no rollback, so the in-memory state may already be partially mutated; the live handle is quarantined while durable recovery stays atomic because no committed batch was written.
  5. The recorder’s poisoned flag is polled once (it also surfaces background-flusher fsync failures from SyncMode::Group). If set, the query fails loudly with the durability error so the caller can act on it; the WAL refuses further appends until the operator restarts the database, which recovers from the last consistent snapshot + WAL.
Source

pub fn execute_with_params_timeout( &self, query: &str, options: Option<ExecuteOptions>, params: BTreeMap<String, LoraValue>, timeout: Duration, ) -> Result<QueryResult>

Execute a parameterised query with a cooperative deadline.

Source

pub fn execute_rows(&self, query: &str) -> Result<Vec<Row>>

Execute a query and return hydrated rows before final result-format projection.

Source

pub fn execute_rows_with_params( &self, query: &str, params: BTreeMap<String, LoraValue>, ) -> Result<Vec<Row>>

Execute a query with parameters and return hydrated rows before final result-format projection.

Source

pub fn try_clear(&self) -> Result<()>

Drop every node and relationship, returning WAL/archive errors to the caller.

When a WAL is attached, the clear is wrapped in arm/commit so the MutationEvent::Clear fired by the store reaches the log inside a transaction. If a failure happens after the in-memory graph has been cleared, the recorder is poisoned by the failing WAL path and future writes fail until the database is reopened from durable state.

Source

pub fn clear(&self)

Drop every node and relationship.

This compatibility helper keeps the historical infallible Rust API. Bindings that can report errors should call Self::try_clear.

Source

pub fn node_count(&self) -> usize

Number of nodes currently in the graph.

Source

pub fn relationship_count(&self) -> usize

Number of relationships currently in the graph.

Source

pub fn with_store<R>(&self, f: impl FnOnce(&S) -> R) -> R

Run a closure with a shared borrow of the underlying store. Used by bindings to answer ad-hoc queries without locking the RwLock themselves.

Source

pub fn with_store_mut<R>(&self, f: impl FnOnce(&mut S) -> R) -> R

Run a closure with an exclusive borrow of the underlying store. Reserved for admin paths (restore, bulk load); regular mutation goes through execute_with_params.

Source§

impl<S> Database<S>

Source

pub fn save_snapshot_to(&self, path: impl AsRef<Path>) -> Result<SnapshotMeta>

Serialize the current graph state to the given path. Writes are atomic: the payload goes to <path>.tmp, is fsync’d, and then renamed over the target; a torn write can never leave a half-written file at path. If any step before the rename fails, the stale <path>.tmp is removed so a crashed save never leaks scratch files.

Holds a store read lock for the duration of the save so concurrent readers can proceed and writers wait behind a consistent snapshot.

Source

pub fn load_snapshot_from(&self, path: impl AsRef<Path>) -> Result<SnapshotMeta>

Replace the current graph state with a snapshot loaded from path. Holds the store write lock for the duration of the load; concurrent queries block until restore completes.

Source§

impl Database<InMemoryGraph>

Source

pub fn in_memory_from_snapshot(path: impl AsRef<Path>) -> Result<Self>

Convenience constructor: open (or create) an empty in-memory database and immediately restore it from path. Errors if the file cannot be opened or the snapshot is malformed.

Source

pub fn checkpoint_to(&self, path: impl AsRef<Path>) -> Result<SnapshotMeta>

Take a checkpoint: snapshot the current state with the WAL’s durable_lsn stamped into the header, append a Checkpoint marker to the WAL, then drop sealed segments at or below the fence.

Errors with “checkpoint requires WAL enabled” when called on a database constructed without a WAL — operators that just want a fence-less dump should use [save_snapshot_to] instead.

The write-lock-held window covers snapshot serialization plus the checkpoint marker append. Truncation runs after the rename but still under the write lock; making it concurrent with queries is a v2 concern (see docs/decisions/0004-wal.md).

Trait Implementations§

Source§

impl<S> QueryRunner for Database<S>
where S: GraphStorage + GraphStorageMut + Send + Sync + 'static,

Source§

fn execute( &self, query: &str, options: Option<ExecuteOptions>, ) -> Result<QueryResult>

Source§

impl<S> SnapshotAdmin for Database<S>
where S: GraphStorage + GraphStorageMut + Snapshotable + Send + Sync + 'static,

Source§

impl WalAdmin for Database<InMemoryGraph>

Source§

fn checkpoint(&self, path: &Path) -> Result<SnapshotMeta>

Take a checkpoint at path. The snapshot’s header is stamped with the WAL’s durable_lsn; older sealed segments are then dropped.
Source§

fn wal_status(&self) -> Result<WalStatus>

Snapshot of the WAL’s current state — durable / next LSN, active / oldest segment id. Cheap; a single WAL mutex acquisition.
Source§

fn wal_truncate(&self, fence_lsn: u64) -> Result<()>

Drop sealed segments at or below fence_lsn. Idempotent.

Auto Trait Implementations§

§

impl<S> Freeze for Database<S>

§

impl<S> !RefUnwindSafe for Database<S>

§

impl<S> Send for Database<S>
where S: Send + Sync,

§

impl<S> Sync for Database<S>
where S: Send + Sync,

§

impl<S> Unpin for Database<S>

§

impl<S> UnsafeUnpin for Database<S>

§

impl<S> !UnwindSafe for Database<S>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more