Skip to main content

reifydb_sqlite/
pragma.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use 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 shrink_memory(conn: &Connection) -> SqliteResult<()> {
34	set(conn, "shrink_memory", 0)
35}
36
37pub fn shutdown(conn: &Connection) -> SqliteResult<()> {
38	set(conn, "wal_checkpoint", "TRUNCATE")?;
39	set(conn, "cache_size", 0)?;
40	Ok(())
41}
42
43fn set<V: ToSql>(conn: &Connection, name: &str, value: V) -> SqliteResult<()> {
44	conn.pragma_update(None, name, value).map_err(|source| SqliteError::Pragma {
45		name: name.into(),
46		source,
47	})
48}
49
50#[cfg(test)]
51mod tests {
52	use std::{env::temp_dir, fs::remove_file};
53
54	use rusqlite::Connection;
55	use uuid::Uuid;
56
57	use super::apply;
58	use crate::SqliteConfig;
59
60	/// Locks in the unit conversions performed by `apply`: `cache_size` is the KiB count negated
61	/// (SQLite reads a negative `cache_size` as KiB, a positive one as pages), while `page_size`
62	/// and `mmap_size` are raw bytes. A future change that, say, swapped `as_kib()` for
63	/// `as_bytes()` on the cache would record 2_048_000 here and fail.
64	#[test]
65	fn test_apply_converts_units_for_pragmas() {
66		let path = temp_dir().join(format!("reifydb_pragma_{}.db", Uuid::new_v4()));
67		let conn = Connection::open(&path).unwrap();
68
69		// new(..) defaults: cache_size 2000 KiB, page_size 4096 bytes, mmap_size 64 MiB.
70		apply(&conn, &SqliteConfig::new(&path)).unwrap();
71
72		let cache_size: i64 = conn.pragma_query_value(None, "cache_size", |r| r.get(0)).unwrap();
73		let page_size: i64 = conn.pragma_query_value(None, "page_size", |r| r.get(0)).unwrap();
74		let mmap_size: i64 = conn.pragma_query_value(None, "mmap_size", |r| r.get(0)).unwrap();
75
76		assert_eq!(cache_size, -2000, "cache_size must be the KiB count negated");
77		assert_eq!(page_size, 4096, "page_size must be raw bytes");
78		assert_eq!(mmap_size, 67_108_864, "mmap_size must be raw bytes (64 MiB)");
79
80		drop(conn);
81		let _ = remove_file(&path);
82		let _ = remove_file(path.with_extension("db-wal"));
83		let _ = remove_file(path.with_extension("db-shm"));
84	}
85}