store_api/storage/
descriptors.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::fmt;
16
17use derive_builder::Builder;
18use serde::{Deserialize, Serialize};
19
20use crate::storage::{ColumnDefaultConstraint, ColumnSchema, ConcreteDataType};
21
22/// Id of column. Unique in each region.
23pub type ColumnId = u32;
24/// Group number of one region. Unique in each region.
25pub type RegionGroup = u8;
26/// Sequence number of region inside one table. Unique in each table.
27/// The first 8 bits are preserved for [RegionGroup].
28pub type RegionSeq = u32;
29/// Id of regions under the same table. Unique in each table.
30/// Is composed by [RegionGroup] and [RegionSeq].
31pub type RegionNumber = u32;
32/// Id of table. Universal unique.
33pub type TableId = u32;
34
35const REGION_GROUP_MASK: u32 = 0b1111_1111 << 24;
36const REGION_SEQ_MASK: u32 = (0b1 << 24) - 1;
37
38/// The max valid region sequence number.
39pub const MAX_REGION_SEQ: u32 = REGION_SEQ_MASK;
40
41/// Id of the region. It's generated by concatenating table id, region group and region number.
42///
43/// ```plaintext
44/// 63                                  31         23                  0
45/// ┌────────────────────────────────────┬──────────┬──────────────────┐
46/// │          Table Id(32)              │ Group(8) │   Sequence(24)   │
47/// └────────────────────────────────────┴──────────┴──────────────────┘
48///                                         Region Number(32)
49/// ```
50#[derive(Default, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
51pub struct RegionId(u64);
52
53impl RegionId {
54    /// Construct a new [RegionId] from table id and region number.
55    pub const fn new(table_id: TableId, region_number: RegionNumber) -> RegionId {
56        RegionId(((table_id as u64) << 32) | region_number as u64)
57    }
58
59    /// Returns the table id of the region.
60    pub const fn table_id(&self) -> TableId {
61        (self.0 >> 32) as TableId
62    }
63
64    /// Returns the region number of the region.
65    pub const fn region_number(&self) -> RegionNumber {
66        self.0 as RegionNumber
67    }
68
69    /// Returns the group number of the region
70    pub const fn region_group(&self) -> RegionGroup {
71        ((self.region_number() & REGION_GROUP_MASK) >> 24) as RegionGroup
72    }
73
74    /// Return the sequence number of the region
75    pub const fn region_sequence(&self) -> RegionSeq {
76        self.region_number() & REGION_SEQ_MASK
77    }
78
79    /// Returns the region id as u64.
80    pub const fn as_u64(&self) -> u64 {
81        self.0
82    }
83
84    /// Construct a new [RegionId] from u64.
85    pub const fn from_u64(id: u64) -> RegionId {
86        RegionId(id)
87    }
88
89    /// Construct a new [RegionId] from table id, region group and region sequence.
90    pub const fn with_group_and_seq(
91        table_id: TableId,
92        group: RegionGroup,
93        seq: RegionSeq,
94    ) -> RegionId {
95        RegionId(
96            ((table_id as u64) << 32)
97                | ((group as u32) << 24) as u64
98                | (seq & REGION_SEQ_MASK) as u64,
99        )
100    }
101}
102
103impl fmt::Debug for RegionId {
104    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105        write!(
106            f,
107            "{}({}, {})",
108            self.0,
109            self.table_id(),
110            self.region_number()
111        )
112    }
113}
114
115impl fmt::Display for RegionId {
116    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117        write!(f, "{:?}", self)
118    }
119}
120
121impl From<u64> for RegionId {
122    fn from(region_id: u64) -> RegionId {
123        RegionId::from_u64(region_id)
124    }
125}
126
127impl From<RegionId> for u64 {
128    fn from(region_id: RegionId) -> u64 {
129        region_id.as_u64()
130    }
131}
132
133impl PartialEq<u64> for RegionId {
134    fn eq(&self, other: &u64) -> bool {
135        self.0 == *other
136    }
137}
138
139impl PartialEq<RegionId> for u64 {
140    fn eq(&self, other: &RegionId) -> bool {
141        *self == other.0
142    }
143}
144
145/// A [ColumnDescriptor] contains information to create a column.
146#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Builder)]
147#[builder(pattern = "owned", build_fn(validate = "Self::validate"))]
148pub struct ColumnDescriptor {
149    pub id: ColumnId,
150    #[builder(setter(into))]
151    pub name: String,
152    pub data_type: ConcreteDataType,
153    /// Is column nullable, default is true.
154    #[builder(default = "true")]
155    is_nullable: bool,
156    /// Is time index column, default is true.
157    #[builder(default = "false")]
158    is_time_index: bool,
159    /// Default constraint of column, default is None, which means no default constraint
160    /// for this column, and user must provide a value for a not-null column.
161    #[builder(default)]
162    default_constraint: Option<ColumnDefaultConstraint>,
163    #[builder(default, setter(into))]
164    pub comment: String,
165}
166
167impl ColumnDescriptor {
168    #[inline]
169    pub fn is_nullable(&self) -> bool {
170        self.is_nullable
171    }
172    #[inline]
173    pub fn is_time_index(&self) -> bool {
174        self.is_time_index
175    }
176
177    #[inline]
178    pub fn default_constraint(&self) -> Option<&ColumnDefaultConstraint> {
179        self.default_constraint.as_ref()
180    }
181
182    /// Convert [ColumnDescriptor] to [ColumnSchema]. Fields not in ColumnSchema **will not**
183    /// be stored as metadata.
184    pub fn to_column_schema(&self) -> ColumnSchema {
185        ColumnSchema::new(&self.name, self.data_type.clone(), self.is_nullable)
186            .with_time_index(self.is_time_index)
187            .with_default_constraint(self.default_constraint.clone())
188            .expect("ColumnDescriptor should validate default constraint")
189    }
190}
191
192impl ColumnDescriptorBuilder {
193    pub fn new<S: Into<String>>(id: ColumnId, name: S, data_type: ConcreteDataType) -> Self {
194        Self {
195            id: Some(id),
196            name: Some(name.into()),
197            data_type: Some(data_type),
198            ..Default::default()
199        }
200    }
201
202    fn validate(&self) -> Result<(), String> {
203        if let Some(name) = &self.name {
204            if name.is_empty() {
205                return Err("name should not be empty".to_string());
206            }
207        }
208
209        if let (Some(Some(constraint)), Some(data_type)) =
210            (&self.default_constraint, &self.data_type)
211        {
212            // The default value of unwrap_or should be same as the default value
213            // defined in the `#[builder(default = "xxx")]` attribute.
214            let is_nullable = self.is_nullable.unwrap_or(true);
215
216            constraint
217                .validate(data_type, is_nullable)
218                .map_err(|e| e.to_string())?;
219        }
220
221        Ok(())
222    }
223}
224
225#[cfg(test)]
226mod tests {
227    use datatypes::value::Value;
228
229    use super::*;
230
231    #[inline]
232    fn new_column_desc_builder() -> ColumnDescriptorBuilder {
233        ColumnDescriptorBuilder::new(3, "test", ConcreteDataType::int32_datatype())
234    }
235
236    #[test]
237    fn test_column_descriptor_builder() {
238        let desc = new_column_desc_builder().build().unwrap();
239        assert_eq!(3, desc.id);
240        assert_eq!("test", desc.name);
241        assert_eq!(ConcreteDataType::int32_datatype(), desc.data_type);
242        assert!(desc.is_nullable);
243        assert!(desc.default_constraint.is_none());
244        assert!(desc.comment.is_empty());
245
246        let desc = new_column_desc_builder()
247            .is_nullable(false)
248            .build()
249            .unwrap();
250        assert!(!desc.is_nullable());
251
252        let desc = new_column_desc_builder()
253            .default_constraint(Some(ColumnDefaultConstraint::Value(Value::Null)))
254            .build()
255            .unwrap();
256        assert_eq!(
257            ColumnDefaultConstraint::Value(Value::Null),
258            *desc.default_constraint().unwrap()
259        );
260
261        let desc = new_column_desc_builder()
262            .default_constraint(Some(ColumnDefaultConstraint::Value(Value::Int32(123))))
263            .build()
264            .unwrap();
265        assert_eq!(
266            ColumnDefaultConstraint::Value(Value::Int32(123)),
267            desc.default_constraint.unwrap()
268        );
269
270        let desc = new_column_desc_builder()
271            .comment("A test column")
272            .build()
273            .unwrap();
274        assert_eq!("A test column", desc.comment);
275
276        assert!(new_column_desc_builder()
277            .is_nullable(false)
278            .default_constraint(Some(ColumnDefaultConstraint::Value(Value::Null)))
279            .build()
280            .is_err());
281    }
282
283    #[test]
284    fn test_descriptor_to_column_schema() {
285        let constraint = ColumnDefaultConstraint::Value(Value::Int32(123));
286        let desc = new_column_desc_builder()
287            .default_constraint(Some(constraint.clone()))
288            .is_nullable(false)
289            .build()
290            .unwrap();
291        let column_schema = desc.to_column_schema();
292        let expected = ColumnSchema::new("test", ConcreteDataType::int32_datatype(), false)
293            .with_default_constraint(Some(constraint))
294            .unwrap();
295
296        assert_eq!(expected, column_schema);
297    }
298
299    #[test]
300    fn test_region_id() {
301        assert_eq!(RegionId::new(0, 1), 1);
302        assert_eq!(4294967296, RegionId::new(1, 0));
303        assert_eq!(4294967297, RegionId::new(1, 1));
304        assert_eq!(4294967396, RegionId::new(1, 100));
305        assert_eq!(8589934602, RegionId::new(2, 10));
306        assert_eq!(18446744069414584330, RegionId::new(u32::MAX, 10));
307
308        let region_id = RegionId::new(u32::MAX, 1);
309        assert_eq!(u32::MAX, region_id.table_id());
310        assert_eq!(1, region_id.region_number());
311        let inner: u64 = region_id.into();
312        assert_eq!(RegionId::from(inner), region_id);
313
314        let region_id = RegionId::new(1234, 5);
315        assert_eq!("5299989643269(1234, 5)", region_id.to_string());
316        assert_eq!("5299989643269(1234, 5)", format!("{:?}", region_id));
317    }
318
319    #[test]
320    fn test_region_id_to_json() {
321        let region_id = RegionId::from(4294967297);
322        let json = serde_json::to_string(&region_id).unwrap();
323        assert_eq!("4294967297", json);
324
325        let parsed: RegionId = serde_json::from_str(&json).unwrap();
326        assert_eq!(region_id, parsed);
327    }
328
329    #[test]
330    fn test_retrieve_region_group_and_seq() {
331        let region_id = RegionId::with_group_and_seq(111, 222, 333);
332        assert_eq!(111, region_id.table_id());
333        assert_eq!(222, region_id.region_group());
334        assert_eq!(333, region_id.region_sequence());
335
336        let expected_region_number = 222 << 24 | 333;
337        assert_eq!(expected_region_number, region_id.region_number());
338    }
339
340    #[test]
341    fn test_invalid_large_region_sequence() {
342        // region sequence larger than `MAX_REGION_SEQ` will be masked into valid range
343        let region_id = RegionId::with_group_and_seq(111, 222, u32::MAX);
344        assert_eq!(MAX_REGION_SEQ, region_id.region_sequence());
345    }
346}