Skip to main content

StorageBackend

Struct StorageBackend 

Source
pub struct StorageBackend { /* private fields */ }
Expand description

Concrete storage backend providing capability traits.

Implementations§

Source§

impl StorageBackend

Source

pub fn sqlite(path: impl AsRef<Path>) -> Result<StorageBackend, SqliteError>

File-backed SQLite database.

Opens (or creates) the database at path. An existing filesystem path whose mode is read-only is opened with the same locked-down pool configuration as Self::sqlite_read_only. The writable pool provides 1 writer + N readers in WAL mode for concurrent access. No schema is applied — call apply_schema() for each service.

Source

pub fn sqlite_with_max_readers( path: impl AsRef<Path>, max_readers: Option<usize>, ) -> Result<StorageBackend, SqliteError>

Open SQLite with a reader count selected before any connections are opened. None preserves the default pool size and filesystem read-only detection.

Source

pub fn sqlite_read_only( path: impl AsRef<Path>, ) -> Result<StorageBackend, SqliteError>

File-backed SQLite database opened read-only.

Opens the database at path and sets PRAGMA query_only = ON on the writer connection so that any write attempt (INSERT/UPDATE/DELETE) returns an error. Reader connections are opened with SQLITE_OPEN_READ_ONLY by the pool; at least one remains dedicated even for a rollback-journal snapshot, while this PRAGMA extends the protection to the otherwise-unused writer slot.

The database file must already exist — unlike sqlite() this constructor does not create a new file.

Source

pub fn sqlite_read_only_with_max_readers( path: impl AsRef<Path>, max_readers: Option<usize>, ) -> Result<StorageBackend, SqliteError>

Open a read-only SQLite store with a construction-time reader count.

Source

pub fn memory() -> Result<StorageBackend, SqliteError>

In-memory SQLite database (for tests).

All data is lost when the backend is dropped. The pool degrades to single-connection mode since in-memory databases cannot be shared across multiple connections.

Source

pub fn sql(&self) -> Arc<dyn SqlAccess> ⓘ

Get the SQL access capability.

Returns an Arc<dyn SqlAccess> suitable for passing to services.

Source

pub fn apply_schema(&self, plan: &ServiceSchemaPlan) -> Result<(), SqliteError>

Apply a service’s schema plan (run migrations).

Each migration in the plan’s sqlite list is applied idempotently, including when another opener commits it first. Already-applied migrations are skipped after taking the SQLite write lock. The _schema_versions table tracks which migrations have been run.

Source

pub fn apply_pack_ddl_statements( &self, statements: &[&'static str], ) -> Result<(), SqliteError>

Apply pack-auxiliary DDL statements.

Executes the full plan in one transaction, applying each DDL statement idempotently via execute_batch. Each statement MUST be self-contained and use CREATE TABLE IF NOT EXISTS (or equivalent idempotent DDL) so that calling this method more than once does not fail.

Pack auxiliary tables are NOT tracked in _schema_versions — they are non-versioned. Use apply_schema with a ServiceSchemaPlan when version tracking is needed.

Plans declaring nullable-column upgrades must use Self::apply_pack_ddl_statements_with_columns. The runtime supplies the SQL slice and column metadata separately because its SchemaPlan type lives above this crate in the dependency chain.

Source

pub fn apply_pack_ddl_statements_with_columns( &self, statements: &[&'static str], additions: &[PackColumnAddition], ) -> Result<(), SqliteError>

Apply a pack’s nullable-column upgrades and idempotent SQL atomically.

Missing columns are added only to existing tables; the full SQL plan creates fresh tables. Existing columns and the final schema must match the declarations. Schema inspection, additions, and SQL all run under one writer transaction, including rollback if any later step fails.

Source

pub fn validate_pack_schema_columns( &self, additions: &[PackColumnAddition], ) -> Result<(), SqliteError>

Validate a pack’s declared columns without applying SQL or acquiring a writer. Read-only hosts use this before exposing verbs that require these columns.

Source

pub fn prepare_core_schema(&self) -> Result<u32, SqliteError>

Prepare the core schema for runtime boot.

Writable backends acquire the canonical database-GC owner before the writer, apply the ordinary versioned prefix, and may finish V21 only through its zero-legacy-reference fast path. A legacy V20 database remains at V20 for the async host’s application-assisted attachment cutover; this method alone is not a serving boot gate. Read-only backends perform a query-only compatibility check and require the snapshot to be at this build’s exact latest schema version.

Source

pub fn schema_version(&self) -> Result<u32, SqliteError>

Read the applied schema version through the pool’s ordinary reader or writer, without running migrations. Unlike migrations::inspect_schema_version, this goes through the already-open pool rather than a fresh boot-time snapshot connection, so it tolerates a WAL sidecar left by this same backend’s own recent writes.

Source

pub fn attachment_cutover_status( &self, ) -> Result<AttachmentCutoverStatus, SqliteError>

Inspect the coordinated V21 attachment cutover state.

Source

pub fn stage_attachment_cutover( &self, owner: &DatabaseGcOwnerGuard, ) -> Result<(), SqliteError>

Commit resumable V21 stage 1 while the caller owns this database’s GC protocol. The owner must remain live through verified application backfill and finalization.

Source

pub fn apply_verified_attachments( &self, owner: &DatabaseGcOwnerGuard, attachments: &[Attachment], ) -> Result<(), SqliteError>

Atomically publish a verified batch of pack-owned attachment roles.

Source

pub fn finalize_attachment_cutover( &self, owner: &DatabaseGcOwnerGuard, ) -> Result<(), SqliteError>

Atomically swap GC liveness/fences to attachments, remove the legacy entity column, and record V21 while the canonical owner is held.

Source

pub fn entities(&self) -> Result<Arc<dyn EntityStore>, SqliteError>

Get an EntityStore. Applies the entities DDL if not already present.

Idempotent — safe to call multiple times.

Source

pub fn entities_for_namespace( &self, namespace: &str, ) -> Result<Arc<dyn EntityStore>, SqliteError>

Get an EntityStore. The namespace parameter is validated (non-empty) and the entities schema is applied, but the store itself is unscoped — namespace is the caller’s responsibility on each query/delete call.

Source

pub fn attachments(&self) -> Result<Arc<dyn AttachmentStore>, SqliteError>

Get the role-keyed attachment store.

Unlike the legacy capability accessors, this does not install DDL on demand. The coordinated V21 core cutover owns creation of the table, reference fences, GC liveness swap, and removal of the legacy entity column as one boot-gated operation.

Source

pub fn graph(&self) -> Result<Arc<dyn GraphStore>, SqliteError>

Get a GraphStore for the default namespace.

Creates the graph_edges table (with indexes) if it does not already exist. Idempotent — safe to call multiple times.

Source

pub fn graph_for_namespace( &self, namespace: &str, ) -> Result<Arc<dyn GraphStore>, SqliteError>

Get a GraphStore scoped to a namespace.

Source

pub fn notes(&self) -> Result<Arc<dyn NoteStore>, SqliteError>

Get a NoteStore. Applies the notes DDL if not already present.

Idempotent — safe to call multiple times.

Source

pub fn notes_for_namespace( &self, namespace: &str, ) -> Result<Arc<dyn NoteStore>, SqliteError>

Get a NoteStore. The namespace parameter is validated (non-empty) and the notes schema is applied, but the store itself is unscoped — namespace is the caller’s responsibility on each query/delete call.

Source

pub fn notes_seq_repair_run_count(&self) -> usize

How many times the lazy notes_seq anti-join repair has actually executed against this backend’s pool. Exposed for regression tests asserting the repair runs at most once per backend for the process’s lifetime, not once per notes_for_namespace call (khive #827).

Source

pub fn events(&self) -> Result<Arc<dyn EventStore>, SqliteError>

Get an EventStore for the default namespace.

Creates the events table (with indexes) if it does not already exist. Idempotent — safe to call multiple times.

Source

pub fn events_for_namespace( &self, namespace: &str, ) -> Result<Arc<dyn EventStore>, SqliteError>

Get an EventStore scoped to a namespace.

Source

pub fn agents(&self) -> Result<Arc<dyn AgentStore>, SqliteError>

Get the agent-process store (ADR-142 §1). Applies the agents DDL if not already present. Idempotent — safe to call multiple times. Unlike the other stores here, agent-process records are not namespace-scoped, so there is no _for_namespace variant.

Source

pub fn vectors( &self, model_key: &str, embedding_model: &str, dimensions: usize, ) -> Result<Arc<dyn VectorStore>, SqliteError>

Get a VectorStore for a specific embedding model, scoped to the default namespace.

Creates the vec0 virtual table if it does not already exist. The model_key must contain only ASCII alphanumeric/underscore characters. The embedding_model is the canonical display name stored in each vector row.

Source

pub fn vectors_for_namespace( &self, model_key: &str, embedding_model: &str, dimensions: usize, namespace: &str, ) -> Result<Arc<dyn VectorStore>, SqliteError>

Get a VectorStore for a specific embedding model with a default namespace.

Creates the vec0 virtual table if it does not already exist. The namespace is a default for trait methods that lack a per-call namespace parameter (count, delete, info). Access control is enforced at the runtime layer.

The model_key must contain only ASCII alphanumeric/underscore characters. The embedding_model is the canonical display name stored in the embedding_model column of each vector row (e.g. "all-minilm-l6-v2").

Source

pub fn ensure_vector_tables( &self, models: &[(&str, usize)], ) -> Result<(), SqliteError>

Ensure all requested vector tables with one schema-writer acquisition. Read-only backends inspect the same tables using one reader instead.

Source

pub fn register_embedding_model( &self, engine_name: &str, model_id: &str, key_version: &str, dimensions: u32, ) -> Result<(), SqliteError>

Register an embedding model in the _embedding_models registry table.

Idempotent: if a row with the same canonical_key already exists, updates its status back to 'active' without changing other fields.

Source

pub fn sparse( &self, model_key: &str, ) -> Result<Arc<dyn SparseStore>, SqliteError>

Get a SparseStore for a specific model key, scoped to the default namespace.

Creates the sparse table if it does not already exist.

Source

pub fn sparse_for_namespace( &self, model_key: &str, namespace: &str, ) -> Result<Arc<dyn SparseStore>, SqliteError>

Get a SparseStore for a specific model key with an explicit default namespace.

The model_key must contain only ASCII alphanumeric/underscore characters.

Source

pub fn text(&self, table_key: &str) -> Result<Arc<dyn TextSearch>, SqliteError>

Get a TextSearch for a specific table key.

Creates the FTS5 virtual table if it does not already exist. Uses the trigram tokenizer by default (CJK-safe).

The table_key must contain only ASCII alphanumeric/underscore characters.

Source

pub fn text_with_tokenizer( &self, table_key: &str, tokenizer: &str, ) -> Result<Arc<dyn TextSearch>, SqliteError>

Get a TextSearch with an explicit FTS5 tokenizer.

Use when you need a tokenizer other than the default trigram — for example unicode61 for Latin-only corpora.

Both table_key and tokenizer must contain only ASCII alphanumeric/underscore characters.

Source

pub fn blob_store( &self, config_root: Option<&Path>, floor_bytes: Option<u64>, ) -> Result<Arc<dyn BlobStore>, SqliteError>

Get a BlobStore rooted per khive#292’s precedence chain: KHIVE_BLOB_ROOT env var > config_root (a caller-resolved khive.toml override — khive-db has no TOML parser of its own) > beside this backend’s database directory. floor_bytes overrides the default 100 GB fail-closed free-space floor (None keeps the default). Errors if none of the three roots apply — e.g. an in-memory backend with no override and no env var has nowhere to default to.

Source

pub fn blob_store_read_only( &self, config_root: Option<&Path>, floor_bytes: Option<u64>, ) -> Result<Arc<dyn BlobStore>, SqliteError>

Resolve the filesystem blob root exactly like Self::blob_store but require it to exist instead of creating it. Snapshot runtimes wrap the returned capability so its read methods remain available while every mutator is refused.

Source

pub fn is_file_backed(&self) -> bool

Is this a file-backed backend?

Source

pub fn is_read_only(&self) -> bool

Whether this backend was opened with SQLite’s read-only/query-only contract, explicitly or after filesystem-mode detection.

Source

pub fn data_dir(&self) -> Option<PathBuf>

Return the directory containing the backend’s database file, or None for an in-memory backend.

Source

pub fn ann_root(&self) -> Option<PathBuf>

Root directory for this database’s ANN segment tree, or None for an in-memory backend. Derived from the database file name itself (<db-file>.ann/ beside the file), so two databases sharing a parent directory can never adopt each other’s segments or UUID maps. The suffix is appended at the OsString byte level — a lossy UTF-8 conversion would collapse distinct non-UTF-8 filenames into one replacement-character root, breaking exactly that isolation.

Source

pub fn pool(&self) -> &ConnectionPool

Access the underlying pool (escape hatch).

Source

pub fn pool_arc(&self) -> Arc<ConnectionPool> ⓘ

Clone the underlying pool Arc.

Auto Trait Implementations§

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<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

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> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

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

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

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

Source§

type Error = !

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

fn try_from(value: U) -> Result<T, !>

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