Skip to main content

nodedb_lite/config/
validate.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! [`LiteConfig::validate`] — coherence checks for the percentage fields.
4
5use nodedb_types::error::{NodeDbError, NodeDbResult};
6
7use super::defaults::MAX_TOTAL_ENGINE_PERCENT;
8use super::types::LiteConfig;
9
10impl LiteConfig {
11    /// Validate that percentage fields are coherent.
12    ///
13    /// Returns an error if:
14    /// - Any individual percentage exceeds 100
15    /// - The sum of all engine percentages exceeds `MAX_TOTAL_ENGINE_PERCENT`
16    pub fn validate(&self) -> NodeDbResult<()> {
17        for (name, pct) in [
18            ("hnsw_percent", self.hnsw_percent),
19            ("csr_percent", self.csr_percent),
20            ("loro_percent", self.loro_percent),
21            ("query_percent", self.query_percent),
22            ("kv_percent", self.kv_percent),
23            ("document_percent", self.document_percent),
24            ("strict_percent", self.strict_percent),
25            ("columnar_percent", self.columnar_percent),
26            ("timeseries_percent", self.timeseries_percent),
27            ("spatial_percent", self.spatial_percent),
28            ("fts_percent", self.fts_percent),
29            ("array_percent", self.array_percent),
30            ("sparse_percent", self.sparse_percent),
31        ] {
32            if pct > 100 {
33                return Err(NodeDbError::config(format!(
34                    "{name} must be 0–100, got {pct}"
35                )));
36            }
37        }
38
39        let total = self
40            .hnsw_percent
41            .saturating_add(self.csr_percent)
42            .saturating_add(self.loro_percent)
43            .saturating_add(self.query_percent)
44            .saturating_add(self.kv_percent)
45            .saturating_add(self.document_percent)
46            .saturating_add(self.strict_percent)
47            .saturating_add(self.columnar_percent)
48            .saturating_add(self.timeseries_percent)
49            .saturating_add(self.spatial_percent)
50            .saturating_add(self.fts_percent)
51            .saturating_add(self.array_percent)
52            .saturating_add(self.sparse_percent);
53
54        if total > MAX_TOTAL_ENGINE_PERCENT {
55            return Err(NodeDbError::config(format!(
56                "sum of engine percentages is {total}%, must not exceed {MAX_TOTAL_ENGINE_PERCENT}% \
57                 (at least 1% headroom required)"
58            )));
59        }
60
61        Ok(())
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn default_config_validates() {
71        assert!(LiteConfig::default().validate().is_ok());
72    }
73
74    #[test]
75    fn validate_rejects_percent_over_100() {
76        let cfg = LiteConfig {
77            hnsw_percent: 101,
78            ..LiteConfig::default()
79        };
80        assert!(cfg.validate().is_err());
81    }
82
83    #[test]
84    fn validate_rejects_sum_over_max() {
85        let cfg = LiteConfig {
86            hnsw_percent: 40,
87            csr_percent: 25,
88            loro_percent: 25,
89            query_percent: 15,
90            ..LiteConfig::default()
91        };
92        // Sum = 105 > 99.
93        assert!(cfg.validate().is_err());
94    }
95}