Expand description
§Sqlite Reader Writer Concurrency (RWC)
This crate presents an opinionated approach on how to interact with a sqlite database to maximize the reader writer concurrency.
§Setup
Sqlite only supports on write operation at any given time. However, in WAL mode multiple readers can operate on the database without blocking the writer and vice versa.
To leverage this, the ConnectionPool
maintains a list of read only connections
and one write connection. This allows multiple readers to access the database and
we enforce exclusive access to the writer connection.
While Sqlite does have internal mechanisms to enforce exclusive write access, they
are a bit limited and mostly rely on an sleep-retry loop. By enforcing exclusive
access to the writer at this level, we can have more predictable writer access
behaviors and we only have to deal with SQLITE_BUSY
errors from another process.
Finally, since all other connections are read only, we also ensure that it is not possible to accidentally write something outside of the designated writer.
§Async
This crate also contains a basic async wrapper for the ConnectionPool
, where
each connection is assigned its own thread and communication occurs over a channel.
This can be enabled with the async
feature.
§Example
use sqlite_rwc::{SyncConnectionPool, ConnectionPoolConfig};
use sqlite_rwc::drivers::rusqlite::RusqliteDriver;
use tempdir::TempDir;
let temp_dir = TempDir::new("sqlite-wrc-example").unwrap();
let db_path = temp_dir.path().join("sqlite.db");
let config = ConnectionPoolConfig {
max_read_connection_count: 4,
file_path: db_path,
connection_acquire_timeout: None,
#[cfg(feature="watcher")]
watcher: sqlite_watcher::watcher::Watcher::new().unwrap(),
};
let pool = SyncConnectionPool::<RusqliteDriver>::new(config).unwrap();
let mut connection = pool.connection().unwrap();
//unscoped read operation ...
connection.execute_batch("SQL");
connection.read_transaction_closure(|conn| -> rusqlite::Result<()>{
///scoped read operation
Ok(())
}).unwrap();
connection.transaction_closure(|conn| -> rusqlite::Result<()>{
//transaction operation
Ok(())
}).unwrap();
Modules§
Structs§
- Connection
Pool - Connection
Pool Config - Pooled
Connection - Read
Transaction - Performs an explicit read transaction using
BEGIN
andEND
sql statements. - Sync
Connection Adapter - Defines behaviors appropriate for usage of a connection with sync/non-async usage.
- Transaction
- Even though some implementations have their own transaction type (e.g.: rusqlite), they are consumed on commit/rollback. We want to run some extra code after commit and rollback.