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 tokenization: ConfigTokenization,
25
26    pub search: ConfigSearch,
27
28    pub store: ConfigStore,
29}
30
31impl Config {
32    pub fn validate(&self) {
33        // Check 'write_buffer' for KV
34        if self.store.kv.database.write_buffer == 0 {
35            panic!("write_buffer for kv must not be zero");
36        }
37
38        // Check 'flush_after' for KV
39        if self.store.kv.database.flush_after >= self.store.kv.pool.inactive_after {
40            panic!("flush_after for kv must be strictly lower than inactive_after");
41        }
42
43        // Check 'consolidate_after' for FST
44        if self.store.fst.graph.consolidate_after >= self.store.fst.pool.inactive_after {
45            panic!("consolidate_after for fst must be strictly lower than inactive_after");
46        }
47    }
48}
49
50/// Configuration group for normalization options (Unicode normalization,
51/// stemming, lemmatization…).
52#[derive(Deserialize, Clone, Copy)]
53pub struct ConfigNormalization {
54    pub diacritic_folding_enabled: bool,
55
56    #[cfg(feature = "stemming")]
57    pub stemming_enabled: bool,
58}
59
60/// Configuration group for tokenization options.
61#[derive(Deserialize, Clone, Copy)]
62pub struct ConfigTokenization {
63    pub detect_special_patterns: bool,
64
65    #[serde(alias = "split_special_patterns")]
66    pub compat_split_special_patterns: bool,
67}
68
69#[derive(Deserialize)]
70pub struct ConfigSearch {
71    pub query_limit_default: u16,
72
73    pub query_limit_maximum: u16,
74
75    pub query_alternates_try: usize,
76
77    pub suggest_limit_default: u16,
78
79    pub suggest_limit_maximum: u16,
80
81    pub list_limit_default: u16,
82
83    pub list_limit_maximum: u16,
84}
85
86#[derive(Deserialize)]
87pub struct ConfigStore {
88    pub kv: Arc<ConfigStoreKV>,
89
90    pub fst: Arc<ConfigStoreFST>,
91}
92
93#[derive(Deserialize)]
94pub struct ConfigStoreKV {
95    #[serde(deserialize_with = "env_var::path_buf")]
96    pub path: PathBuf,
97
98    pub retain_word_objects: usize,
99
100    pub pool: ConfigStoreKVPool,
101
102    pub database: ConfigStoreKVDatabase,
103}
104
105#[derive(Deserialize)]
106pub struct ConfigStoreKVPool {
107    pub inactive_after: u64,
108}
109
110#[derive(Deserialize)]
111pub struct ConfigStoreKVDatabase {
112    pub flush_after: u64,
113
114    pub compress: bool,
115
116    pub parallelism: u16,
117
118    pub max_files: Option<u32>,
119
120    pub max_compactions: u16,
121
122    pub max_flushes: u16,
123
124    pub write_buffer: usize,
125
126    pub write_ahead_log: bool,
127}
128
129#[derive(Deserialize)]
130pub struct ConfigStoreFST {
131    #[serde(deserialize_with = "env_var::path_buf")]
132    pub path: PathBuf,
133
134    pub pool: ConfigStoreFSTPool,
135
136    pub graph: ConfigStoreFSTGraph,
137}
138
139#[derive(Deserialize)]
140pub struct ConfigStoreFSTPool {
141    pub inactive_after: u64,
142}
143
144#[derive(Deserialize)]
145pub struct ConfigStoreFSTGraph {
146    pub consolidate_after: u64,
147
148    pub max_size: usize,
149
150    pub max_words: usize,
151}
152
153#[cfg(test)]
154pub(crate) mod tests {
155    pub fn defaults_toml() -> &'static str {
156        r#"
157        [channel]
158        inet = "[::1]:1491"
159        tcp_timeout = 300
160
161        [normalization]
162        diacritic_folding_enabled = true
163        stemming_enabled = false
164
165        [tokenization]
166        detect_special_patterns = true
167        compat_split_special_patterns = false
168
169        [search]
170        query_limit_default = 10
171        query_limit_maximum = 100
172        query_alternates_try = 4
173        suggest_limit_default = 5
174        suggest_limit_maximum = 20
175        list_limit_default = 100
176        list_limit_maximum = 500
177
178        [store.kv]
179        path = "./data/store/kv/"
180        retain_word_objects = 1000
181        pool.inactive_after = 1800
182        database.flush_after = 900
183        database.compress = true
184        database.parallelism = 2
185        database.max_compactions = 1
186        database.max_flushes = 1
187        database.write_buffer = 16384
188        database.write_ahead_log = true
189
190        [store.fst]
191        path = "./data/store/fst/"
192        pool.inactive_after = 300
193        graph.consolidate_after = 180
194        graph.max_size = 2048
195        graph.max_words = 250000
196        "#
197    }
198}