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