1use rusqlite::{Connection, ToSql};
5
6use crate::{
7 SqliteConfig,
8 error::{SqliteError, SqliteResult},
9};
10
11pub fn apply(conn: &Connection, config: &SqliteConfig) -> SqliteResult<()> {
12 set(conn, "page_size", config.page_size.as_bytes() as u32)?;
13 set(conn, "auto_vacuum", "INCREMENTAL")?;
14 set(conn, "journal_mode", config.journal_mode.as_str())?;
15 set(conn, "synchronous", config.synchronous_mode.as_str())?;
16 set(conn, "temp_store", config.temp_store.as_str())?;
17 set(conn, "cache_size", -(config.cache_size.as_kib() as i32))?;
18 set(conn, "wal_autocheckpoint", config.wal_autocheckpoint)?;
19 set(conn, "mmap_size", config.mmap_size.as_bytes() as i64)?;
20 conn.set_prepared_statement_cache_capacity(config.prepared_statement_cache_capacity as usize);
21 Ok(())
22}
23
24pub fn apply_read_only(conn: &Connection, config: &SqliteConfig) -> SqliteResult<()> {
25 set(conn, "query_only", true)?;
26 set(conn, "temp_store", config.temp_store.as_str())?;
27 set(conn, "cache_size", -(config.cache_size.as_kib() as i32))?;
28 set(conn, "mmap_size", config.mmap_size.as_bytes() as i64)?;
29 conn.set_prepared_statement_cache_capacity(config.prepared_statement_cache_capacity as usize);
30 Ok(())
31}
32
33pub fn incremental_vacuum(conn: &Connection) -> SqliteResult<()> {
34 conn.pragma_query(None, "incremental_vacuum", |_| Ok(())).map_err(|source| SqliteError::Execute {
35 statement: "PRAGMA incremental_vacuum".into(),
36 source,
37 })?;
38 conn.pragma(None, "wal_checkpoint", "TRUNCATE", |_| Ok(())).map_err(|source| SqliteError::Execute {
39 statement: "PRAGMA wal_checkpoint(TRUNCATE)".into(),
40 source,
41 })?;
42 Ok(())
43}
44
45pub fn shrink_memory(conn: &Connection) -> SqliteResult<()> {
46 set(conn, "shrink_memory", 0)
47}
48
49pub fn shutdown(conn: &Connection) -> SqliteResult<()> {
50 set(conn, "wal_checkpoint", "TRUNCATE")?;
51 set(conn, "cache_size", 0)?;
52 Ok(())
53}
54
55fn set<V: ToSql>(conn: &Connection, name: &str, value: V) -> SqliteResult<()> {
56 conn.pragma_update(None, name, value).map_err(|source| SqliteError::Pragma {
57 name: name.into(),
58 source,
59 })
60}
61
62#[cfg(test)]
63mod tests {
64 use std::{env::temp_dir, fs::remove_file};
65
66 use rusqlite::Connection;
67 use uuid::Uuid;
68
69 use super::apply;
70 use crate::SqliteConfig;
71
72 #[test]
77 fn test_apply_converts_units_for_pragmas() {
78 let path = temp_dir().join(format!("reifydb_pragma_{}.db", Uuid::new_v4()));
79 let conn = Connection::open(&path).unwrap();
80
81 apply(&conn, &SqliteConfig::new(&path)).unwrap();
83
84 let cache_size: i64 = conn.pragma_query_value(None, "cache_size", |r| r.get(0)).unwrap();
85 let page_size: i64 = conn.pragma_query_value(None, "page_size", |r| r.get(0)).unwrap();
86 let mmap_size: i64 = conn.pragma_query_value(None, "mmap_size", |r| r.get(0)).unwrap();
87
88 assert_eq!(cache_size, -2000, "cache_size must be the KiB count negated");
89 assert_eq!(page_size, 4096, "page_size must be raw bytes");
90 assert_eq!(mmap_size, 67_108_864, "mmap_size must be raw bytes (64 MiB)");
91
92 drop(conn);
93 let _ = remove_file(&path);
94 let _ = remove_file(path.with_extension("db-wal"));
95 let _ = remove_file(path.with_extension("db-shm"));
96 }
97}