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 writer_interval_ms: Option<u64>,
74    pub buffer_capacity: usize,
75    pub flush_coalesce_bytes: usize,
76    pub synchronous_commit: bool,
77    pub checkpoint_interval_ms: Option<u64>,
78    pub retain_segments: usize,
79}
80
81#[derive(Debug, Clone, Copy)]
82pub struct BackgroundConfig {
83    pub wal_writer_interval: Option<Duration>,
84    pub checkpoint_interval: Option<Duration>,
85    pub bg_writer_interval: Option<Duration>,
86    pub vacuum: IndexVacuumConfig,
87    pub mvcc_vacuum: MvccVacuumConfig,
88}
89
90pub fn background_config(
91    wal_config: &WalConfig,
92    vacuum_cfg: IndexVacuumConfig,
93    mvcc_cfg: MvccVacuumConfig,
94) -> BackgroundConfig {
95    let wal_writer_interval = wal_config.writer_interval_ms.and_then(duration_from_ms);
96    let checkpoint_interval = wal_config.checkpoint_interval_ms.and_then(duration_from_ms);
97
98    let env_interval = std::env::var("QUILL_BG_WRITER_INTERVAL_MS")
99        .ok()
100        .and_then(|raw| raw.parse::<u64>().ok());
101    let bg_interval_ms = env_interval.unwrap_or(vacuum_cfg.interval_ms);
102    let bg_writer_interval = duration_from_ms(bg_interval_ms);
103
104    let mvcc_interval_ms = std::env::var("QUILL_MVCC_VACUUM_INTERVAL_MS")
105        .ok()
106        .and_then(|raw| raw.parse::<u64>().ok())
107        .unwrap_or(mvcc_cfg.interval_ms);
108    let mvcc_batch = std::env::var("QUILL_MVCC_VACUUM_BATCH")
109        .ok()
110        .and_then(|raw| raw.parse::<usize>().ok())
111        .unwrap_or(mvcc_cfg.batch_limit)
112        .max(1);
113
114    BackgroundConfig {
115        wal_writer_interval,
116        checkpoint_interval,
117        bg_writer_interval,
118        vacuum: vacuum_cfg,
119        mvcc_vacuum: MvccVacuumConfig {
120            interval_ms: mvcc_interval_ms,
121            batch_limit: mvcc_batch,
122        },
123    }
124}
125
126fn duration_from_ms(ms: u64) -> Option<Duration> {
127    if ms == 0 {
128        None
129    } else {
130        Some(Duration::from_millis(ms))
131    }
132}
133
134impl Default for WalConfig {
135    fn default() -> Self {
136        WalConfig {
137            directory: PathBuf::from("wal"),
138            segment_size: 16 * 1024 * 1024, // 16 MiB segments by default
139            sync_on_flush: true,
140            writer_interval_ms: Some(50),
141            buffer_capacity: 256,
142            flush_coalesce_bytes: 2 * 1024 * 1024,
143            synchronous_commit: false,
144            checkpoint_interval_ms: Some(5000),
145            retain_segments: 8,
146        }
147    }
148}
149
150#[derive(Debug, Clone, Copy)]
151pub struct BTreeConfig {
152    pub seq_batch_enable: bool,
153    pub seq_window: usize,
154    pub prefetch_enable: bool,
155    pub prefetch_window: usize,
156    pub debug_find_level: u8,
157    pub debug_insert_level: u8,
158    pub debug_split_level: u8,
159}
160
161impl Default for BTreeConfig {
162    fn default() -> Self {
163        BTreeConfig {
164            seq_batch_enable: true,
165            seq_window: 32,
166            prefetch_enable: true,
167            prefetch_window: 2,
168            debug_find_level: 0,
169            debug_insert_level: 0,
170            debug_split_level: 0,
171        }
172    }
173}
174
175#[derive(Debug, Clone, Copy)]
176pub struct TableScanConfig {
177    pub stream_scan_enable: bool,
178    pub stream_threshold_pages: Option<u32>,
179    pub readahead_pages: usize,
180}
181
182impl Default for TableScanConfig {
183    fn default() -> Self {
184        TableScanConfig {
185            stream_scan_enable: false,
186            stream_threshold_pages: None, // None => use pool_size/4
187            readahead_pages: 2,
188        }
189    }
190}
191
192#[derive(Debug, Clone, Copy)]
193pub struct IndexVacuumConfig {
194    /// Background vacuum interval in milliseconds
195    pub interval_ms: u64,
196    /// Pending garbage counter threshold to trigger a cleanup batch
197    pub trigger_threshold: usize,
198    /// Max number of entries to cleanup in one batch
199    pub batch_limit: usize,
200}
201
202impl Default for IndexVacuumConfig {
203    fn default() -> Self {
204        Self {
205            interval_ms: 10_000,     // 10s
206            trigger_threshold: 4096, // pending count to trigger
207            batch_limit: 128,        // small batch to avoid stalls
208        }
209    }
210}
211
212#[derive(Debug, Clone, Copy)]
213pub struct MvccVacuumConfig {
214    /// Background MVCC vacuum interval in milliseconds
215    pub interval_ms: u64,
216    /// Max tuples to reclaim per iteration
217    pub batch_limit: usize,
218}
219
220impl Default for MvccVacuumConfig {
221    fn default() -> Self {
222        Self {
223            interval_ms: 15_000, // 15s
224            batch_limit: 512,
225        }
226    }
227}