metric_engine/engine/
options.rs1use std::collections::HashMap;
18
19use store_api::metric_engine_consts::{
20 METRIC_ENGINE_INDEX_SKIPPING_INDEX_FALSE_POSITIVE_RATE_OPTION,
21 METRIC_ENGINE_INDEX_SKIPPING_INDEX_FALSE_POSITIVE_RATE_OPTION_DEFAULT,
22 METRIC_ENGINE_INDEX_SKIPPING_INDEX_GRANULARITY_OPTION,
23 METRIC_ENGINE_INDEX_SKIPPING_INDEX_GRANULARITY_OPTION_DEFAULT, METRIC_ENGINE_INDEX_TYPE_OPTION,
24};
25use store_api::mito_engine_options::MEMTABLE_PARTITION_TREE_PRIMARY_KEY_ENCODING;
26
27use crate::error::{Error, ParseRegionOptionsSnafu, Result};
28
29const SEG_ROW_COUNT_FOR_DATA_REGION: u32 = 256;
34
35#[derive(Debug, Clone, Copy, PartialEq)]
37pub struct PhysicalRegionOptions {
38 pub index: IndexOptions,
39}
40
41#[derive(Debug, Clone, Copy, Default, PartialEq)]
43pub enum IndexOptions {
44 #[default]
45 None,
46 Inverted,
47 Skipping {
48 granularity: u32,
49 false_positive_rate: f64,
50 },
51}
52
53pub fn set_data_region_options(
55 options: &mut HashMap<String, String>,
56 sparse_primary_key_encoding_if_absent: bool,
57) {
58 options.remove(METRIC_ENGINE_INDEX_TYPE_OPTION);
59 options.remove(METRIC_ENGINE_INDEX_SKIPPING_INDEX_GRANULARITY_OPTION);
60 options.remove(METRIC_ENGINE_INDEX_SKIPPING_INDEX_FALSE_POSITIVE_RATE_OPTION);
61 options.insert(
62 "index.inverted_index.segment_row_count".to_string(),
63 SEG_ROW_COUNT_FOR_DATA_REGION.to_string(),
64 );
65 options.insert("memtable.type".to_string(), "partition_tree".to_string());
67 if sparse_primary_key_encoding_if_absent
68 && !options.contains_key(MEMTABLE_PARTITION_TREE_PRIMARY_KEY_ENCODING)
69 {
70 options.insert(
71 MEMTABLE_PARTITION_TREE_PRIMARY_KEY_ENCODING.to_string(),
72 "sparse".to_string(),
73 );
74 }
75}
76
77impl TryFrom<&HashMap<String, String>> for PhysicalRegionOptions {
78 type Error = Error;
79
80 fn try_from(value: &HashMap<String, String>) -> Result<Self> {
81 let index = match value
82 .get(METRIC_ENGINE_INDEX_TYPE_OPTION)
83 .map(|s| s.to_lowercase())
84 {
85 Some(ref index_type) if index_type == "inverted" => Ok(IndexOptions::Inverted),
86 Some(ref index_type) if index_type == "skipping" => {
87 let granularity = value
88 .get(METRIC_ENGINE_INDEX_SKIPPING_INDEX_GRANULARITY_OPTION)
89 .map_or(
90 Ok(METRIC_ENGINE_INDEX_SKIPPING_INDEX_GRANULARITY_OPTION_DEFAULT),
91 |g| {
92 g.parse().map_err(|_| {
93 ParseRegionOptionsSnafu {
94 reason: format!("Invalid granularity: {}", g),
95 }
96 .build()
97 })
98 },
99 )?;
100 let false_positive_rate = value
101 .get(METRIC_ENGINE_INDEX_SKIPPING_INDEX_FALSE_POSITIVE_RATE_OPTION)
102 .map_or(
103 Ok(METRIC_ENGINE_INDEX_SKIPPING_INDEX_FALSE_POSITIVE_RATE_OPTION_DEFAULT),
104 |f| {
105 f.parse().ok().filter(|f| *f > 0.0 && *f <= 1.0).ok_or(
106 ParseRegionOptionsSnafu {
107 reason: format!("Invalid false positive rate: {}", f),
108 }
109 .build(),
110 )
111 },
112 )?;
113 Ok(IndexOptions::Skipping {
114 granularity,
115 false_positive_rate,
116 })
117 }
118 Some(index_type) => ParseRegionOptionsSnafu {
119 reason: format!("Invalid index type: {}", index_type),
120 }
121 .fail(),
122 None => Ok(IndexOptions::default()),
123 }?;
124
125 Ok(PhysicalRegionOptions { index })
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132
133 #[test]
134 fn test_set_data_region_options_should_remove_metric_engine_options() {
135 let mut options = HashMap::new();
136 options.insert(
137 METRIC_ENGINE_INDEX_TYPE_OPTION.to_string(),
138 "inverted".to_string(),
139 );
140 options.insert(
141 METRIC_ENGINE_INDEX_SKIPPING_INDEX_GRANULARITY_OPTION.to_string(),
142 "102400".to_string(),
143 );
144 options.insert(
145 METRIC_ENGINE_INDEX_SKIPPING_INDEX_FALSE_POSITIVE_RATE_OPTION.to_string(),
146 "0.01".to_string(),
147 );
148 set_data_region_options(&mut options, false);
149
150 for key in [
151 METRIC_ENGINE_INDEX_TYPE_OPTION,
152 METRIC_ENGINE_INDEX_SKIPPING_INDEX_GRANULARITY_OPTION,
153 METRIC_ENGINE_INDEX_SKIPPING_INDEX_FALSE_POSITIVE_RATE_OPTION,
154 ] {
155 assert_eq!(options.get(key), None);
156 }
157 }
158
159 #[test]
160 fn test_deserialize_physical_region_options_from_hashmap() {
161 let mut options = HashMap::new();
162 options.insert(
163 METRIC_ENGINE_INDEX_TYPE_OPTION.to_string(),
164 "inverted".to_string(),
165 );
166 options.insert(
167 METRIC_ENGINE_INDEX_SKIPPING_INDEX_GRANULARITY_OPTION.to_string(),
168 "102400".to_string(),
169 );
170 let physical_region_options = PhysicalRegionOptions::try_from(&options).unwrap();
171 assert_eq!(physical_region_options.index, IndexOptions::Inverted);
172
173 let mut options = HashMap::new();
174 options.insert(
175 METRIC_ENGINE_INDEX_TYPE_OPTION.to_string(),
176 "skipping".to_string(),
177 );
178 options.insert(
179 METRIC_ENGINE_INDEX_SKIPPING_INDEX_GRANULARITY_OPTION.to_string(),
180 "102400".to_string(),
181 );
182 options.insert(
183 METRIC_ENGINE_INDEX_SKIPPING_INDEX_FALSE_POSITIVE_RATE_OPTION.to_string(),
184 "0.01".to_string(),
185 );
186 let physical_region_options = PhysicalRegionOptions::try_from(&options).unwrap();
187 assert_eq!(
188 physical_region_options.index,
189 IndexOptions::Skipping {
190 granularity: 102400,
191 false_positive_rate: 0.01,
192 }
193 );
194 }
195}