meta_srv/key/
datanode.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
15use std::str::FromStr;
16
17use common_meta::datanode::DatanodeStatKey;
18use lazy_static::lazy_static;
19use regex::Regex;
20use serde::{Deserialize, Serialize};
21use snafu::{ensure, OptionExt, ResultExt};
22
23use crate::error;
24use crate::error::Result;
25
26pub(crate) const DATANODE_LEASE_PREFIX: &str = "__meta_datanode_lease";
27const INACTIVE_REGION_PREFIX: &str = "__meta_inactive_region";
28
29const DATANODE_STAT_PREFIX: &str = "__meta_datanode_stat";
30
31lazy_static! {
32    pub(crate) static ref DATANODE_LEASE_KEY_PATTERN: Regex =
33        Regex::new(&format!("^{DATANODE_LEASE_PREFIX}-([0-9]+)-([0-9]+)$")).unwrap();
34    static ref DATANODE_STAT_KEY_PATTERN: Regex =
35        Regex::new(&format!("^{DATANODE_STAT_PREFIX}-([0-9]+)-([0-9]+)$")).unwrap();
36    static ref INACTIVE_REGION_KEY_PATTERN: Regex = Regex::new(&format!(
37        "^{INACTIVE_REGION_PREFIX}-([0-9]+)-([0-9]+)-([0-9]+)$"
38    ))
39    .unwrap();
40}
41
42#[derive(Debug, Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]
43pub struct DatanodeLeaseKey {
44    pub node_id: u64,
45}
46
47impl DatanodeLeaseKey {
48    pub fn prefix_key() -> Vec<u8> {
49        format!("{DATANODE_LEASE_PREFIX}-0-").into_bytes()
50    }
51}
52
53impl From<&DatanodeLeaseKey> for DatanodeStatKey {
54    fn from(lease_key: &DatanodeLeaseKey) -> Self {
55        DatanodeStatKey {
56            node_id: lease_key.node_id,
57        }
58    }
59}
60
61#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
62pub struct InactiveRegionKey {
63    pub node_id: u64,
64    pub region_id: u64,
65}
66
67impl InactiveRegionKey {
68    pub fn get_prefix_by_cluster() -> Vec<u8> {
69        format!("{}-0-", INACTIVE_REGION_PREFIX).into_bytes()
70    }
71}
72
73impl From<InactiveRegionKey> for Vec<u8> {
74    fn from(value: InactiveRegionKey) -> Self {
75        format!(
76            "{}-0-{}-{}",
77            INACTIVE_REGION_PREFIX, value.node_id, value.region_id
78        )
79        .into_bytes()
80    }
81}
82
83impl FromStr for InactiveRegionKey {
84    type Err = error::Error;
85
86    fn from_str(key: &str) -> Result<Self> {
87        let caps = INACTIVE_REGION_KEY_PATTERN
88            .captures(key)
89            .context(error::InvalidInactiveRegionKeySnafu { key })?;
90
91        ensure!(
92            caps.len() == 4,
93            error::InvalidInactiveRegionKeySnafu { key }
94        );
95
96        let node_id = caps[2].to_string();
97        let region_id = caps[3].to_string();
98        let node_id: u64 = node_id.parse().context(error::ParseNumSnafu {
99            err_msg: format!("invalid node_id: {node_id}"),
100        })?;
101        let region_id: u64 = region_id.parse().context(error::ParseNumSnafu {
102            err_msg: format!("invalid region_id: {region_id}"),
103        })?;
104
105        Ok(Self { node_id, region_id })
106    }
107}
108
109impl TryFrom<Vec<u8>> for InactiveRegionKey {
110    type Error = error::Error;
111
112    fn try_from(bytes: Vec<u8>) -> Result<Self> {
113        String::from_utf8(bytes)
114            .context(error::InvalidRegionKeyFromUtf8Snafu {})
115            .map(|x| x.parse())?
116    }
117}
118
119#[cfg(test)]
120mod tests {
121    use super::*;
122
123    #[test]
124    fn test_stat_key_round_trip() {
125        let key = DatanodeStatKey { node_id: 1 };
126
127        let key_bytes: Vec<u8> = key.into();
128        let new_key: DatanodeStatKey = key_bytes.try_into().unwrap();
129
130        assert_eq!(1, new_key.node_id);
131    }
132
133    #[test]
134    fn test_lease_key_round_trip() {
135        let key = DatanodeLeaseKey { node_id: 1 };
136
137        let key_bytes: Vec<u8> = key.clone().try_into().unwrap();
138        let new_key: DatanodeLeaseKey = key_bytes.try_into().unwrap();
139
140        assert_eq!(new_key, key);
141    }
142
143    #[test]
144    fn test_lease_key_to_stat_key() {
145        let lease_key = DatanodeLeaseKey { node_id: 101 };
146
147        let stat_key: DatanodeStatKey = (&lease_key).into();
148
149        assert_eq!(101, stat_key.node_id);
150    }
151
152    #[test]
153    fn test_inactive_region_key_round_trip() {
154        let key = InactiveRegionKey {
155            node_id: 1,
156            region_id: 2,
157        };
158
159        let key_bytes: Vec<u8> = key.into();
160        let new_key: InactiveRegionKey = key_bytes.try_into().unwrap();
161
162        assert_eq!(new_key, key);
163    }
164}