pub struct SqliteStore { /* private fields */ }sqlite only.Expand description
SQLite database with connection pool and transaction provider.
This struct can be cloned and used in multiple places in the application. Every cloned instance
will re-use the same connection pool and have access to the same transaction instance if one
was started. To guard against sharing transactions unknowingly across unrelated database
queries, a concept of a TransactionPermit was introduced which does not protect from misuse
but helps to make “holding” a transaction explicit.
Please note that SQLite strictly serializes transactions with writes and will block any
parallel attempt to begin another one. Processes starting a transaction will acquire a
TransactionPermit and keep it until the transaction was committed or rolled back. If the
query only involves reads it is recommended to not use transactions and use the execute
method directly as acquiring transactions will potentially block other processes to do work.
§Design decisions
This storage API design was chosen to make the dynamics of the underlying SQLite database explicit to avoid potentially introducing subtle bugs. Internally any process can access the transaction object to do writes and (uncommitted) reads (see “Transaction I” in diagram). Care is required when designing systems like that as it’s still possible to allow concurrent processes to read and write within the same transaction (for example one process could roll back the transaction while the other one assumed it will be committed). Usually developers want to design writes to the database within a transaction if they need consistency and atomicity guarantees. “Unrelated” queries can be “pooled” in one transaction (for performance reasons for example) if consistency is guaranteed by all involved processes and the underlying data-model (see “Transaction II” in diagram).
Transaction I:
begin ---------------------> commit
Process I:
--> write --> read -->
Transaction II:
begin ----------------------> commit
Process II:
--> write --> write -->
Process III:
--> read --> write --->Another design decision is to not expose transactions to the high-level storage APIs (similar
to the “Repository Pattern”). Users of the storage methods like get_operation (in
OperationStore) etc. do not need to explicity deal with transaction objects, as this is
handled internally now. Like this it is possible to separate the “logic” from the “storage”
layer and keep the code clean.
Implementations§
Source§impl SqliteStore
impl SqliteStore
Sourcepub fn from_pool(pool: SqlitePool) -> Self
pub fn from_pool(pool: SqlitePool) -> Self
Creates a new SqliteStore using the provided connection pool.
Sourcepub fn pool(&self) -> &SqlitePool
pub fn pool(&self) -> &SqlitePool
Returns a reference to the connection pool.
Sourcepub async fn temporary() -> Self
Available on crate features test_utils only.
pub async fn temporary() -> Self
test_utils only.Builds an in-memory SQLite database with a randomised name for testing purposes.
Sourcepub async fn tx<F, R>(&self, f: F) -> Result<R, SqliteError>
pub async fn tx<F, R>(&self, f: F) -> Result<R, SqliteError>
Executes a SQL query within a transaction.
This method will return an error when no transaction is currently given. Make sure to call
begin before.
If the query fails the user probably wants to roll back the transaction and free the permit. This is not handled automatically.
Sourcepub async fn execute<F, R>(&self, f: F) -> Result<R, SqliteError>
pub async fn execute<F, R>(&self, f: F) -> Result<R, SqliteError>
Executes a SQL query directly.
Trait Implementations§
Source§impl<N> AddressBookStore<VerifyingKey, N> for SqliteStore
impl<N> AddressBookStore<VerifyingKey, N> for SqliteStore
type Error = SqliteError
Source§async fn insert_node_info(&self, info: N) -> Result<bool, Self::Error>
async fn insert_node_info(&self, info: N) -> Result<bool, Self::Error>
Source§async fn remove_node_info(&self, id: &VerifyingKey) -> Result<bool, Self::Error>
async fn remove_node_info(&self, id: &VerifyingKey) -> Result<bool, Self::Error>
Source§async fn remove_older_than(
&self,
duration: Duration,
) -> Result<usize, Self::Error>
async fn remove_older_than( &self, duration: Duration, ) -> Result<usize, Self::Error>
Source§async fn node_info(&self, id: &VerifyingKey) -> Result<Option<N>, Self::Error>
async fn node_info(&self, id: &VerifyingKey) -> Result<Option<N>, Self::Error>
Source§async fn node_topics(
&self,
id: &VerifyingKey,
) -> Result<HashSet<Topic>, Self::Error>
async fn node_topics( &self, id: &VerifyingKey, ) -> Result<HashSet<Topic>, Self::Error>
Source§async fn all_node_infos(&self) -> Result<Vec<N>, Self::Error>
async fn all_node_infos(&self) -> Result<Vec<N>, Self::Error>
Source§async fn all_nodes_len(&self) -> Result<usize, Self::Error>
async fn all_nodes_len(&self) -> Result<usize, Self::Error>
Source§async fn all_bootstrap_nodes_len(&self) -> Result<usize, Self::Error>
async fn all_bootstrap_nodes_len(&self) -> Result<usize, Self::Error>
Source§async fn selected_node_infos(
&self,
ids: &[VerifyingKey],
) -> Result<Vec<N>, Self::Error>
async fn selected_node_infos( &self, ids: &[VerifyingKey], ) -> Result<Vec<N>, Self::Error>
Source§async fn set_topics(
&self,
id: VerifyingKey,
topics: HashSet<Topic>,
) -> Result<(), Self::Error>
async fn set_topics( &self, id: VerifyingKey, topics: HashSet<Topic>, ) -> Result<(), Self::Error>
Source§async fn node_infos_by_topics(
&self,
topics: &[Topic],
) -> Result<Vec<N>, Self::Error>
async fn node_infos_by_topics( &self, topics: &[Topic], ) -> Result<Vec<N>, Self::Error>
Source§impl Clone for SqliteStore
impl Clone for SqliteStore
Source§fn clone(&self) -> SqliteStore
fn clone(&self) -> SqliteStore
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl<A, L> CursorStore<A, L> for SqliteStore
impl<A, L> CursorStore<A, L> for SqliteStore
Source§async fn get_cursor(
&self,
name: impl AsRef<str>,
) -> Result<Option<Cursor<A, L>>, Self::Error>
async fn get_cursor( &self, name: impl AsRef<str>, ) -> Result<Option<Cursor<A, L>>, Self::Error>
Returns the cursor matching the given name from the database.
Source§async fn set_cursor(&self, cursor: &Cursor<A, L>) -> Result<(), Self::Error>
async fn set_cursor(&self, cursor: &Cursor<A, L>) -> Result<(), Self::Error>
Inserts the given cursor into the database.
Source§async fn delete_cursor(&self, name: impl AsRef<str>) -> Result<(), Self::Error>
async fn delete_cursor(&self, name: impl AsRef<str>) -> Result<(), Self::Error>
Deletes the cursor matching the given name from the database.
type Error = SqliteError
Source§impl Debug for SqliteStore
impl Debug for SqliteStore
Source§impl<ID, S> GroupsStore<ID, S> for SqliteStore
impl<ID, S> GroupsStore<ID, S> for SqliteStore
type Error = SqliteError
Source§async fn set_groups_state(&self, id: &ID, state: &S) -> Result<(), SqliteError>
async fn set_groups_state(&self, id: &ID, state: &S) -> Result<(), SqliteError>
Source§async fn get_groups_state(&self, id: &ID) -> Result<Option<S>, SqliteError>
async fn get_groups_state(&self, id: &ID) -> Result<Option<S>, SqliteError>
Source§impl<L, E> LogStore<Operation<E>, VerifyingKey, L, u64, Hash> for SqliteStorewhere
E: Extensions,
L: LogId,
impl<L, E> LogStore<Operation<E>, VerifyingKey, L, u64, Hash> for SqliteStorewhere
E: Extensions,
L: LogId,
Source§async fn get_latest_entry(
&self,
author: &VerifyingKey,
log_id: &L,
) -> Result<Option<Operation<E>>, Self::Error>
async fn get_latest_entry( &self, author: &VerifyingKey, log_id: &L, ) -> Result<Option<Operation<E>>, Self::Error>
Retrieve the latest entry in an author’s log.
Source§async fn get_latest_entry_tx(
&self,
author: &VerifyingKey,
log_id: &L,
) -> Result<Option<Operation<E>>, Self::Error>
async fn get_latest_entry_tx( &self, author: &VerifyingKey, log_id: &L, ) -> Result<Option<Operation<E>>, Self::Error>
Retrieve the latest entry in an author’s log.
This variant of the method is intended to be used in situations where atomicity of database operations is needed. It requires a transaction context with an acquired permit.
Source§async fn get_log_heights(
&self,
author: &VerifyingKey,
logs: &[L],
) -> Result<Option<BTreeMap<L, SeqNum>>, Self::Error>
async fn get_log_heights( &self, author: &VerifyingKey, logs: &[L], ) -> Result<Option<BTreeMap<L, SeqNum>>, Self::Error>
Retrieve the latest sequence number for a set of author’s logs.
Source§async fn get_log_size(
&self,
author: &VerifyingKey,
log_id: &L,
after: Option<SeqNum>,
until: Option<SeqNum>,
) -> Result<Option<(u64, u64)>, Self::Error>
async fn get_log_size( &self, author: &VerifyingKey, log_id: &L, after: Option<SeqNum>, until: Option<SeqNum>, ) -> Result<Option<(u64, u64)>, Self::Error>
Retrieve the count and total byte size of all operations in an author’s log.
Source§async fn get_log_entries(
&self,
author: &VerifyingKey,
log_id: &L,
after: Option<SeqNum>,
until: Option<SeqNum>,
) -> Result<Option<Vec<(Operation<E>, Vec<u8>)>>, Self::Error>
async fn get_log_entries( &self, author: &VerifyingKey, log_id: &L, after: Option<SeqNum>, until: Option<SeqNum>, ) -> Result<Option<Vec<(Operation<E>, Vec<u8>)>>, Self::Error>
Retrieve log entries representing operations from an author’s log.
Source§async fn prune_entries(
&self,
author: &VerifyingKey,
log_id: &L,
until: &SeqNum,
) -> Result<u64, Self::Error>
async fn prune_entries( &self, author: &VerifyingKey, log_id: &L, until: &SeqNum, ) -> Result<u64, Self::Error>
Prune entries from an author’s log.
Pruning involves deletion of the entry bodies (ie. payloads) from the database.
type Error = SqliteError
Source§impl<E, L> OperationStore<Operation<E>, Hash, L> for SqliteStorewhere
E: Extensions,
L: LogId,
impl<E, L> OperationStore<Operation<E>, Hash, L> for SqliteStorewhere
E: Extensions,
L: LogId,
type Error = SqliteError
Source§async fn insert_operation(
&self,
id: &Hash,
operation: &Operation<E>,
log_id: &L,
) -> Result<bool, Self::Error>
async fn insert_operation( &self, id: &Hash, operation: &Operation<E>, log_id: &L, ) -> Result<bool, Self::Error>
Source§async fn get_operation(
&self,
id: &Hash,
) -> Result<Option<Operation<E>>, Self::Error>
async fn get_operation( &self, id: &Hash, ) -> Result<Option<Operation<E>>, Self::Error>
Source§async fn get_operation_tx(
&self,
id: &Hash,
) -> Result<Option<Operation<E>>, Self::Error>
async fn get_operation_tx( &self, id: &Hash, ) -> Result<Option<Operation<E>>, Self::Error>
Source§async fn has_operation(&self, id: &Hash) -> Result<bool, Self::Error>
async fn has_operation(&self, id: &Hash) -> Result<bool, Self::Error>
Source§async fn has_operation_tx(&self, id: &Hash) -> Result<bool, Self::Error>
async fn has_operation_tx(&self, id: &Hash) -> Result<bool, Self::Error>
Source§impl<ID> OrdererStore<ID> for SqliteStore
impl<ID> OrdererStore<ID> for SqliteStore
type Error = SqliteError
Source§async fn mark_ready(&self, id: ID) -> Result<bool, Self::Error>
async fn mark_ready(&self, id: ID) -> Result<bool, Self::Error>
Source§async fn mark_pending(
&self,
child_id: ID,
parent_ids: Vec<ID>,
) -> Result<bool, Self::Error>
async fn mark_pending( &self, child_id: ID, parent_ids: Vec<ID>, ) -> Result<bool, Self::Error>
Source§async fn get_next_pending(
&self,
id: ID,
) -> Result<Option<HashSet<(ID, Vec<ID>)>>, Self::Error>
async fn get_next_pending( &self, id: ID, ) -> Result<Option<HashSet<(ID, Vec<ID>)>>, Self::Error>
Source§async fn take_next_ready(&self) -> Result<Option<ID>, Self::Error>
async fn take_next_ready(&self) -> Result<Option<ID>, Self::Error>
Source§impl OrdererTestExt for SqliteStore
Available on crate features test_utils only.
impl OrdererTestExt for SqliteStore
test_utils only.Source§impl<T, L> TopicStore<T, VerifyingKey, L> for SqliteStore
SQLite TopicStore implementation that can be used to map a topic to a set of (generic)
per-author data identifiers.
impl<T, L> TopicStore<T, VerifyingKey, L> for SqliteStore
SQLite TopicStore implementation that can be used to map a topic to a set of (generic)
per-author data identifiers.
Source§async fn associate(
&self,
topic: &T,
author: &VerifyingKey,
data_id: &L,
) -> Result<bool, SqliteError>
async fn associate( &self, topic: &T, author: &VerifyingKey, data_id: &L, ) -> Result<bool, SqliteError>
Associate a topic with an author + log id pair.
Source§async fn remove(
&self,
topic: &T,
author: &VerifyingKey,
data_id: &L,
) -> Result<bool, SqliteError>
async fn remove( &self, topic: &T, author: &VerifyingKey, data_id: &L, ) -> Result<bool, SqliteError>
Remove an association between a topic and author + log id pair.
Source§async fn resolve(
&self,
topic: &T,
) -> Result<BTreeMap<VerifyingKey, Vec<L>>, Self::Error>
async fn resolve( &self, topic: &T, ) -> Result<BTreeMap<VerifyingKey, Vec<L>>, Self::Error>
Retrieve a list of all logs associated with the provided topic for all known authors.
type Error = SqliteError
Source§impl Transaction for SqliteStore
impl Transaction for SqliteStore
Source§async fn begin(&self) -> Result<TransactionPermit, SqliteError>
async fn begin(&self) -> Result<TransactionPermit, SqliteError>
Begins a transaction.
Transactions are strictly serialized, this is expressed in form of a TransactionPermit
processes need to hold when acquiring access to a new transaction. Any concurrent process
calling it will await here if there’s already another process holding a permit, this will
potentially “slow down” work and should be carefully used.
Any process with a transaction can now start using the tx method to execute writes within
this transaction or perform uncommitted “dirty” reads on it.
It is usually not necessary to acquire a transaction when the logic only requires committed
reads to the database. Use execute instead.
Source§async fn rollback(&self, permit: TransactionPermit) -> Result<(), SqliteError>
async fn rollback(&self, permit: TransactionPermit) -> Result<(), SqliteError>
Rolls back the transaction and with that all uncommitted changes.
This takes the permit and frees it after the rollback has finished. Other processes can now begin new transactions.
Source§async fn commit(&self, permit: TransactionPermit) -> Result<(), SqliteError>
async fn commit(&self, permit: TransactionPermit) -> Result<(), SqliteError>
Commits the transaction.
This takes the permit and frees it after the commit has finished. Other processes can now begin new transactions.
type Error = SqliteError
type Permit = TransactionPermit
Auto Trait Implementations§
impl Freeze for SqliteStore
impl !RefUnwindSafe for SqliteStore
impl Send for SqliteStore
impl Sync for SqliteStore
impl Unpin for SqliteStore
impl UnsafeUnpin for SqliteStore
impl !UnwindSafe for SqliteStore
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
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
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