1use std::path::PathBuf;
2use std::time::Duration;
3
4#[derive(Debug, Clone, Copy)]
5pub struct IOSchedulerConfig {
6 pub workers: usize,
8 #[cfg(target_os = "linux")]
10 pub iouring_queue_depth: usize,
11 #[cfg(target_os = "linux")]
13 pub iouring_fixed_buffers: usize,
14 #[cfg(target_os = "linux")]
16 pub iouring_sqpoll_idle_ms: Option<u32>,
17 pub fsync_on_write: bool,
19 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, 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, readahead_pages: 2,
188 }
189 }
190}
191
192#[derive(Debug, Clone, Copy)]
193pub struct IndexVacuumConfig {
194 pub interval_ms: u64,
196 pub trigger_threshold: usize,
198 pub batch_limit: usize,
200}
201
202impl Default for IndexVacuumConfig {
203 fn default() -> Self {
204 Self {
205 interval_ms: 10_000, trigger_threshold: 4096, batch_limit: 128, }
209 }
210}
211
212#[derive(Debug, Clone, Copy)]
213pub struct MvccVacuumConfig {
214 pub interval_ms: u64,
216 pub batch_limit: usize,
218}
219
220impl Default for MvccVacuumConfig {
221 fn default() -> Self {
222 Self {
223 interval_ms: 15_000, batch_limit: 512,
225 }
226 }
227}