Expand description
Interfaces and implementations of persistence layers for p2panda data types and application states.
p2panda follows a strict separation of read- and write-only database interfaces to allow designing efficient and fail-safe atomic transactions throughout the stack.
§Read queries
p2panda-store currently offers all read-only trait interfaces for commonly used p2panda core
data-types and flows (for example “get the latest operation for this log”). These persistence
and query APIs are utilised by higher-level components of the p2panda stack, such as
p2panda-sync and p2panda-stream.
For detailed information concerning the Operation type, please consult the documentation for
the p2panda-core crate.
Logs in the context of p2panda-store are simply a collection of operations grouped under a
common identifier. The precise type for which LogId is implemented is left up to the
developer to decide according to their needs. With this in mind, the traits and implementations
provided by p2panda-store do not perform any validation of log integrity. Developers using
this crate must take steps to ensure their log design is fit for purpose and that all
operations have been thoroughly validated before being persisted.
Also note that the traits provided here are not intended to offer generic storage solutions for non-p2panda data types, nor are they intended to solve all application-layer storage concerns.
§Write transactions
Multiple writes to a database should be grouped into one single, atomic transaction when they need to strictly all occur or none occur. This is crucial to guarantee a crash-resiliant p2p application, as any form of failure and disruption (user moving mobile app into the background, etc.) might otherwise result in invalid database state which is hard to recover from.
p2panda-store offers WritableStore, Transaction and WriteToStore traits to accommodate
for exactly such a system and all p2panda implementations strictly follow the same pattern.
// Initialise a concrete store implementation, for example for SQLite. This implementation
// needs to implement the `WritableStore` trait, providing it's native transaction interface.
let mut store = Sqlite::new();
// Establish state, do things with it. `User` and `Event` both implement `WriteToStore` for the
// concrete store type `Sqlite`.
let user = User::new("casey");
let mut event = Event::new("Ants Research Meetup");
event.register_attendance(&user);
// Persist state in database in one single, atomic transaction.
let mut tx = store.begin().await?;
user.write(&mut tx).await?;
event.write(&mut tx).await?;
tx.commit().await?;
It is recommended for application developers to re-use similar transaction patterns to leverage the same crash-resiliance guarantees for their application-layer state and persistance handling.
§Store implementations
Read queries and atomic write transactions are implemented for all p2panda-stack related data types for concrete databases: In-Memory and SQLite.
An in-memory storage solution is provided in the form of a MemoryStore which implements both
OperationStore and LogStore. The store is gated by the memory feature flag and is enabled
by default.
A SQLite storage solution is provided in the form of a SqliteStore which implements both
OperationStore and LogStore. The store is gated by the sqlite feature flag and is
disabled by default.
Re-exports§
pub use memory::MemoryStore;pub use operations::LogId;pub use operations::LogStore;pub use operations::OperationStore;pub use sqlite::store::SqliteStore;pub use sqlite::store::SqliteStoreError;
Modules§
- memory
- In-memory persistence for p2panda operations and logs.
- operations
- Trait definitions for read-only queries on p2panda operation and log state.
- sqlite
Traits§
- Transaction
- Organises multiple “writes” to a store into one atomic transaction.
- Writable
Store - Store implementation returning an atomic transaction object for fail-safe writes.
- Write
ToStore - Writes state changes into a store as part of an atomic transaction.