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 engine mutex 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 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§

impl<S> Database<S>

Source

pub fn new(store: Arc<Mutex<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<Mutex<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_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 on its first call lazily issues Wal::begin and from then on forwards every event to Wal::append.
  3. On Ok, recorder.commit() writes a TxCommit only when a TxBegin was actually allocated; the surrounding recorder.flush() runs only in that case so a read-only query never pays an fsync.
  4. On Err, recorder.abort() marks the (lazily-issued) tx for replay-time discard; if no TxBegin was issued, abort is a no-op on the WAL. The engine has no rollback, so the in-memory state may already be partially mutated; the abort marker is what gives the durable layer per-query atomicity.
  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 clear(&self)

Drop every node and relationship.

When a WAL is attached, clear() is wrapped in arm/commit so the MutationEvent::Clear fired by the store reaches the log inside a transaction (without arming, the recorder would poison itself on the first event). WAL failures here are best-effort: the in-memory state is still cleared so the caller’s contract holds, but the recorder’s poisoned flag will surface to the next query.

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 mutex 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 the store mutex for the duration of the save so concurrent queries see a consistent point-in-time 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 mutex 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 mutex-held window covers snapshot serialization plus the checkpoint marker append. Truncation runs after the rename but still under the mutex; 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 + '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 + '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 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,

§

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

§

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