Skip to main content

ConnectionPool

Struct ConnectionPool 

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

A read-write connection pool for SQLite.

Architecture:

  • 1 writer connection protected by a Mutex (exclusive access)
  • N reader connections in a lock-free queue (concurrent access)
  • All connections share the same database file in WAL mode

For in-memory databases, or when WAL mode is disabled/unavailable, the pool degrades to single-connection mode and routes all operations through the writer connection.

Implementations§

Source§

impl ConnectionPool

Source

pub fn new(config: PoolConfig) -> Result<ConnectionPool, SqliteError>

Create a new connection pool.

Opens 1 writer + N reader connections to the same database when pooling is enabled. All connections are configured consistently (busy timeout, foreign keys, cache, mmap, temp store). For in-memory databases, or when WAL is disabled or unavailable, the pool falls back to single-connection mode.

Source

pub fn reader(&self) -> Result<ReaderGuard<'_>, SqliteError>

Check out a reader connection.

Tries to pop from the lock-free queue. If empty, spins briefly then waits with exponential backoff up to checkout_timeout.

§Deadlock Warning

In degraded mode (WAL unavailable, max_readers == 0), this method locks the writer mutex. If the calling thread already holds a WriterGuard, this will deadlock (parking_lot Mutex is not reentrant). Never call reader() while holding a WriterGuard on the same pool.

Source

pub fn writer(&self) -> Result<WriterGuard<'_>, SqliteError>

Check out the writer connection.

Waits up to checkout_timeout for the writer Mutex and returns Err(SqliteError::InvalidData) if the timeout is exceeded.

Source

pub fn try_writer(&self) -> Result<WriterGuard<'_>, SqliteError>

Non-panicking writer checkout.

Returns Err on timeout instead of panicking. Use this in request handlers where a 500 is preferable to crashing the process.

Source

pub fn try_writer_nowait(&self) -> Result<WriterGuard<'_>, SqliteError>

Zero-wait writer checkout for background tasks.

Uses try_lock() (no timeout, no spin) — returns Err immediately when any other caller holds the writer Mutex. Background tasks (e.g. the WAL checkpoint task) MUST use this instead of try_writer so that a busy writer causes the background task to skip its current tick rather than stalling for up to checkout_timeout (default 5s) while write traffic is in progress.

Source

pub fn available_readers(&self) -> usize

Get the current number of available reader connections.

Source

pub fn max_readers(&self) -> usize

Get the total number of reader connections in the pool.

Source

pub fn config(&self) -> &PoolConfig

Return the pool configuration.

Source

pub fn writer_task_handle( &self, ) -> Result<Option<WriterTaskHandle>, StorageError>

Return the pool-wide ADR-067 Component A writer task, spawning it lazily on first access if PoolConfig::write_queue_enabled is set. Exactly one writer task exists per ConnectionPool (per DB file); see crates/khive-db/docs/api/pool.md#connectionpoolwriter_task_handle–single-writer-task-rationale for why a per-store writer task would defeat the single-writer guarantee.

Returns Ok(None) if the flag is off, or if the writer task failed to spawn for a reason other than a missing runtime (for example, an in-memory pool has no standalone-connection support) — callers fall back to the legacy pool-mutex write path in either case. A spawn failure is logged once here (at first access), not once per store.

Returns Err(StorageError::WriterTaskNoRuntime) instead of panicking when write_queue_enabled is set but this is the first access and no Tokio runtime is available on the calling thread (checked via tokio::runtime::Handle::try_current) — spawning the writer task requires tokio::spawn, which panics outside a runtime. Callers that already treat a missing writer task as best-effort (construction-time degrade to the legacy path, matching slice 1’s documented policy) can collapse this into None with .ok().flatten(); callers that need to fail loud on a genuine misconfiguration (write queue requested but no runtime to run it on) can propagate the Err directly.

Source

pub fn legacy_conn(&self) -> Arc<Mutex<RawMutex, Connection>>

Compatibility method: returns the writer connection wrapped in Arc<Mutex>.

WARNING: This exists only for backward compatibility with code that calls store.conn(). New code should use reader() and writer().

Source

pub fn open_standalone_writer(&self) -> Result<Connection, SqliteError>

Open a standalone read-write connection to the same file-backed database.

Stores whose trait methods take Send + 'static closures (executed via spawn_blocking) cannot hold the pooled WriterGuard’s MutexGuard across the call — it opens an independent connection instead. This must still honor PoolConfig::read_only: opening SQLITE_OPEN_READ_WRITE unconditionally here would let a read-only backend’s graph/event/text stores bypass the flag that the pooled writer enforces via query_only.

Source

pub fn open_standalone_reader(&self) -> Result<Connection, SqliteError>

Open a standalone read-only connection to the same file-backed database.

Companion to open_standalone_writer for stores that also need an independent reader connection outside the pooled reader queue.

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<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> 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 = 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