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:
evenyag
2022-09-28 13:56:25 +08:00
committed by GitHub
parent 25078e821b
commit ed89cc3e21
13 changed files with 644 additions and 198 deletions
+2 -2
View File
@@ -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,
+42 -36
View File
@@ -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());