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