quill_sql/config/
mod.rs

1use std::path::PathBuf;
2use std::time::Duration;
3
4#[derive(Debug, Clone, Copy)]
5pub struct IOSchedulerConfig {
6    /// Number of io_uring worker threads (or fallback thread pool workers)
7    pub workers: usize,
8    /// IoUring queue depth (Linux only). Ignored on non-Linux.
9    #[cfg(target_os = "linux")]
10    pub iouring_queue_depth: usize,
11    /// Number of registered fixed buffers for io_uring (Linux only).
12    #[cfg(target_os = "linux")]
13    pub iouring_fixed_buffers: usize,
14    /// Optional SQPOLL idle time in milliseconds (Linux only).
15    #[cfg(target_os = "linux")]
16    pub iouring_sqpoll_idle_ms: Option<u32>,
17    /// Whether the IO backend should force an fsync/fdatasync after writes.
18    pub fsync_on_write: bool,
19    /// WAL handler worker threads (buffered I/O)
20    pub wal_workers: usize,
21}
22
23impl IOSchedulerConfig {
24    pub fn default_workers() -> usize {
25        std::thread::available_parallelism()
26            .map(|n| n.get())
27            .unwrap_or(1)
28    }
29}
30
31impl Default for IOSchedulerConfig {
32    fn default() -> Self {
33        IOSchedulerConfig {
34            workers: Self::default_workers(),
35            #[cfg(target_os = "linux")]
36            iouring_queue_depth: 256,
37            #[cfg(target_os = "linux")]
38            iouring_fixed_buffers: 256,
39            #[cfg(target_os = "linux")]
40            iouring_sqpoll_idle_ms: None,
41            fsync_on_write: true,
42            wal_workers: std::cmp::max(1, Self::default_workers() / 2),
43        }
44    }
45}
46
47#[derive(Debug, Clone, Copy)]
48pub struct BufferPoolConfig {
49    pub buffer_pool_size: usize,
50    pub lru_k_k: usize,
51    pub tiny_lfu_enable: bool,
52    pub tiny_lfu_counters: usize,
53    pub admission_enable: bool,
54}
55
56impl Default for BufferPoolConfig {
57    fn default() -> Self {
58        BufferPoolConfig {
59            buffer_pool_size: 5000,
60            lru_k_k: 2,
61            tiny_lfu_enable: true,
62            tiny_lfu_counters: 4,
63            admission_enable: true,
64        }
65    }
66}
67
68#[derive(Debug, Clone)]
69pub struct WalConfig {
70    pub directory: PathBuf,
71    pub segment_size: u64,
72    pub sync_on_flush: bool,
73    pub persist_control_file_on_flush: bool,
74    pub writer_interval_ms: Option<u64>,
75    pub buffer_capacity: usize,
76    pub flush_coalesce_bytes: usize,
77    pub synchronous_commit: bool,
78    pub checkpoint_interval_ms: Option<u64>,
79    pub retain_segments: usize,
80}
81
82#[derive(Debug, Clone, Copy)]
83pub struct BackgroundConfig {
84    pub wal_writer_interval: Option<Duration>,
85    pub checkpoint_interval: Option<Duration>,
86    pub bg_writer_interval: Option<Duration>,
87    pub vacuum: IndexVacuumConfig,
88    pub mvcc_vacuum: MvccVacuumConfig,
89}
90
91pub fn background_config(
92    wal_config: &WalConfig,
93    vacuum_cfg: IndexVacuumConfig,
94    mvcc_cfg: MvccVacuumConfig,
95) -> BackgroundConfig {
96    let wal_writer_interval = wal_config.writer_interval_ms.and_then(duration_from_ms);
97    let checkpoint_interval = wal_config.checkpoint_interval_ms.and_then(duration_from_ms);
98
99    let env_interval = std::env::var("QUILL_BG_WRITER_INTERVAL_MS")
100        .ok()
101        .and_then(|raw| raw.parse::<u64>().ok());
102    let bg_interval_ms = env_interval.unwrap_or(vacuum_cfg.interval_ms);
103    let bg_writer_interval = duration_from_ms(bg_interval_ms);
104
105    let mvcc_interval_ms = std::env::var("QUILL_MVCC_VACUUM_INTERVAL_MS")
106        .ok()
107        .and_then(|raw| raw.parse::<u64>().ok())
108        .unwrap_or(mvcc_cfg.interval_ms);
109    let mvcc_batch = std::env::var("QUILL_MVCC_VACUUM_BATCH")
110        .ok()
111        .and_then(|raw| raw.parse::<usize>().ok())
112        .unwrap_or(mvcc_cfg.batch_limit)
113        .max(1);
114
115    BackgroundConfig {
116        wal_writer_interval,
117        checkpoint_interval,
118        bg_writer_interval,
119        vacuum: vacuum_cfg,
120        mvcc_vacuum: MvccVacuumConfig {
121            interval_ms: mvcc_interval_ms,
122            batch_limit: mvcc_batch,
123        },
124    }
125}
126
127fn duration_from_ms(ms: u64) -> Option<Duration> {
128    if ms == 0 {
129        None
130    } else {
131        Some(Duration::from_millis(ms))
132    }
133}
134
135impl Default for WalConfig {
136    fn default() -> Self {
137        WalConfig {
138            directory: PathBuf::from("wal"),
139            segment_size: 16 * 1024 * 1024, // 16 MiB segments by default
140            sync_on_flush: false,
141            persist_control_file_on_flush: false,
142            writer_interval_ms: Some(50),
143            buffer_capacity: 256,
144            flush_coalesce_bytes: 2 * 1024 * 1024,
145            synchronous_commit: false,
146            checkpoint_interval_ms: Some(5000),
147            retain_segments: 8,
148        }
149    }
150}
151
152#[derive(Debug, Clone, Copy)]
153pub struct BTreeConfig {
154    pub seq_batch_enable: bool,
155    pub seq_window: usize,
156    pub prefetch_enable: bool,
157    pub prefetch_window: usize,
158    pub debug_find_level: u8,
159    pub debug_insert_level: u8,
160    pub debug_split_level: u8,
161}
162
163impl Default for BTreeConfig {
164    fn default() -> Self {
165        BTreeConfig {
166            seq_batch_enable: true,
167            seq_window: 32,
168            prefetch_enable: true,
169            prefetch_window: 2,
170            debug_find_level: 0,
171            debug_insert_level: 0,
172            debug_split_level: 0,
173        }
174    }
175}
176
177#[derive(Debug, Clone, Copy)]
178pub struct IndexVacuumConfig {
179    /// Background vacuum interval in milliseconds
180    pub interval_ms: u64,
181    /// Pending garbage counter threshold to trigger a cleanup batch
182    pub trigger_threshold: usize,
183    /// Max number of entries to cleanup in one batch
184    pub batch_limit: usize,
185}
186
187impl Default for IndexVacuumConfig {
188    fn default() -> Self {
189        Self {
190            interval_ms: 10_000,     // 10s
191            trigger_threshold: 4096, // pending count to trigger
192            batch_limit: 128,        // small batch to avoid stalls
193        }
194    }
195}
196
197#[derive(Debug, Clone, Copy)]
198pub struct MvccVacuumConfig {
199    /// Background MVCC vacuum interval in milliseconds
200    pub interval_ms: u64,
201    /// Max tuples to reclaim per iteration
202    pub batch_limit: usize,
203}
204
205impl Default for MvccVacuumConfig {
206    fn default() -> Self {
207        Self {
208            interval_ms: 15_000, // 15s
209            batch_limit: 512,
210        }
211    }
212}