store_api/
mito_engine_options.rs1use std::collections::HashMap;
19
20pub use common_wal::options::WAL_OPTIONS_KEY;
22pub const APPEND_MODE_KEY: &str = "append_mode";
24pub const WRITE_BUFFER_SIZE_KEY: &str = "write_buffer_size";
26pub const MERGE_MODE_KEY: &str = "merge_mode";
28pub const TTL_KEY: &str = "ttl";
30pub const AUTO_FLUSH_INTERVAL_KEY: &str = "auto_flush_interval";
32pub const COMPACTION_EXPERIMENTAL_OUTPUT_PARALLELISM: &str =
34 "compaction.experimental_output_parallelism";
35pub const COMPACTION_TYPE: &str = "compaction.type";
37pub const COMPACTION_OVERRIDE: &str = "compaction.override";
39pub const COMPACTION_TYPE_TWCS: &str = "twcs";
41pub const COMPACTION_TWCS_PREFIX: &str = "compaction.twcs.";
43pub const TWCS_TRIGGER_FILE_NUM: &str = "compaction.twcs.trigger_file_num";
45pub const TWCS_ACTIVE_WINDOW_TRIGGER_FILE_NUM: &str =
47 "compaction.twcs.active_window.trigger_file_num";
48pub const TWCS_ACTIVE_WINDOW_L1_MERGE_TRIGGER: &str =
50 "compaction.twcs.active_window.l1_merge_trigger";
51pub const TWCS_INACTIVE_WINDOW_TRIGGER_FILE_NUM: &str =
53 "compaction.twcs.inactive_window.trigger_file_num";
54pub const TWCS_INACTIVE_WINDOW_L1_MERGE_TRIGGER: &str =
56 "compaction.twcs.inactive_window.l1_merge_trigger";
57pub const TWCS_MAX_OUTPUT_FILE_SIZE: &str = "compaction.twcs.max_output_file_size";
59pub const TWCS_TIME_WINDOW: &str = "compaction.twcs.time_window";
61pub const TWCS_REMOTE_COMPACTION: &str = "compaction.twcs.remote_compaction";
63pub const TWCS_FALLBACK_TO_LOCAL: &str = "compaction.twcs.fallback_to_local";
65pub const COMPACTION_OPTION_KEYS: [&str; 11] = [
67 COMPACTION_TYPE,
68 COMPACTION_OVERRIDE,
69 TWCS_TRIGGER_FILE_NUM,
70 TWCS_ACTIVE_WINDOW_TRIGGER_FILE_NUM,
71 TWCS_ACTIVE_WINDOW_L1_MERGE_TRIGGER,
72 TWCS_INACTIVE_WINDOW_TRIGGER_FILE_NUM,
73 TWCS_INACTIVE_WINDOW_L1_MERGE_TRIGGER,
74 TWCS_MAX_OUTPUT_FILE_SIZE,
75 TWCS_TIME_WINDOW,
76 TWCS_REMOTE_COMPACTION,
77 TWCS_FALLBACK_TO_LOCAL,
78];
79pub const MEMTABLE_TYPE: &str = "memtable.type";
81pub const MEMTABLE_BULK_MERGE_THRESHOLD: &str = "memtable.bulk.merge_threshold";
83pub const MEMTABLE_BULK_ENCODE_ROW_THRESHOLD: &str = "memtable.bulk.encode_row_threshold";
85pub const MEMTABLE_BULK_ENCODE_BYTES_THRESHOLD: &str = "memtable.bulk.encode_bytes_threshold";
87pub const MEMTABLE_BULK_MAX_MERGE_GROUPS: &str = "memtable.bulk.max_merge_groups";
89pub const MEMTABLE_PARTITION_TREE_INDEX_MAX_KEYS_PER_SHARD: &str =
91 "memtable.partition_tree.index_max_keys_per_shard";
92pub const MEMTABLE_PARTITION_TREE_DATA_FREEZE_THRESHOLD: &str =
94 "memtable.partition_tree.data_freeze_threshold";
95pub const MEMTABLE_PARTITION_TREE_FORK_DICTIONARY_BYTES: &str =
97 "memtable.partition_tree.fork_dictionary_bytes";
98pub const SKIP_WAL_KEY: &str = "skip_wal";
100pub const SST_FORMAT_KEY: &str = "sst_format";
102pub const MAX_ROW_GROUP_ROW_COUNT: &str = "max_row_group_row_count";
104pub const MAX_ROW_GROUP_ROW_COUNT_LIMIT: usize = 10 * 1024 * 1024;
106pub const PRESERVE_ROW_SEQUENCE: &str = "preserve_row_sequence";
108pub const EXPERIMENTAL_SST_FLOAT_FIELD_ENCODING: &str = "experimental_sst_float_field_encoding";
110
111#[derive(
113 Debug,
114 Default,
115 Clone,
116 Copy,
117 PartialEq,
118 Eq,
119 Hash,
120 serde::Serialize,
121 serde::Deserialize,
122 strum::EnumString,
123)]
124#[serde(rename_all = "snake_case")]
125#[strum(serialize_all = "snake_case")]
126pub enum FloatFieldEncoding {
127 #[default]
129 Default,
130 ByteStreamSplit,
132}
133#[derive(Debug, PartialEq, Eq)]
137pub struct TwcsTriggerOptionConflict {
138 pub legacy_value: String,
140 pub canonical_value: String,
142}
143
144pub fn normalize_twcs_trigger_options(
146 options: &mut HashMap<String, String>,
147) -> Result<(), TwcsTriggerOptionConflict> {
148 let Some(canonical_value) = options.get(TWCS_ACTIVE_WINDOW_TRIGGER_FILE_NUM).cloned() else {
149 return Ok(());
150 };
151 if let Some(legacy_value) = options.get(TWCS_TRIGGER_FILE_NUM)
152 && legacy_value != &canonical_value
153 {
154 return Err(TwcsTriggerOptionConflict {
155 legacy_value: legacy_value.clone(),
156 canonical_value,
157 });
158 }
159
160 options.remove(TWCS_ACTIVE_WINDOW_TRIGGER_FILE_NUM);
161 options.insert(TWCS_TRIGGER_FILE_NUM.to_string(), canonical_value);
162 Ok(())
163}
164
165pub fn is_mito_engine_option_key(key: &str) -> bool {
167 COMPACTION_OPTION_KEYS.contains(&key)
168 || [
169 "ttl",
170 WRITE_BUFFER_SIZE_KEY,
171 AUTO_FLUSH_INTERVAL_KEY,
172 COMPACTION_EXPERIMENTAL_OUTPUT_PARALLELISM,
173 "storage",
174 "index.inverted_index.ignore_column_ids",
175 "index.inverted_index.segment_row_count",
176 WAL_OPTIONS_KEY,
177 MEMTABLE_TYPE,
178 MEMTABLE_BULK_MERGE_THRESHOLD,
179 MEMTABLE_BULK_ENCODE_ROW_THRESHOLD,
180 MEMTABLE_BULK_ENCODE_BYTES_THRESHOLD,
181 MEMTABLE_BULK_MAX_MERGE_GROUPS,
182 MEMTABLE_PARTITION_TREE_INDEX_MAX_KEYS_PER_SHARD,
183 MEMTABLE_PARTITION_TREE_DATA_FREEZE_THRESHOLD,
184 MEMTABLE_PARTITION_TREE_FORK_DICTIONARY_BYTES,
185 APPEND_MODE_KEY,
187 MERGE_MODE_KEY,
188 SST_FORMAT_KEY,
189 MAX_ROW_GROUP_ROW_COUNT,
190 PRESERVE_ROW_SEQUENCE,
191 EXPERIMENTAL_SST_FLOAT_FIELD_ENCODING,
192 ]
193 .contains(&key)
194}
195
196#[cfg(test)]
197mod tests {
198 use std::collections::HashMap;
199
200 use super::*;
201
202 #[test]
203 fn test_is_mito_engine_option_key() {
204 assert!(is_mito_engine_option_key("ttl"));
205 assert!(is_mito_engine_option_key("write_buffer_size"));
206 assert!(is_mito_engine_option_key("auto_flush_interval"));
207 assert!(is_mito_engine_option_key(
208 "compaction.experimental_output_parallelism"
209 ));
210 assert!(is_mito_engine_option_key("compaction.type"));
211 assert!(is_mito_engine_option_key("compaction.override"));
212 assert!(is_mito_engine_option_key(
213 "compaction.twcs.trigger_file_num"
214 ));
215 assert!(is_mito_engine_option_key(
216 "compaction.twcs.active_window.trigger_file_num"
217 ));
218 assert!(is_mito_engine_option_key(
219 "compaction.twcs.active_window.l1_merge_trigger"
220 ));
221 assert!(is_mito_engine_option_key(
222 "compaction.twcs.inactive_window.trigger_file_num"
223 ));
224 assert!(is_mito_engine_option_key(
225 "compaction.twcs.inactive_window.l1_merge_trigger"
226 ));
227 assert!(is_mito_engine_option_key("compaction.twcs.time_window"));
228 assert!(is_mito_engine_option_key("storage"));
229 assert!(is_mito_engine_option_key(
230 "index.inverted_index.ignore_column_ids"
231 ));
232 assert!(is_mito_engine_option_key(
233 "index.inverted_index.segment_row_count"
234 ));
235 assert!(is_mito_engine_option_key("wal_options"));
236 assert!(is_mito_engine_option_key("memtable.type"));
237 assert!(is_mito_engine_option_key("memtable.bulk.merge_threshold"));
238 assert!(is_mito_engine_option_key(
239 "memtable.bulk.encode_row_threshold"
240 ));
241 assert!(is_mito_engine_option_key(
242 "memtable.bulk.encode_bytes_threshold"
243 ));
244 assert!(is_mito_engine_option_key("memtable.bulk.max_merge_groups"));
245 assert!(is_mito_engine_option_key(
246 "memtable.partition_tree.index_max_keys_per_shard"
247 ));
248 assert!(is_mito_engine_option_key(
249 "memtable.partition_tree.data_freeze_threshold"
250 ));
251 assert!(is_mito_engine_option_key(
252 "memtable.partition_tree.fork_dictionary_bytes"
253 ));
254 assert!(is_mito_engine_option_key("append_mode"));
255 assert!(is_mito_engine_option_key("max_row_group_row_count"));
256 assert!(is_mito_engine_option_key("preserve_row_sequence"));
257 assert!(is_mito_engine_option_key(
258 EXPERIMENTAL_SST_FLOAT_FIELD_ENCODING
259 ));
260 assert!(!is_mito_engine_option_key("foo"));
261 }
262
263 #[test]
264 fn test_float_field_encoding_values() {
265 assert_eq!(
266 "default".parse::<FloatFieldEncoding>(),
267 Ok(FloatFieldEncoding::Default)
268 );
269 assert_eq!(
270 "byte_stream_split".parse::<FloatFieldEncoding>(),
271 Ok(FloatFieldEncoding::ByteStreamSplit)
272 );
273 assert_eq!(
274 serde_json::from_str::<FloatFieldEncoding>("\"byte_stream_split\"").unwrap(),
275 FloatFieldEncoding::ByteStreamSplit
276 );
277 assert!(serde_json::from_str::<FloatFieldEncoding>("\"unknown\"").is_err());
278 }
279
280 #[test]
281 fn test_normalize_twcs_trigger_aliases_to_legacy_key() {
282 let expected = HashMap::from([(TWCS_TRIGGER_FILE_NUM.to_string(), "4".to_string())]);
283 for mut options in [
284 HashMap::from([(TWCS_TRIGGER_FILE_NUM.to_string(), "4".to_string())]),
285 HashMap::from([(
286 TWCS_ACTIVE_WINDOW_TRIGGER_FILE_NUM.to_string(),
287 "4".to_string(),
288 )]),
289 HashMap::from([
290 (TWCS_TRIGGER_FILE_NUM.to_string(), "4".to_string()),
291 (
292 TWCS_ACTIVE_WINDOW_TRIGGER_FILE_NUM.to_string(),
293 "4".to_string(),
294 ),
295 ]),
296 ] {
297 normalize_twcs_trigger_options(&mut options).unwrap();
298 assert_eq!(expected, options);
299 }
300 }
301
302 #[test]
303 fn test_normalize_twcs_trigger_conflicting_aliases() {
304 let mut options = HashMap::from([
305 (TWCS_TRIGGER_FILE_NUM.to_string(), "4".to_string()),
306 (
307 TWCS_ACTIVE_WINDOW_TRIGGER_FILE_NUM.to_string(),
308 "8".to_string(),
309 ),
310 ]);
311 let original = options.clone();
312
313 let error = normalize_twcs_trigger_options(&mut options).unwrap_err();
314
315 assert_eq!("4", error.legacy_value);
316 assert_eq!("8", error.canonical_value);
317 assert_eq!(original, options);
318 }
319}