concurrent_writers/
concurrent_writers.rs1use sqlrite::{Connection, Result};
20
21fn main() -> Result<()> {
22 let mut a = Connection::open_in_memory()?;
23 a.execute("PRAGMA journal_mode = mvcc")?;
24 a.execute(
25 "CREATE TABLE accounts (
26 id INTEGER PRIMARY KEY,
27 holder TEXT NOT NULL,
28 balance INTEGER NOT NULL
29 )",
30 )?;
31 a.execute("INSERT INTO accounts (id, holder, balance) VALUES (1, 'alice', 100)")?;
32 a.execute("INSERT INTO accounts (id, holder, balance) VALUES (2, 'bob', 100)")?;
33
34 let mut b = a.connect();
38
39 println!("=== Disjoint-row commits both succeed ===");
40 a.execute("BEGIN CONCURRENT")?;
41 b.execute("BEGIN CONCURRENT")?;
42 a.execute("UPDATE accounts SET balance = balance + 10 WHERE id = 1")?;
43 b.execute("UPDATE accounts SET balance = balance + 20 WHERE id = 2")?;
44 a.execute("COMMIT")?;
45 b.execute("COMMIT")?; print_balances(&mut a)?;
47
48 println!("\n=== Same-row commits: A wins, B retries ===");
49 a.execute("BEGIN CONCURRENT")?;
52 b.execute("BEGIN CONCURRENT")?;
53 a.execute("UPDATE accounts SET balance = balance + 5 WHERE id = 1")?;
54 b.execute("UPDATE accounts SET balance = balance + 50 WHERE id = 1")?;
55 a.execute("COMMIT")?;
56 match b.execute("COMMIT") {
60 Err(e) if e.is_retryable() => {
61 eprintln!(" B lost the race: {e}");
62 b.execute("BEGIN CONCURRENT")?;
63 b.execute("UPDATE accounts SET balance = balance + 50 WHERE id = 1")?;
64 b.execute("COMMIT")?;
65 }
66 other => {
67 other?;
68 }
69 }
70 print_balances(&mut a)?;
71
72 Ok(())
73}
74
75fn print_balances(conn: &mut Connection) -> Result<()> {
76 let stmt = conn.prepare("SELECT id, holder, balance FROM accounts ORDER BY id")?;
77 let mut rows = stmt.query()?;
78 while let Some(row) = rows.next()? {
79 let id: i64 = row.get_by_name("id")?;
80 let holder: String = row.get_by_name("holder")?;
81 let balance: i64 = row.get_by_name("balance")?;
82 println!(" account {id} ({holder}): {balance}");
83 }
84 Ok(())
85}