From 9718aa17c90c279dee8e1e02f28983551f50a75a Mon Sep 17 00:00:00 2001 From: Ruihang Xia Date: Fri, 4 Aug 2023 17:08:07 +0800 Subject: [PATCH] feat: define region group and sequence (#2100) * define region group Signed-off-by: Ruihang Xia * define region sequence Signed-off-by: Ruihang Xia * check partition number Signed-off-by: Ruihang Xia * fix clippy Signed-off-by: Ruihang Xia * test region seq and group Signed-off-by: Ruihang Xia --------- Signed-off-by: Ruihang Xia --- src/meta-srv/src/error.rs | 6 +- src/meta-srv/src/service/ddl.rs | 9 ++- src/store-api/src/storage/descriptors.rs | 71 ++++++++++++++++++++++-- 3 files changed, 78 insertions(+), 8 deletions(-) diff --git a/src/meta-srv/src/error.rs b/src/meta-srv/src/error.rs index d2d0be5017..41b41d96d1 100644 --- a/src/meta-srv/src/error.rs +++ b/src/meta-srv/src/error.rs @@ -469,6 +469,9 @@ pub enum Error { source: SendError, location: Location, }, + + #[snafu(display("Too many partitions, location: {}", location))] + TooManyPartitions { location: Location }, } pub type Result = std::result::Result; @@ -525,7 +528,8 @@ impl ErrorExt for Error { | Error::ParseNum { .. } | Error::UnsupportedSelectorType { .. } | Error::InvalidArguments { .. } - | Error::InvalidHeartbeatRequest { .. } => StatusCode::InvalidArguments, + | Error::InvalidHeartbeatRequest { .. } + | Error::TooManyPartitions { .. } => StatusCode::InvalidArguments, Error::LeaseKeyFromUtf8 { .. } | Error::LeaseValueFromUtf8 { .. } | Error::StatKeyFromUtf8 { .. } diff --git a/src/meta-srv/src/service/ddl.rs b/src/meta-srv/src/service/ddl.rs index d1f560de91..faf840084a 100644 --- a/src/meta-srv/src/service/ddl.rs +++ b/src/meta-srv/src/service/ddl.rs @@ -24,14 +24,15 @@ use common_meta::rpc::ddl::{ use common_meta::rpc::router; use common_meta::table_name::TableName; use common_telemetry::{info, warn}; -use snafu::{OptionExt, ResultExt}; +use snafu::{ensure, OptionExt, ResultExt}; +use store_api::storage::MAX_REGION_SEQ; use table::metadata::RawTableInfo; use tonic::{Request, Response}; use super::store::kv::KvStoreRef; use super::GrpcResult; use crate::ddl::DdlManagerRef; -use crate::error::{self, Result, TableMetadataManagerSnafu}; +use crate::error::{self, Result, TableMetadataManagerSnafu, TooManyPartitionsSnafu}; use crate::metasrv::{MetaSrv, SelectorContext, SelectorRef}; use crate::sequence::SequenceRef; use crate::table_routes::get_table_route_value; @@ -192,6 +193,10 @@ async fn handle_create_table_route( ..Default::default() }; + ensure!( + partitions.len() <= MAX_REGION_SEQ as usize, + TooManyPartitionsSnafu + ); let region_routes = partitions .into_iter() .enumerate() diff --git a/src/store-api/src/storage/descriptors.rs b/src/store-api/src/storage/descriptors.rs index efa87ed1de..de0ce1739f 100644 --- a/src/store-api/src/storage/descriptors.rs +++ b/src/store-api/src/storage/descriptors.rs @@ -19,16 +19,36 @@ use serde::{Deserialize, Serialize}; use crate::storage::{consts, ColumnDefaultConstraint, ColumnSchema, ConcreteDataType}; -/// Id of column, unique in each region. +/// Id of column. Unique in each region. pub type ColumnId = u32; -/// Id of column family, unique in each region. +/// Id of column family. Unique in each region. pub type ColumnFamilyId = u32; -/// Sequence number of regions under the same table. +/// Group number of one region. Unique in each region. +pub type RegionGroup = u8; +/// Sequence number of region inside one table. Unique in each table. +/// The first 8 bits are preserved for [RegionGroup]. +pub type RegionSeq = u32; +/// Id of regions under the same table. Unique in each table. +/// Is composed by [RegionGroup] and [RegionSeq]. pub type RegionNumber = u32; -/// Id of table. +/// Id of table. Universal unique. pub type TableId = u32; -/// Id of the region. It's generated by concatenating table id and region number. +const REGION_GROUP_MASK: u32 = 0b1111_1111 << 24; +const REGION_SEQ_MASK: u32 = (0b1 << 24) - 1; + +/// The max valid region sequence number. +pub const MAX_REGION_SEQ: u32 = REGION_SEQ_MASK; + +/// Id of the region. It's generated by concatenating table id, region group and region number. +/// +/// ```plaintext +/// 63 31 23 0 +/// ┌────────────────────────────────────┬──────────┬──────────────────┐ +/// │ Table Id(32) │ Group(8) │ Sequence(24) │ +/// └────────────────────────────────────┴──────────┴──────────────────┘ +/// Region Number(32) +/// ``` #[derive(Default, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct RegionId(u64); @@ -48,6 +68,16 @@ impl RegionId { self.0 as RegionNumber } + /// Returns the group number of the region + pub const fn region_group(&self) -> RegionGroup { + ((self.region_number() & REGION_GROUP_MASK) >> 24) as RegionGroup + } + + /// Return the sequence number of the region + pub const fn region_sequence(&self) -> RegionSeq { + self.region_number() & REGION_SEQ_MASK + } + /// Returns the region id as u64. pub const fn as_u64(&self) -> u64 { self.0 @@ -57,6 +87,19 @@ impl RegionId { pub const fn from_u64(id: u64) -> RegionId { RegionId(id) } + + #[cfg(test)] + pub const fn with_group_and_seq( + table_id: TableId, + group: RegionGroup, + seq: RegionSeq, + ) -> RegionId { + RegionId( + ((table_id as u64) << 32) + | ((group as u32) << 24) as u64 + | (seq & REGION_SEQ_MASK) as u64, + ) + } } impl fmt::Debug for RegionId { @@ -411,4 +454,22 @@ mod tests { let parsed: RegionId = serde_json::from_str(&json).unwrap(); assert_eq!(region_id, parsed); } + + #[test] + fn test_retrieve_region_group_and_seq() { + let region_id = RegionId::with_group_and_seq(111, 222, 333); + assert_eq!(111, region_id.table_id()); + assert_eq!(222, region_id.region_group()); + assert_eq!(333, region_id.region_sequence()); + + let expected_region_number = 222 << 24 | 333; + assert_eq!(expected_region_number, region_id.region_number()); + } + + #[test] + fn test_invalid_large_region_sequence() { + // region sequence larger than `MAX_REGION_SEQ` will be masked into valid range + let region_id = RegionId::with_group_and_seq(111, 222, u32::MAX); + assert_eq!(MAX_REGION_SEQ, region_id.region_sequence()); + } }