OXYGENHUB
# df940d75cd3d oxygenhub / crates / hub / src / db / mod.rs
1.7 KiB · Rust · last changed Write transactions begin IMMEDIATE, so a concurrent writer is waited for (busy timeout) instead of failing at once with database is locked; a test of 16 concurrent log appends fails without it 1 month ago source blame history raw
1
//! SQLite through `sqlx` (hub spec §3.1, §17.2): WAL, foreign keys on,
2
//! migrations embedded and applied at start. One module per table group.
3
4
pub mod accounts;
5
pub mod activity;
6
pub mod flow;
7
pub mod hooks;
8
pub mod issues;
9
pub mod notify;
10
pub mod projects;
11
pub mod proposals;
12
pub mod releases;
13
pub mod repos;
14
15
use sqlx::sqlite::{SqliteConnectOptions, SqliteJournalMode, SqlitePoolOptions, SqliteSynchronous};
16
use sqlx::SqlitePool;
17
use std::path::Path;
18
19
pub type Pool = SqlitePool;
20
21
/// Open (creating if needed) and migrate the database at `path`.
22
pub async fn open(path: &Path) -> anyhow::Result<Pool> {
23
    let options = SqliteConnectOptions::new()
24
        .filename(path)
25
        .create_if_missing(true)
26
        .journal_mode(SqliteJournalMode::Wal)
27
        .synchronous(SqliteSynchronous::Normal)
28
        .foreign_keys(true)
29
        .busy_timeout(std::time::Duration::from_secs(5));
30
    let pool = SqlitePoolOptions::new().max_connections(8).connect_with(options).await?;
31
    sqlx::migrate!("./migrations").run(&pool).await?;
32
    Ok(pool)
33
}
34
35
/// Milliseconds since the epoch, the hub's timestamp unit (as `oxy`'s).
36
pub fn now_ms() -> i64 {
37
    std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).map(|d| d.as_millis() as i64).unwrap_or(0)
38
}
39
40
/// A write transaction that takes SQLite's write lock at `BEGIN`
41
/// (`BEGIN IMMEDIATE`). A deferred transaction that reads and then writes
42
/// fails at once with "database is locked" when another writer holds the
43
/// lock, whatever the busy timeout; an immediate one waits its turn.
44
pub async fn begin_write(pool: &Pool) -> sqlx::Result<sqlx::Transaction<'static, sqlx::Sqlite>> {
45
    pool.begin_with("BEGIN IMMEDIATE").await
46
}