metric_engine/engine/
options.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Specific options for the metric engine to create or open a region.
16
17use std::collections::HashMap;
18
19use store_api::metric_engine_consts::{
20    METRIC_ENGINE_INDEX_SKIPPING_INDEX_GRANULARITY_OPTION,
21    METRIC_ENGINE_INDEX_SKIPPING_INDEX_GRANULARITY_OPTION_DEFAULT, METRIC_ENGINE_INDEX_TYPE_OPTION,
22};
23use store_api::mito_engine_options::MEMTABLE_PARTITION_TREE_PRIMARY_KEY_ENCODING;
24
25use crate::error::{Error, ParseRegionOptionsSnafu, Result};
26
27/// The empirical value for the seg row count of the metric data region.
28/// Compared to the mito engine, the pattern of the metric engine constructs smaller indices.
29/// Therefore, compared to the default seg row count of 1024, by adjusting it to a smaller
30/// value and appropriately increasing the size of the index, it results in an improved indexing effect.
31const SEG_ROW_COUNT_FOR_DATA_REGION: u32 = 256;
32
33/// Physical region options.
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub struct PhysicalRegionOptions {
36    pub index: IndexOptions,
37}
38
39/// Index options for auto created columns
40#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
41pub enum IndexOptions {
42    #[default]
43    None,
44    Inverted,
45    Skipping {
46        granularity: u32,
47    },
48}
49
50/// Sets data region specific options.
51pub fn set_data_region_options(
52    options: &mut HashMap<String, String>,
53    sparse_primary_key_encoding_if_absent: bool,
54) {
55    options.remove(METRIC_ENGINE_INDEX_TYPE_OPTION);
56    options.remove(METRIC_ENGINE_INDEX_SKIPPING_INDEX_GRANULARITY_OPTION);
57    options.insert(
58        "index.inverted_index.segment_row_count".to_string(),
59        SEG_ROW_COUNT_FOR_DATA_REGION.to_string(),
60    );
61    // Set memtable options for the data region.
62    options.insert("memtable.type".to_string(), "partition_tree".to_string());
63    if sparse_primary_key_encoding_if_absent
64        && !options.contains_key(MEMTABLE_PARTITION_TREE_PRIMARY_KEY_ENCODING)
65    {
66        options.insert(
67            MEMTABLE_PARTITION_TREE_PRIMARY_KEY_ENCODING.to_string(),
68            "sparse".to_string(),
69        );
70    }
71}
72
73impl TryFrom<&HashMap<String, String>> for PhysicalRegionOptions {
74    type Error = Error;
75
76    fn try_from(value: &HashMap<String, String>) -> Result<Self> {
77        let index = match value
78            .get(METRIC_ENGINE_INDEX_TYPE_OPTION)
79            .map(|s| s.to_lowercase())
80        {
81            Some(ref index_type) if index_type == "inverted" => Ok(IndexOptions::Inverted),
82            Some(ref index_type) if index_type == "skipping" => {
83                let granularity = value
84                    .get(METRIC_ENGINE_INDEX_SKIPPING_INDEX_GRANULARITY_OPTION)
85                    .map_or(
86                        Ok(METRIC_ENGINE_INDEX_SKIPPING_INDEX_GRANULARITY_OPTION_DEFAULT),
87                        |g| {
88                            g.parse().map_err(|_| {
89                                ParseRegionOptionsSnafu {
90                                    reason: format!("Invalid granularity: {}", g),
91                                }
92                                .build()
93                            })
94                        },
95                    )?;
96                Ok(IndexOptions::Skipping { granularity })
97            }
98            Some(index_type) => ParseRegionOptionsSnafu {
99                reason: format!("Invalid index type: {}", index_type),
100            }
101            .fail(),
102            None => Ok(IndexOptions::default()),
103        }?;
104
105        Ok(PhysicalRegionOptions { index })
106    }
107}
108
109#[cfg(test)]
110mod tests {
111    use super::*;
112
113    #[test]
114    fn test_set_data_region_options_should_remove_metric_engine_options() {
115        let mut options = HashMap::new();
116        options.insert(
117            METRIC_ENGINE_INDEX_TYPE_OPTION.to_string(),
118            "inverted".to_string(),
119        );
120        options.insert(
121            METRIC_ENGINE_INDEX_SKIPPING_INDEX_GRANULARITY_OPTION.to_string(),
122            "102400".to_string(),
123        );
124        set_data_region_options(&mut options, false);
125
126        for key in [
127            METRIC_ENGINE_INDEX_TYPE_OPTION,
128            METRIC_ENGINE_INDEX_SKIPPING_INDEX_GRANULARITY_OPTION,
129        ] {
130            assert_eq!(options.get(key), None);
131        }
132    }
133
134    #[test]
135    fn test_deserialize_physical_region_options_from_hashmap() {
136        let mut options = HashMap::new();
137        options.insert(
138            METRIC_ENGINE_INDEX_TYPE_OPTION.to_string(),
139            "inverted".to_string(),
140        );
141        options.insert(
142            METRIC_ENGINE_INDEX_SKIPPING_INDEX_GRANULARITY_OPTION.to_string(),
143            "102400".to_string(),
144        );
145        let physical_region_options = PhysicalRegionOptions::try_from(&options).unwrap();
146        assert_eq!(physical_region_options.index, IndexOptions::Inverted);
147
148        let mut options = HashMap::new();
149        options.insert(
150            METRIC_ENGINE_INDEX_TYPE_OPTION.to_string(),
151            "skipping".to_string(),
152        );
153        options.insert(
154            METRIC_ENGINE_INDEX_SKIPPING_INDEX_GRANULARITY_OPTION.to_string(),
155            "102400".to_string(),
156        );
157        let physical_region_options = PhysicalRegionOptions::try_from(&options).unwrap();
158        assert_eq!(
159            physical_region_options.index,
160            IndexOptions::Skipping {
161                granularity: 102400
162            }
163        );
164    }
165}