mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2026-10-30 07:26:56 +00:00
feat: Change signature of the Region::alter method (#287)
* feat: Change signature of the Region::alter method * refactor: Add builders for ColumnsMetadata and ColumnFamiliesMetadata * feat: Support altering the region metadata Altering the region metadata is done in a copy-write fashion: 1. Convert the `RegionMetadata` into `RegionDescriptor` which is more convenient to mutate 2. Apply the `AlterOperation` to the `RegionDescriptor`. This would mutate the descriptor in-place 3. Create a `RegionMetadataBuilder` from the descriptor, bump the version and then build the new metadata * feat: Implement altering table using the new Region::alter api * refactor: Replaced wal name by region id Region id is cheaper to clone than name * chore: Remove pub(crate) of build_xxxx in engine mod * style: fix clippy * test: Add tests for AlterOperation and RegionMetadata::alter * chore: ColumnsMetadataBuilder methods return &mut Self
This commit is contained in:
@@ -126,7 +126,7 @@ struct MitoEngineInner<S: StorageEngine> {
|
||||
table_mutex: Mutex<()>,
|
||||
}
|
||||
|
||||
pub(crate) fn build_row_key_desc(
|
||||
fn build_row_key_desc(
|
||||
mut column_id: ColumnId,
|
||||
table_name: &str,
|
||||
table_schema: &SchemaRef,
|
||||
@@ -189,7 +189,7 @@ pub(crate) fn build_row_key_desc(
|
||||
))
|
||||
}
|
||||
|
||||
pub(crate) fn build_column_family(
|
||||
fn build_column_family(
|
||||
mut column_id: ColumnId,
|
||||
table_name: &str,
|
||||
table_schema: &SchemaRef,
|
||||
|
||||
@@ -23,10 +23,9 @@ use object_store::ObjectStore;
|
||||
use snafu::{OptionExt, ResultExt};
|
||||
use store_api::manifest::action::ProtocolAction;
|
||||
use store_api::manifest::{self, Manifest, ManifestVersion, MetaActionIterator};
|
||||
use store_api::storage::RegionDescriptorBuilder;
|
||||
use store_api::storage::{
|
||||
ChunkReader, PutOperation, ReadContext, Region, RegionMeta, ScanRequest, SchemaRef, Snapshot,
|
||||
WriteContext, WriteRequest,
|
||||
AddColumn, AlterOperation, AlterRequest, ChunkReader, ColumnDescriptorBuilder, PutOperation,
|
||||
ReadContext, Region, RegionMeta, ScanRequest, SchemaRef, Snapshot, WriteContext, WriteRequest,
|
||||
};
|
||||
use table::error::{Error as TableError, MissingColumnSnafu, Result as TableResult};
|
||||
use table::metadata::{FilterPushDownType, TableInfoRef, TableMetaBuilder};
|
||||
@@ -37,7 +36,6 @@ use table::{
|
||||
};
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::engine::{build_column_family, build_row_key_desc, INIT_COLUMN_ID};
|
||||
use crate::error::{
|
||||
self, ProjectedColumnNotFoundSnafu, Result, ScanTableManifestSnafu, SchemaBuildSnafu,
|
||||
TableInfoNotFoundSnafu, UnsupportedDefaultConstraintSnafu, UpdateTableManifestSnafu,
|
||||
@@ -184,31 +182,43 @@ impl<R: Region> Table for MitoTable<R> {
|
||||
let table_info = self.table_info();
|
||||
let table_name = &table_info.name;
|
||||
let table_meta = &table_info.meta;
|
||||
let table_schema = match &req.alter_kind {
|
||||
let (alter_op, table_schema) = match &req.alter_kind {
|
||||
AlterKind::AddColumn { new_column } => {
|
||||
build_table_schema_with_new_column(table_name, &table_meta.schema, new_column)?
|
||||
let desc = ColumnDescriptorBuilder::new(
|
||||
table_meta.next_column_id,
|
||||
&new_column.name,
|
||||
new_column.data_type.clone(),
|
||||
)
|
||||
.is_nullable(new_column.is_nullable)
|
||||
.default_constraint(new_column.default_constraint.clone())
|
||||
.build()
|
||||
.context(error::BuildColumnDescriptorSnafu {
|
||||
table_name,
|
||||
column_name: &new_column.name,
|
||||
})?;
|
||||
let alter_op = AlterOperation::AddColumns {
|
||||
columns: vec![AddColumn {
|
||||
desc,
|
||||
// TODO(yingwen): [alter] AlterTableRequest should be able to add a key column.
|
||||
is_key: false,
|
||||
}],
|
||||
};
|
||||
|
||||
// TODO(yingwen): [alter] Better way to alter the schema struct. In fact the column order
|
||||
// in table schema could differ from the region schema, so we could just push this column
|
||||
// to the back of the schema (as last column).
|
||||
let table_schema =
|
||||
build_table_schema_with_new_column(table_name, &table_meta.schema, new_column)?;
|
||||
|
||||
(alter_op, table_schema)
|
||||
}
|
||||
};
|
||||
|
||||
let primary_key_indices = &table_meta.primary_key_indices;
|
||||
let (next_column_id, default_cf) = build_column_family(
|
||||
INIT_COLUMN_ID,
|
||||
table_name,
|
||||
&table_schema,
|
||||
primary_key_indices,
|
||||
)?;
|
||||
let (next_column_id, row_key) = build_row_key_desc(
|
||||
next_column_id,
|
||||
table_name,
|
||||
&table_schema,
|
||||
primary_key_indices,
|
||||
)?;
|
||||
|
||||
let new_meta = TableMetaBuilder::default()
|
||||
.schema(table_schema.clone())
|
||||
.engine(&table_meta.engine)
|
||||
.next_column_id(next_column_id)
|
||||
.primary_key_indices(primary_key_indices.clone())
|
||||
.next_column_id(table_meta.next_column_id + 1) // Bump next column id.
|
||||
.primary_key_indices(table_meta.primary_key_indices.clone())
|
||||
.build()
|
||||
.context(error::BuildTableMetaSnafu { table_name })?;
|
||||
|
||||
@@ -216,25 +226,21 @@ impl<R: Region> Table for MitoTable<R> {
|
||||
new_info.ident.version = table_info.ident.version + 1;
|
||||
new_info.meta = new_meta;
|
||||
|
||||
// first alter region
|
||||
// FIXME(yingwen): [alter] Alter the region, now this is a temporary implementation.
|
||||
let region = self.region();
|
||||
let region_descriptor = RegionDescriptorBuilder::default()
|
||||
.id(region.id())
|
||||
.name(region.name())
|
||||
.row_key(row_key)
|
||||
.default_cf(default_cf)
|
||||
.build()
|
||||
.context(error::BuildRegionDescriptorSnafu {
|
||||
table_name,
|
||||
region_name: region.name(),
|
||||
})?;
|
||||
let region_meta = region.in_memory_metadata();
|
||||
let alter_req = AlterRequest {
|
||||
operation: alter_op,
|
||||
version: region_meta.version(),
|
||||
};
|
||||
|
||||
logging::debug!(
|
||||
"start altering region {} of table {}, with new region descriptor {:?}",
|
||||
"start altering region {} of table {}, with request {:?}",
|
||||
region.name(),
|
||||
table_name,
|
||||
region_descriptor
|
||||
alter_req,
|
||||
);
|
||||
region.alter(region_descriptor).map_err(TableError::new)?;
|
||||
region.alter(alter_req).await.map_err(TableError::new)?;
|
||||
|
||||
// then alter table info
|
||||
logging::debug!(
|
||||
|
||||
@@ -12,9 +12,9 @@ use datatypes::schema::{ColumnSchema, Schema};
|
||||
use storage::metadata::{RegionMetaImpl, RegionMetadata};
|
||||
use storage::write_batch::{Mutation, WriteBatch};
|
||||
use store_api::storage::{
|
||||
Chunk, ChunkReader, CreateOptions, EngineContext, GetRequest, GetResponse, OpenOptions,
|
||||
ReadContext, Region, RegionDescriptor, RegionId, RegionMeta, ScanRequest, ScanResponse,
|
||||
SchemaRef, Snapshot, StorageEngine, WriteContext, WriteResponse,
|
||||
AlterRequest, Chunk, ChunkReader, CreateOptions, EngineContext, GetRequest, GetResponse,
|
||||
OpenOptions, ReadContext, Region, RegionDescriptor, RegionId, RegionMeta, ScanRequest,
|
||||
ScanResponse, SchemaRef, Snapshot, StorageEngine, WriteContext, WriteResponse,
|
||||
};
|
||||
|
||||
pub type Result<T> = std::result::Result<T, MockError>;
|
||||
@@ -115,13 +115,12 @@ impl Snapshot for MockSnapshot {
|
||||
// purpose the cost should be acceptable.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MockRegion {
|
||||
// FIXME(yingwen): Remove this once name is provided by metadata.
|
||||
name: String,
|
||||
pub inner: Arc<MockRegionInner>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MockRegionInner {
|
||||
name: String,
|
||||
pub metadata: ArcSwap<RegionMetadata>,
|
||||
memtable: Arc<RwLock<MockMemtable>>,
|
||||
}
|
||||
@@ -140,7 +139,7 @@ impl Region for MockRegion {
|
||||
}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
&self.name
|
||||
&self.inner.name
|
||||
}
|
||||
|
||||
fn in_memory_metadata(&self) -> RegionMetaImpl {
|
||||
@@ -163,9 +162,12 @@ impl Region for MockRegion {
|
||||
WriteBatch::new(self.in_memory_metadata().schema().clone())
|
||||
}
|
||||
|
||||
fn alter(&self, descriptor: RegionDescriptor) -> Result<()> {
|
||||
let metadata = descriptor.try_into().unwrap();
|
||||
async fn alter(&self, request: AlterRequest) -> Result<()> {
|
||||
let current = self.inner.metadata.load();
|
||||
// Mock engine just panic if failed to create a new metadata.
|
||||
let metadata = current.alter(&request).unwrap();
|
||||
self.inner.update_metadata(metadata);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -177,6 +179,7 @@ impl MockRegionInner {
|
||||
memtable.insert(column.name.clone(), vec![]);
|
||||
}
|
||||
Self {
|
||||
name: metadata.name().to_string(),
|
||||
metadata: ArcSwap::new(Arc::new(metadata)),
|
||||
memtable: Arc::new(RwLock::new(memtable)),
|
||||
}
|
||||
@@ -277,7 +280,6 @@ impl StorageEngine for MockEngine {
|
||||
let name = descriptor.name.clone();
|
||||
let metadata = descriptor.try_into().unwrap();
|
||||
let region = MockRegion {
|
||||
name: name.clone(),
|
||||
inner: Arc::new(MockRegionInner::new(metadata)),
|
||||
};
|
||||
regions.opened_regions.insert(name, region.clone());
|
||||
|
||||
Reference in New Issue
Block a user