pub struct StorageBackend { /* private fields */ }Expand description
Concrete storage backend providing capability traits.
Implementations§
Source§impl StorageBackend
impl StorageBackend
Sourcepub fn sqlite(path: impl AsRef<Path>) -> Result<StorageBackend, SqliteError>
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.
Sourcepub fn sqlite_with_max_readers(
path: impl AsRef<Path>,
max_readers: Option<usize>,
) -> Result<StorageBackend, SqliteError>
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.
Sourcepub fn sqlite_read_only(
path: impl AsRef<Path>,
) -> Result<StorageBackend, SqliteError>
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.
Sourcepub fn sqlite_read_only_with_max_readers(
path: impl AsRef<Path>,
max_readers: Option<usize>,
) -> Result<StorageBackend, SqliteError>
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.
Sourcepub fn memory() -> Result<StorageBackend, SqliteError>
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.
Sourcepub fn sql(&self) -> Arc<dyn SqlAccess> ⓘ
pub fn sql(&self) -> Arc<dyn SqlAccess> ⓘ
Get the SQL access capability.
Returns an Arc<dyn SqlAccess> suitable for passing to services.
Sourcepub fn apply_schema(&self, plan: &ServiceSchemaPlan) -> Result<(), SqliteError>
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.
Sourcepub fn apply_pack_ddl_statements(
&self,
statements: &[&'static str],
) -> Result<(), SqliteError>
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.
Sourcepub fn apply_pack_ddl_statements_with_columns(
&self,
statements: &[&'static str],
additions: &[PackColumnAddition],
) -> Result<(), SqliteError>
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.
Sourcepub fn validate_pack_schema_columns(
&self,
additions: &[PackColumnAddition],
) -> Result<(), SqliteError>
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.
Sourcepub fn prepare_core_schema(&self) -> Result<u32, SqliteError>
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.
Sourcepub fn schema_version(&self) -> Result<u32, SqliteError>
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.
Sourcepub fn attachment_cutover_status(
&self,
) -> Result<AttachmentCutoverStatus, SqliteError>
pub fn attachment_cutover_status( &self, ) -> Result<AttachmentCutoverStatus, SqliteError>
Inspect the coordinated V21 attachment cutover state.
Sourcepub fn stage_attachment_cutover(
&self,
owner: &DatabaseGcOwnerGuard,
) -> Result<(), SqliteError>
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.
Sourcepub fn apply_verified_attachments(
&self,
owner: &DatabaseGcOwnerGuard,
attachments: &[Attachment],
) -> Result<(), SqliteError>
pub fn apply_verified_attachments( &self, owner: &DatabaseGcOwnerGuard, attachments: &[Attachment], ) -> Result<(), SqliteError>
Atomically publish a verified batch of pack-owned attachment roles.
Sourcepub fn finalize_attachment_cutover(
&self,
owner: &DatabaseGcOwnerGuard,
) -> Result<(), SqliteError>
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.
Sourcepub fn entities(&self) -> Result<Arc<dyn EntityStore>, SqliteError>
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.
Sourcepub fn entities_for_namespace(
&self,
namespace: &str,
) -> Result<Arc<dyn EntityStore>, SqliteError>
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.
Sourcepub fn attachments(&self) -> Result<Arc<dyn AttachmentStore>, SqliteError>
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.
Sourcepub fn graph(&self) -> Result<Arc<dyn GraphStore>, SqliteError>
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.
Sourcepub fn graph_for_namespace(
&self,
namespace: &str,
) -> Result<Arc<dyn GraphStore>, SqliteError>
pub fn graph_for_namespace( &self, namespace: &str, ) -> Result<Arc<dyn GraphStore>, SqliteError>
Get a GraphStore scoped to a namespace.
Sourcepub fn notes(&self) -> Result<Arc<dyn NoteStore>, SqliteError>
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.
Sourcepub fn notes_for_namespace(
&self,
namespace: &str,
) -> Result<Arc<dyn NoteStore>, SqliteError>
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.
Sourcepub fn notes_seq_repair_run_count(&self) -> usize
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).
Sourcepub fn events(&self) -> Result<Arc<dyn EventStore>, SqliteError>
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.
Sourcepub fn events_for_namespace(
&self,
namespace: &str,
) -> Result<Arc<dyn EventStore>, SqliteError>
pub fn events_for_namespace( &self, namespace: &str, ) -> Result<Arc<dyn EventStore>, SqliteError>
Get an EventStore scoped to a namespace.
Sourcepub fn agents(&self) -> Result<Arc<dyn AgentStore>, SqliteError>
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.
Sourcepub fn vectors(
&self,
model_key: &str,
embedding_model: &str,
dimensions: usize,
) -> Result<Arc<dyn VectorStore>, SqliteError>
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.
Sourcepub fn vectors_for_namespace(
&self,
model_key: &str,
embedding_model: &str,
dimensions: usize,
namespace: &str,
) -> Result<Arc<dyn VectorStore>, SqliteError>
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").
Sourcepub fn ensure_vector_tables(
&self,
models: &[(&str, usize)],
) -> Result<(), SqliteError>
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.
Sourcepub fn register_embedding_model(
&self,
engine_name: &str,
model_id: &str,
key_version: &str,
dimensions: u32,
) -> Result<(), SqliteError>
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.
Sourcepub fn sparse(
&self,
model_key: &str,
) -> Result<Arc<dyn SparseStore>, SqliteError>
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.
Sourcepub fn sparse_for_namespace(
&self,
model_key: &str,
namespace: &str,
) -> Result<Arc<dyn SparseStore>, SqliteError>
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.
Sourcepub fn text(&self, table_key: &str) -> Result<Arc<dyn TextSearch>, SqliteError>
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.
Sourcepub fn text_with_tokenizer(
&self,
table_key: &str,
tokenizer: &str,
) -> Result<Arc<dyn TextSearch>, SqliteError>
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.
Sourcepub fn blob_store(
&self,
config_root: Option<&Path>,
floor_bytes: Option<u64>,
) -> Result<Arc<dyn BlobStore>, SqliteError>
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.
Sourcepub fn blob_store_read_only(
&self,
config_root: Option<&Path>,
floor_bytes: Option<u64>,
) -> Result<Arc<dyn BlobStore>, SqliteError>
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.
Sourcepub fn is_file_backed(&self) -> bool
pub fn is_file_backed(&self) -> bool
Is this a file-backed backend?
Sourcepub fn is_read_only(&self) -> bool
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.
Sourcepub fn data_dir(&self) -> Option<PathBuf>
pub fn data_dir(&self) -> Option<PathBuf>
Return the directory containing the backend’s database file, or None
for an in-memory backend.
Sourcepub fn ann_root(&self) -> Option<PathBuf>
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.
Sourcepub fn pool(&self) -> &ConnectionPool
pub fn pool(&self) -> &ConnectionPool
Access the underlying pool (escape hatch).
Sourcepub fn pool_arc(&self) -> Arc<ConnectionPool> ⓘ
pub fn pool_arc(&self) -> Arc<ConnectionPool> ⓘ
Clone the underlying pool Arc.
Auto Trait Implementations§
impl !Freeze for StorageBackend
impl !RefUnwindSafe for StorageBackend
impl !UnwindSafe for StorageBackend
impl Send for StorageBackend
impl Sync for StorageBackend
impl Unpin for StorageBackend
impl UnsafeUnpin for StorageBackend
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<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
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