Skip to main content

nodedb_types/config/tuning/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2
3mod bitemporal;
4mod data_plane;
5mod engines;
6mod memory;
7mod network;
8mod scheduler;
9mod shutdown;
10
11pub use bitemporal::BitemporalTuning;
12pub use data_plane::{DataPlaneTuning, QueryTuning};
13pub use engines::{
14    DEFAULT_MAX_DEPTH, DEFAULT_MAX_VISITED, GraphTuning, KvTuning, SparseTuning, TimeseriesToning,
15    VectorTuning,
16};
17pub use memory::MemoryTuning;
18pub use network::{BridgeTuning, ClusterTransportTuning, NetworkTuning, WalTuning};
19pub use scheduler::SchedulerTuning;
20pub use shutdown::ShutdownTuning;
21
22use serde::{Deserialize, Serialize};
23
24/// Top-level tuning configuration.
25///
26/// All fields have sensible defaults derived from the current hardcoded values.
27/// Override via the `[tuning]` section in `config.toml`.
28#[derive(Debug, Clone, Default, Serialize, Deserialize)]
29pub struct TuningConfig {
30    #[serde(default)]
31    pub data_plane: DataPlaneTuning,
32    #[serde(default)]
33    pub query: QueryTuning,
34    #[serde(default)]
35    pub vector: VectorTuning,
36    #[serde(default)]
37    pub sparse: SparseTuning,
38    #[serde(default)]
39    pub graph: GraphTuning,
40    #[serde(default)]
41    pub timeseries: TimeseriesToning,
42    #[serde(default)]
43    pub kv: KvTuning,
44    #[serde(default)]
45    pub bridge: BridgeTuning,
46    #[serde(default)]
47    pub network: NetworkTuning,
48    #[serde(default)]
49    pub wal: WalTuning,
50    #[serde(default)]
51    pub cluster_transport: ClusterTransportTuning,
52    #[serde(default)]
53    pub memory: MemoryTuning,
54    #[serde(default)]
55    pub scheduler: SchedulerTuning,
56    #[serde(default)]
57    pub shutdown: ShutdownTuning,
58    #[serde(default)]
59    pub bitemporal: BitemporalTuning,
60}
61
62impl TuningConfig {
63    /// Tick interval for the bitemporal audit-retention enforcement loop.
64    /// Returns `None` when the operator wants the loop default; returns
65    /// `Some(d)` when `[tuning.bitemporal] tick_interval_secs` is set.
66    pub fn bitemporal_retention_tick(&self) -> Option<std::time::Duration> {
67        Some(self.bitemporal.tick_interval())
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    #[test]
76    fn default_tuning_roundtrip() {
77        let cfg = TuningConfig::default();
78        let toml_str = toml::to_string_pretty(&cfg).expect("serialize");
79        let parsed: TuningConfig = toml::from_str(&toml_str).expect("deserialize");
80
81        assert_eq!(parsed.data_plane.idle_poll_timeout_ms, 100);
82        assert_eq!(parsed.query.sort_run_size, 100_000);
83        assert_eq!(parsed.vector.flat_index_threshold, 10_000);
84        assert_eq!(parsed.sparse.bm25_k1, 1.2);
85        assert_eq!(parsed.graph.max_visited, 100_000);
86        assert_eq!(parsed.timeseries.memtable_budget_bytes, 64 * 1024 * 1024);
87        assert_eq!(parsed.kv.default_capacity, 16_384);
88        assert_eq!(parsed.kv.rehash_load_factor, 0.75);
89        assert_eq!(parsed.kv.expiry_reap_budget, 1024);
90        assert_eq!(parsed.bridge.slab_page_size, 64 * 1024);
91        assert_eq!(parsed.network.default_deadline_secs, 30);
92        assert_eq!(parsed.wal.write_buffer_size, 2 * 1024 * 1024);
93        assert_eq!(parsed.cluster_transport.raft_tick_interval_ms, 10);
94        // New ClusterTransportTuning fields.
95        assert_eq!(
96            parsed.cluster_transport.broadcast_threshold_bytes,
97            8 * 1024 * 1024
98        );
99        assert_eq!(parsed.cluster_transport.ghost_sweep_interval_secs, 1800);
100        assert_eq!(parsed.cluster_transport.health_ping_interval_secs, 5);
101        assert_eq!(parsed.cluster_transport.health_failure_threshold, 3);
102        // New QueryTuning fields.
103        assert_eq!(parsed.query.doc_cache_entries, 4096);
104        assert_eq!(parsed.query.columnar_flush_threshold, 65_536);
105        assert_eq!(parsed.query.compaction_target_bytes, 256 * 1024 * 1024);
106        // New MemoryTuning fields.
107        assert_eq!(parsed.memory.overflow_initial_bytes, 64 * 1024 * 1024);
108        assert_eq!(parsed.memory.overflow_max_bytes, 1024 * 1024 * 1024);
109        assert_eq!(parsed.memory.doc_cache_entries, 4096);
110        assert_eq!(parsed.shutdown.deadline_ms, 900);
111    }
112
113    #[test]
114    fn partial_override() {
115        let toml_str = r#"
116[query]
117sort_run_size = 50000
118
119[network]
120default_deadline_secs = 60
121"#;
122        let cfg: TuningConfig = toml::from_str(toml_str).expect("deserialize");
123        assert_eq!(cfg.query.sort_run_size, 50_000);
124        assert_eq!(cfg.network.default_deadline_secs, 60);
125        assert_eq!(cfg.query.aggregate_scan_cap, 10_000_000);
126        assert_eq!(cfg.vector.seal_threshold, 65_536);
127        // Unset fields retain defaults.
128        assert_eq!(cfg.query.columnar_flush_threshold, 65_536);
129        assert_eq!(cfg.query.compaction_target_bytes, 256 * 1024 * 1024);
130    }
131
132    #[test]
133    fn empty_toml_yields_defaults() {
134        let cfg: TuningConfig = toml::from_str("").expect("deserialize");
135        assert_eq!(cfg.data_plane.max_consecutive_panics, 3);
136        assert_eq!(cfg.graph.max_depth, 10);
137        // Memory tuning defaults.
138        assert_eq!(cfg.memory.overflow_initial_bytes, 64 * 1024 * 1024);
139        assert_eq!(cfg.memory.overflow_max_bytes, 1024 * 1024 * 1024);
140        assert_eq!(cfg.memory.doc_cache_entries, 4096);
141        // Cluster transport new defaults.
142        assert_eq!(
143            cfg.cluster_transport.broadcast_threshold_bytes,
144            8 * 1024 * 1024
145        );
146        assert_eq!(cfg.cluster_transport.ghost_sweep_interval_secs, 1800);
147        assert_eq!(cfg.cluster_transport.health_ping_interval_secs, 5);
148        assert_eq!(cfg.cluster_transport.health_failure_threshold, 3);
149    }
150
151    #[test]
152    fn memory_tuning_override() {
153        let toml_str = r#"
154[memory]
155overflow_initial_bytes = 134217728
156overflow_max_bytes = 2147483648
157doc_cache_entries = 8192
158"#;
159        let cfg: TuningConfig = toml::from_str(toml_str).expect("deserialize");
160        assert_eq!(cfg.memory.overflow_initial_bytes, 128 * 1024 * 1024);
161        assert_eq!(cfg.memory.overflow_max_bytes, 2 * 1024 * 1024 * 1024);
162        assert_eq!(cfg.memory.doc_cache_entries, 8192);
163    }
164}