feat: report store durability status

This commit is contained in:
Eric Wendland 2026-07-05 18:10:41 +02:00
commit 6953e3acde
7 changed files with 124 additions and 18 deletions

View file

@ -2,6 +2,8 @@ use rusqlite::{Connection, OptionalExtension, Transaction, params};
use std::path::Path;
pub const CURRENT_SCHEMA_VERSION: i64 = 2;
pub const FILE_JOURNAL_MODE: &str = "wal";
pub const SYNCHRONOUS_MODE: &str = "normal";
#[derive(Debug, thiserror::Error)]
pub enum StoreError {
@ -17,9 +19,31 @@ pub struct Store {
conn: Connection,
}
fn configure_file_connection(conn: &Connection) -> Result<(), StoreError> {
conn.execute_batch(
r#"
PRAGMA journal_mode = WAL;
PRAGMA synchronous = NORMAL;
PRAGMA foreign_keys = ON;
"#,
)?;
Ok(())
}
fn configure_memory_connection(conn: &Connection) -> Result<(), StoreError> {
conn.execute_batch(
r#"
PRAGMA synchronous = NORMAL;
PRAGMA foreign_keys = ON;
"#,
)?;
Ok(())
}
impl Store {
pub fn open(path: &Path) -> Result<Self, StoreError> {
let conn = Connection::open(path)?;
configure_file_connection(&conn)?;
let store = Self { conn };
store.migrate()?;
Ok(store)
@ -27,6 +51,7 @@ impl Store {
pub fn open_memory() -> Result<Self, StoreError> {
let conn = Connection::open_in_memory()?;
configure_memory_connection(&conn)?;
let store = Self { conn };
store.migrate()?;
Ok(store)
@ -58,7 +83,7 @@ impl Store {
Ok(())
}
fn schema_version(&self) -> Result<i64, StoreError> {
pub fn schema_version(&self) -> Result<i64, StoreError> {
let version = self
.conn
.query_row(
@ -75,6 +100,26 @@ impl Store {
.map_err(|_| StoreError::InvalidSchemaVersion(version))
}
pub fn journal_mode(&self) -> Result<String, StoreError> {
self.conn
.query_row("PRAGMA journal_mode", [], |row| row.get::<_, String>(0))
.map(|mode| mode.to_ascii_lowercase())
.map_err(StoreError::from)
}
pub fn synchronous_mode(&self) -> Result<String, StoreError> {
let mode = self
.conn
.query_row("PRAGMA synchronous", [], |row| row.get::<_, i64>(0))?;
Ok(match mode {
0 => "off".to_owned(),
1 => "normal".to_owned(),
2 => "full".to_owned(),
3 => "extra".to_owned(),
other => format!("unknown-{other}"),
})
}
fn apply_schema_v1(&self) -> Result<(), StoreError> {
let tx = self.conn.unchecked_transaction()?;
tx.execute_batch(
@ -1817,6 +1862,25 @@ mod tests {
let _ = std::fs::remove_file(path);
}
#[test]
fn file_store_uses_documented_durability_pragmas() {
let path = std::env::temp_dir().join(format!("geth-store-durability-{}.sqlite", now_ms()));
let store = Store::open(&path).expect("open file store");
assert_eq!(
store.journal_mode().expect("journal mode"),
FILE_JOURNAL_MODE
);
assert_eq!(
store.synchronous_mode().expect("synchronous mode"),
SYNCHRONOUS_MODE
);
drop(store);
let _ = std::fs::remove_file(&path);
let _ = std::fs::remove_file(path.with_extension("sqlite-wal"));
let _ = std::fs::remove_file(path.with_extension("sqlite-shm"));
}
fn column_exists(store: &Store, table: &str, column: &str) -> bool {
let mut stmt = store
.conn