Skip to main content

SqliteStore

Struct SqliteStore 

Source
pub struct SqliteStore { /* private fields */ }
Available on crate feature 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

Source

pub fn from_pool(pool: SqlitePool) -> Self

Creates a new SqliteStore using the provided connection pool.

Source

pub fn pool(&self) -> &SqlitePool

Returns a reference to the connection pool.

Source

pub async fn temporary() -> Self

Available on crate features test_utils only.

Builds an in-memory SQLite database with a randomised name for testing purposes.

Source

pub async fn tx<F, R>(&self, f: F) -> Result<R, SqliteError>
where F: AsyncFnOnce(&mut Transaction<'_>) -> 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.

Source

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
where N: NodeInfo<VerifyingKey> + Serialize + for<'de> Deserialize<'de>,

Source§

type Error = SqliteError

Source§

async fn insert_node_info(&self, info: N) -> Result<bool, Self::Error>

Inserts information for a node. Read more
Source§

async fn remove_node_info(&self, id: &VerifyingKey) -> Result<bool, Self::Error>

Removes information for a node. Read more
Source§

async fn remove_older_than( &self, duration: Duration, ) -> Result<usize, Self::Error>

Remove all node informations which are older than the given duration (from now). Returns number of removed entries. Read more
Source§

async fn node_info(&self, id: &VerifyingKey) -> Result<Option<N>, Self::Error>

Returns information about a node. Read more
Source§

async fn node_topics( &self, id: &VerifyingKey, ) -> Result<HashSet<Topic>, Self::Error>

Returns topics of a node.
Source§

async fn all_node_infos(&self) -> Result<Vec<N>, Self::Error>

Returns a list of all known node informations.
Source§

async fn all_nodes_len(&self) -> Result<usize, Self::Error>

Returns the count of all known nodes.
Source§

async fn all_bootstrap_nodes_len(&self) -> Result<usize, Self::Error>

Returns the count of all known bootstrap nodes.
Source§

async fn selected_node_infos( &self, ids: &[VerifyingKey], ) -> Result<Vec<N>, Self::Error>

Returns a list of node informations for a selected set.
Source§

async fn set_topics( &self, id: VerifyingKey, topics: HashSet<Topic>, ) -> Result<(), Self::Error>

Sets the list of “topics” this node is “interested” in. Read more
Source§

async fn node_infos_by_topics( &self, topics: &[Topic], ) -> Result<Vec<N>, Self::Error>

Returns a list of informations about nodes which are all interested in at least one of the given topics in this set.
Source§

async fn random_node(&self) -> Result<Option<N>, Self::Error>

Returns information from a randomly picked node or None when no information exists in the database.
Source§

async fn random_bootstrap_node(&self) -> Result<Option<N>, Self::Error>

Returns information from a randomly picked “bootstrap” node or None when no information exists in the database. Read more
Source§

impl Clone for SqliteStore

Source§

fn clone(&self) -> SqliteStore

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<A, L> CursorStore<A, L> for SqliteStore
where A: Author, L: LogId,

Source§

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>

Inserts the given cursor into the database.

Source§

async fn delete_cursor(&self, name: impl AsRef<str>) -> Result<(), Self::Error>

Deletes the cursor matching the given name from the database.

Source§

type Error = SqliteError

Source§

impl Debug for SqliteStore

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<ID, S> GroupsStore<ID, S> for SqliteStore
where ID: for<'a> Deserialize<'a> + Serialize, S: for<'a> Deserialize<'a> + Serialize,

Source§

type Error = SqliteError

Source§

async fn set_groups_state(&self, id: &ID, state: &S) -> Result<(), SqliteError>

Set state for a specified groups instance.
Source§

async fn get_groups_state(&self, id: &ID) -> Result<Option<S>, SqliteError>

Get state for a specified groups instance.
Source§

impl<L, E> LogStore<Operation<E>, VerifyingKey, L, u64, Hash> for SqliteStore
where E: Extensions, L: LogId,

Source§

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>

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>

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>

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>

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>

Prune entries from an author’s log.

Pruning involves deletion of the entry bodies (ie. payloads) from the database.

Source§

type Error = SqliteError

Source§

impl<E, L> OperationStore<Operation<E>, Hash, L> for SqliteStore
where E: Extensions, L: LogId,

Source§

type Error = SqliteError

Source§

async fn insert_operation( &self, id: &Hash, operation: &Operation<E>, log_id: &L, ) -> Result<bool, Self::Error>

Insert an operation. Read more
Source§

async fn get_operation( &self, id: &Hash, ) -> Result<Option<Operation<E>>, Self::Error>

Get an operation by id.
Source§

async fn get_operation_tx( &self, id: &Hash, ) -> Result<Option<Operation<E>>, Self::Error>

Get an operation by id. Read more
Source§

async fn has_operation(&self, id: &Hash) -> Result<bool, Self::Error>

Query the existence of an operation. Read more
Source§

async fn has_operation_tx(&self, id: &Hash) -> Result<bool, Self::Error>

Query the existence of an operation. Read more
Source§

async fn delete_operation(&self, id: &Hash) -> Result<bool, Self::Error>

Delete an operation. Read more
Source§

async fn delete_operation_payload(&self, id: &Hash) -> Result<bool, Self::Error>

Delete an operation payload. Read more
Source§

impl<ID> OrdererStore<ID> for SqliteStore
where ID: Eq + Ord + StdHash + Display + FromStr,

Source§

type Error = SqliteError

Source§

async fn mark_ready(&self, id: ID) -> Result<bool, Self::Error>

Add an item to the store which has all it’s dependencies met already. If this is the first time the item has been added it should also be pushed to the end of a “ready” queue.
Source§

async fn mark_pending( &self, child_id: ID, parent_ids: Vec<ID>, ) -> Result<bool, Self::Error>

Add an item which does not have all it’s dependencies met yet.
Source§

async fn get_next_pending( &self, id: ID, ) -> Result<Option<HashSet<(ID, Vec<ID>)>>, Self::Error>

Get all pending items which directly depend on the given id.
Source§

async fn take_next_ready(&self) -> Result<Option<ID>, Self::Error>

Take the next ready item from the ready queue.
Source§

async fn remove_pending(&self, id: ID) -> Result<bool, Self::Error>

Remove all items from the pending queue which depend on the passed id.
Source§

async fn ready(&self, dependencies: &[ID]) -> Result<bool, Self::Error>

Returns true if all the passed keys are present in the ready list.
Source§

impl OrdererTestExt for SqliteStore

Available on crate features test_utils only.
Source§

async fn ready_len(&self) -> usize

Source§

async fn ready_queue_len(&self) -> usize

Source§

async fn pending_len(&self) -> usize

Source§

impl<T, L> TopicStore<T, VerifyingKey, L> for SqliteStore
where T: Serialize + for<'de> Deserialize<'de>, L: LogId,

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>

Associate a topic with an author + log id pair.

Source§

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>

Retrieve a list of all logs associated with the provided topic for all known authors.

Source§

type Error = SqliteError

Source§

impl Transaction for SqliteStore

Source§

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>

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>

Commits the transaction.

This takes the permit and frees it after the commit has finished. Other processes can now begin new transactions.

Source§

type Error = SqliteError

Source§

type Permit = TransactionPermit

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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. 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> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
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<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

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