pub struct SharedDb { /* private fields */ }Expand description
Shared handle to an on-disk GraphDb. Clone is cheap and shares state.
§Group-commit write path
SharedDb::submit_batch routes mutations through a group-commit queue.
A background drain thread batches concurrent submissions under a single WAL
fsync, yielding throughput that scales with concurrency.
§Direct write path
SharedDb::write gives exclusive &mut GraphDb access for callers that
need complex multi-step mutations (e.g. Cypher write queries). It acquires
the WAL mutex first, then the RwLock write guard, satisfying the lock-order
discipline described in the module doc.
§Event-sink deadlock
GraphDb::set_event_sink runs inside log_then_apply while the write
guard is held. A sink must never call SharedDb::read or
SharedDb::write on the same handle.
Implementations§
pub fn open(dir: &Path) -> Result<Self>
Sourcepub fn open_with_test_sync(
dir: &Path,
sync: impl Fn(&Path) -> Result<()> + Send + Sync + 'static,
) -> Result<Self>
pub fn open_with_test_sync( dir: &Path, sync: impl Fn(&Path) -> Result<()> + Send + Sync + 'static, ) -> Result<Self>
Open with an injectable WAL sync function.
Allows tests to inject fsync failures through the live drain thread
without requiring real filesystem manipulation. Not intended for
production use; the test_sync name signals its purpose.
Sourcepub fn read(&self) -> impl Deref<Target = GraphDb<RealFs>> + '_
pub fn read(&self) -> impl Deref<Target = GraphDb<RealFs>> + '_
Shared read access. Many readers may hold this concurrently.
Readers never acquire the WAL mutex — their p95 latency is unaffected by concurrent write or fsync activity.
§Deadlock warning
Do not hold a returned guard while calling any method on the same
SharedDb; the RwLock is not re-entrant; doing so deadlocks.
Sourcepub fn write(&self) -> WriteGuard<'_>
pub fn write(&self) -> WriteGuard<'_>
Exclusive write access.
Acquires the WAL mutex first, then the RwLock write guard, satisfying
the lock order required by the fsync-failure contract (see module doc).
The returned [WriteGuard] releases the RwLock before the WAL mutex
on drop.
§Deadlock warning
Do not hold a returned guard while calling any method on the same
SharedDb; the RwLock is not re-entrant; doing so deadlocks.
Sourcepub fn reader(&self) -> ReaderSnapshot
pub fn reader(&self) -> ReaderSnapshot
Capture a lock-free ReaderSnapshot of the current db state.
Acquires the read lock only long enough to clone a handful of Arc
handles. Subsequent reads on the returned snapshot are lock-free.
Sourcepub fn submit_batch(&self, ops: Vec<BatchOp>) -> Result<(usize, usize)>
pub fn submit_batch(&self, ops: Vec<BatchOp>) -> Result<(usize, usize)>
Enqueue a mutation batch for the group-committing writer.
Blocks until the containing group is durably committed (one WAL
fsync per group under Strict policy). Submissions from concurrent
callers are coalesced into groups of up to 256 items.
§Durability semantics
Under Strict policy (the default):
- Each submission becomes a separate WAL
Batchframe. - All frames in a group share one fsync — the caller unblocks only after that fsync.
- Fsync failure: the drain thread truncates the WAL back to the
pre-group offset and marks the database degraded. All submitters in
the failed group and all subsequent callers receive
Err. Data that was already in readers’ snapshots (observed between write-lock release and truncation) is not rolled back — equivalent to theRelaxedwindow for in-flight readers. Reopen the database to recover. - A crash between group fsyncs loses the entire unfsynced group, but never tears an individual submission (CRC-protected frame boundaries).
Under Relaxed policy (set via db.write().set_fsync_policy):
- WAL frames are appended but NOT synced; caller unblocks after apply.
§Event ordering
Under Strict / Batched policy, subscription events fire AFTER the
group fsync (durability before notification). Under Relaxed, events
fire immediately after apply.
§FIFO ordering
Submissions from the same caller arrive FIFO at the queue. Across concurrent callers, drain order within a group is arbitrary, but each submission’s commit sequence is monotonically increasing.
§Returns
(nodes_inserted, edges_inserted) on success. An all-noop batch
returns (0, 0).
Sourcepub fn submit_batch_cas(
&self,
preconds: Vec<Precondition>,
ops: Vec<BatchOp>,
) -> Result<(usize, usize)>
pub fn submit_batch_cas( &self, preconds: Vec<Precondition>, ops: Vec<BatchOp>, ) -> Result<(usize, usize)>
Like [submit_batch] but with compare-and-set preconditions.
The preconditions are evaluated by the drain thread under the same
write guard as the batch apply — there is no TOCTOU window. If any
precondition fails, the entire batch is rejected with
core_storage::GraphError::CasConflict and no WAL frame is written.
See crate::Precondition for the full semantics.
Sourcepub fn submit_batch_authz(
&self,
role: String,
ops: Vec<BatchOp>,
) -> Result<(usize, usize)>
pub fn submit_batch_authz( &self, role: String, ops: Vec<BatchOp>, ) -> Result<(usize, usize)>
Like [submit_batch] but with role-scoped write authorization.
The drain thread resolves mask_for_role + scope under the same write
guard as the mutation (§5 lock discipline: authz BEFORE any CAS
preconditions, BEFORE the WAL write).
- Role with
write: None→GraphError::RoleWriteDenied(endpoint not permitted) — maps to HTTP 403. - Scope / visibility violations inside the batch →
GraphError::RoleWriteDeniedwith the appropriate §4.3 reason string.
All-or-nothing semantics: a single denied op rejects the entire batch with no WAL frame written.
Trait Implementations§
Auto Trait Implementations§
Blanket Implementations§
Source§impl<T> ArchivePointee for T
impl<T> ArchivePointee for T
Source§type ArchivedMetadata = ()
type ArchivedMetadata = ()
Source§fn pointer_metadata(
_: &<T as ArchivePointee>::ArchivedMetadata,
) -> <T as Pointee>::Metadata
fn pointer_metadata( _: &<T as ArchivePointee>::ArchivedMetadata, ) -> <T as Pointee>::Metadata
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
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> LayoutRaw for T
impl<T> LayoutRaw for T
Source§fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>
fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>
Source§impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
Source§unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
Source§fn resolve_niched(out: Place<NichedOption<T, N1>>)
fn resolve_niched(out: Place<NichedOption<T, N1>>)
out indicating that a T is niched.