Skip to main content

grafeo_engine/
config.rs

1//! Database configuration.
2
3use std::path::PathBuf;
4
5/// Database configuration.
6#[derive(Debug, Clone)]
7pub struct Config {
8    /// Path to the database directory (None for in-memory only).
9    pub path: Option<PathBuf>,
10
11    /// Memory limit in bytes (None for unlimited).
12    pub memory_limit: Option<usize>,
13
14    /// Path for spilling data to disk under memory pressure.
15    pub spill_path: Option<PathBuf>,
16
17    /// Number of worker threads for query execution.
18    pub threads: usize,
19
20    /// Whether to enable WAL for durability.
21    pub wal_enabled: bool,
22
23    /// WAL flush interval in milliseconds.
24    pub wal_flush_interval_ms: u64,
25
26    /// Whether to maintain backward edges.
27    pub backward_edges: bool,
28
29    /// Whether to enable query logging.
30    pub query_logging: bool,
31
32    /// Adaptive execution configuration.
33    pub adaptive: AdaptiveConfig,
34}
35
36/// Configuration for adaptive query execution.
37///
38/// Adaptive execution monitors actual row counts during query processing and
39/// can trigger re-optimization when estimates are significantly wrong.
40#[derive(Debug, Clone)]
41pub struct AdaptiveConfig {
42    /// Whether adaptive execution is enabled.
43    pub enabled: bool,
44
45    /// Deviation threshold that triggers re-optimization.
46    ///
47    /// A value of 3.0 means re-optimization is triggered when actual cardinality
48    /// is more than 3x or less than 1/3x the estimated value.
49    pub threshold: f64,
50
51    /// Minimum number of rows before considering re-optimization.
52    ///
53    /// Helps avoid thrashing on small result sets.
54    pub min_rows: u64,
55
56    /// Maximum number of re-optimizations allowed per query.
57    pub max_reoptimizations: usize,
58}
59
60impl Default for AdaptiveConfig {
61    fn default() -> Self {
62        Self {
63            enabled: true,
64            threshold: 3.0,
65            min_rows: 1000,
66            max_reoptimizations: 3,
67        }
68    }
69}
70
71impl AdaptiveConfig {
72    /// Creates a disabled adaptive config.
73    #[must_use]
74    pub fn disabled() -> Self {
75        Self {
76            enabled: false,
77            ..Default::default()
78        }
79    }
80
81    /// Sets the deviation threshold.
82    #[must_use]
83    pub fn with_threshold(mut self, threshold: f64) -> Self {
84        self.threshold = threshold;
85        self
86    }
87
88    /// Sets the minimum rows before re-optimization.
89    #[must_use]
90    pub fn with_min_rows(mut self, min_rows: u64) -> Self {
91        self.min_rows = min_rows;
92        self
93    }
94
95    /// Sets the maximum number of re-optimizations.
96    #[must_use]
97    pub fn with_max_reoptimizations(mut self, max: usize) -> Self {
98        self.max_reoptimizations = max;
99        self
100    }
101}
102
103impl Default for Config {
104    fn default() -> Self {
105        Self {
106            path: None,
107            memory_limit: None,
108            spill_path: None,
109            threads: num_cpus::get(),
110            wal_enabled: true,
111            wal_flush_interval_ms: 100,
112            backward_edges: true,
113            query_logging: false,
114            adaptive: AdaptiveConfig::default(),
115        }
116    }
117}
118
119impl Config {
120    /// Creates a new configuration for an in-memory database.
121    #[must_use]
122    pub fn in_memory() -> Self {
123        Self {
124            path: None,
125            wal_enabled: false,
126            ..Default::default()
127        }
128    }
129
130    /// Creates a new configuration for a persistent database.
131    #[must_use]
132    pub fn persistent(path: impl Into<PathBuf>) -> Self {
133        Self {
134            path: Some(path.into()),
135            wal_enabled: true,
136            ..Default::default()
137        }
138    }
139
140    /// Sets the memory limit.
141    #[must_use]
142    pub fn with_memory_limit(mut self, limit: usize) -> Self {
143        self.memory_limit = Some(limit);
144        self
145    }
146
147    /// Sets the number of worker threads.
148    #[must_use]
149    pub fn with_threads(mut self, threads: usize) -> Self {
150        self.threads = threads;
151        self
152    }
153
154    /// Disables backward edges.
155    #[must_use]
156    pub fn without_backward_edges(mut self) -> Self {
157        self.backward_edges = false;
158        self
159    }
160
161    /// Enables query logging.
162    #[must_use]
163    pub fn with_query_logging(mut self) -> Self {
164        self.query_logging = true;
165        self
166    }
167
168    /// Sets the memory budget as a fraction of system RAM.
169    #[must_use]
170    pub fn with_memory_fraction(mut self, fraction: f64) -> Self {
171        use grafeo_common::memory::buffer::BufferManagerConfig;
172        let system_memory = BufferManagerConfig::detect_system_memory();
173        self.memory_limit = Some((system_memory as f64 * fraction) as usize);
174        self
175    }
176
177    /// Sets the spill directory for out-of-core processing.
178    #[must_use]
179    pub fn with_spill_path(mut self, path: impl Into<PathBuf>) -> Self {
180        self.spill_path = Some(path.into());
181        self
182    }
183
184    /// Sets the adaptive execution configuration.
185    #[must_use]
186    pub fn with_adaptive(mut self, adaptive: AdaptiveConfig) -> Self {
187        self.adaptive = adaptive;
188        self
189    }
190
191    /// Disables adaptive execution.
192    #[must_use]
193    pub fn without_adaptive(mut self) -> Self {
194        self.adaptive.enabled = false;
195        self
196    }
197}
198
199/// Helper function to get CPU count (fallback implementation).
200mod num_cpus {
201    pub fn get() -> usize {
202        std::thread::available_parallelism()
203            .map(|n| n.get())
204            .unwrap_or(4)
205    }
206}