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