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