Skip to main content

sonic/
config.rs

1// Sonic
2//
3// Fast, lightweight and schema-less search backend
4// Copyright: 2019, Valerian Saliou <valerian@valeriansaliou.name>
5// Copyright: 2026, Rémi Bardon <remi@remibardon.name>
6// License: Mozilla Public License v2.0 (MPL v2.0)
7
8//! Sonic library configuration.
9//!
10//! It does not include server nor channel configuration, which are specific
11//! to the `sonic-server` binary.
12
13use std::path::PathBuf;
14use std::sync::Arc;
15
16use serde::Deserialize;
17
18use crate::util::serde::env_var;
19
20#[derive(Deserialize)]
21pub struct Config {
22    pub normalization: ConfigNormalization,
23
24    pub search: ConfigSearch,
25
26    pub store: ConfigStore,
27}
28
29impl Config {
30    pub fn validate(&self) {
31        // Check 'write_buffer' for KV
32        if self.store.kv.database.write_buffer == 0 {
33            panic!("write_buffer for kv must not be zero");
34        }
35
36        // Check 'flush_after' for KV
37        if self.store.kv.database.flush_after >= self.store.kv.pool.inactive_after {
38            panic!("flush_after for kv must be strictly lower than inactive_after");
39        }
40
41        // Check 'consolidate_after' for FST
42        if self.store.fst.graph.consolidate_after >= self.store.fst.pool.inactive_after {
43            panic!("consolidate_after for fst must be strictly lower than inactive_after");
44        }
45    }
46}
47
48/// Configuration group for normalization options (Unicode normalization,
49/// stemming, lemmatization…).
50#[derive(Deserialize, Clone, Copy)]
51pub struct ConfigNormalization {
52    pub diacritic_folding_enabled: bool,
53
54    #[cfg(feature = "stemming")]
55    pub stemming_enabled: bool,
56}
57
58#[derive(Deserialize)]
59pub struct ConfigSearch {
60    pub query_limit_default: u16,
61
62    pub query_limit_maximum: u16,
63
64    pub query_alternates_try: usize,
65
66    pub suggest_limit_default: u16,
67
68    pub suggest_limit_maximum: u16,
69
70    pub list_limit_default: u16,
71
72    pub list_limit_maximum: u16,
73}
74
75#[derive(Deserialize)]
76pub struct ConfigStore {
77    pub kv: Arc<ConfigStoreKV>,
78
79    pub fst: Arc<ConfigStoreFST>,
80}
81
82#[derive(Deserialize)]
83pub struct ConfigStoreKV {
84    #[serde(deserialize_with = "env_var::path_buf")]
85    pub path: PathBuf,
86
87    pub retain_word_objects: usize,
88
89    pub pool: ConfigStoreKVPool,
90
91    pub database: ConfigStoreKVDatabase,
92}
93
94#[derive(Deserialize)]
95pub struct ConfigStoreKVPool {
96    pub inactive_after: u64,
97}
98
99#[derive(Deserialize)]
100pub struct ConfigStoreKVDatabase {
101    pub flush_after: u64,
102
103    pub compress: bool,
104
105    pub parallelism: u16,
106
107    pub max_files: Option<u32>,
108
109    pub max_compactions: u16,
110
111    pub max_flushes: u16,
112
113    pub write_buffer: usize,
114
115    pub write_ahead_log: bool,
116}
117
118#[derive(Deserialize)]
119pub struct ConfigStoreFST {
120    #[serde(deserialize_with = "env_var::path_buf")]
121    pub path: PathBuf,
122
123    pub pool: ConfigStoreFSTPool,
124
125    pub graph: ConfigStoreFSTGraph,
126}
127
128#[derive(Deserialize)]
129pub struct ConfigStoreFSTPool {
130    pub inactive_after: u64,
131}
132
133#[derive(Deserialize)]
134pub struct ConfigStoreFSTGraph {
135    pub consolidate_after: u64,
136
137    pub max_size: usize,
138
139    pub max_words: usize,
140}
141
142#[cfg(test)]
143pub(crate) mod tests {
144    pub fn defaults_toml() -> &'static str {
145        r#"
146        [channel]
147        inet = "[::1]:1491"
148        tcp_timeout = 300
149
150        [normalization]
151        diacritic_folding_enabled = true
152        stemming_enabled = false
153
154        [search]
155        query_limit_default = 10
156        query_limit_maximum = 100
157        query_alternates_try = 4
158        suggest_limit_default = 5
159        suggest_limit_maximum = 20
160        list_limit_default = 100
161        list_limit_maximum = 500
162
163        [store.kv]
164        path = "./data/store/kv/"
165        retain_word_objects = 1000
166        pool.inactive_after = 1800
167        database.flush_after = 900
168        database.compress = true
169        database.parallelism = 2
170        database.max_compactions = 1
171        database.max_flushes = 1
172        database.write_buffer = 16384
173        database.write_ahead_log = true
174
175        [store.fst]
176        path = "./data/store/fst/"
177        pool.inactive_after = 300
178        graph.consolidate_after = 180
179        graph.max_size = 2048
180        graph.max_words = 250000
181        "#
182    }
183}