common_meta/ddl/alter_table/
executor.rs1use std::collections::HashMap;
16
17use api::region::RegionResponse;
18use api::v1::AlterTableExpr;
19use api::v1::region::region_request::Body;
20use api::v1::region::{AlterRequest, RegionRequest, RegionRequestHeader, alter_request};
21use common_catalog::format_full_table_name;
22use common_grpc_expr::alter_expr_to_request;
23use common_telemetry::tracing_context::TracingContext;
24use common_telemetry::{debug, info};
25use futures::future;
26use snafu::{ResultExt, ensure};
27use store_api::metadata::ColumnMetadata;
28use store_api::storage::{RegionId, TableId};
29use table::metadata::TableInfo;
30use table::requests::AlterKind;
31use table::table_name::TableName;
32
33use crate::cache_invalidator::{CacheInvalidatorRef, Context};
34use crate::ddl::utils::{add_peer_context_if_needed, raw_table_info};
35use crate::error::{self, Result, UnexpectedSnafu};
36use crate::instruction::CacheIdent;
37use crate::key::table_info::TableInfoValue;
38use crate::key::table_name::TableNameKey;
39use crate::key::{DeserializedValueWithBytes, RegionDistribution, TableMetadataManagerRef};
40use crate::node_manager::NodeManagerRef;
41use crate::rpc::router::{RegionRoute, find_followers, find_leaders, region_distribution};
42
43pub struct AlterTableExecutor {
47 table: TableName,
48 table_id: TableId,
49 new_table_name: Option<String>,
51}
52
53impl AlterTableExecutor {
54 pub fn new(table: TableName, table_id: TableId, new_table_name: Option<String>) -> Self {
56 Self {
57 table,
58 table_id,
59 new_table_name,
60 }
61 }
62
63 pub(crate) async fn on_prepare(
69 &self,
70 table_metadata_manager: &TableMetadataManagerRef,
71 ) -> Result<()> {
72 let catalog = &self.table.catalog_name;
73 let schema = &self.table.schema_name;
74 let table_name = &self.table.table_name;
75
76 let manager = table_metadata_manager;
77 if let Some(new_table_name) = &self.new_table_name {
78 let new_table_name_key = TableNameKey::new(catalog, schema, new_table_name);
79 let exists = manager
80 .table_name_manager()
81 .exists(new_table_name_key)
82 .await?;
83 ensure!(
84 !exists,
85 error::TableAlreadyExistsSnafu {
86 table_name: format_full_table_name(catalog, schema, new_table_name),
87 }
88 )
89 }
90
91 let table_name_key = TableNameKey::new(catalog, schema, table_name);
92 let exists = manager.table_name_manager().exists(table_name_key).await?;
93 ensure!(
94 exists,
95 error::TableNotFoundSnafu {
96 table_name: format_full_table_name(catalog, schema, table_name),
97 }
98 );
99
100 Ok(())
101 }
102
103 pub(crate) fn validate_alter_table_expr(
110 table_info: &TableInfo,
111 alter_table_expr: AlterTableExpr,
112 ) -> Result<TableInfo> {
113 build_new_table_info(table_info, alter_table_expr)
114 }
115
116 pub(crate) async fn on_alter_metadata(
118 &self,
119 table_metadata_manager: &TableMetadataManagerRef,
120 current_table_info_value: &DeserializedValueWithBytes<TableInfoValue>,
121 region_distribution: Option<&RegionDistribution>,
122 mut raw_table_info: TableInfo,
123 column_metadatas: &[ColumnMetadata],
124 metadata_only_alter: bool,
125 ) -> Result<()> {
126 let table_ref = self.table.table_ref();
127 let table_id = self.table_id;
128
129 if let Some(new_table_name) = &self.new_table_name {
130 debug!(
131 "Starting update table: {} metadata, table_id: {}, new table info: {:?}, new table name: {}",
132 table_ref, table_id, raw_table_info, new_table_name
133 );
134
135 table_metadata_manager
136 .rename_table(current_table_info_value, new_table_name.clone())
137 .await?;
138 } else {
139 debug!(
140 "Starting update table: {} metadata, table_id: {}, new table info: {:?}",
141 table_ref, table_id, raw_table_info
142 );
143
144 ensure!(
145 metadata_only_alter || region_distribution.is_some(),
146 UnexpectedSnafu {
147 err_msg: "region distribution is not set when updating table metadata",
148 }
149 );
150
151 if !column_metadatas.is_empty() {
152 raw_table_info::update_table_info_column_ids(&mut raw_table_info, column_metadatas);
153 }
154 table_metadata_manager
155 .update_table_info(
156 current_table_info_value,
157 region_distribution.cloned(),
158 raw_table_info,
159 )
160 .await?;
161 }
162
163 Ok(())
164 }
165
166 pub(crate) async fn on_alter_regions(
168 &self,
169 node_manager: &NodeManagerRef,
170 region_routes: &[RegionRoute],
171 kind: Option<alter_request::Kind>,
172 ) -> Vec<Result<RegionResponse>> {
173 self.dispatch_alter_region_requests(node_manager, region_routes, kind, false)
174 .await
175 }
176
177 pub(crate) async fn on_alter_skip_wal_regions(
179 &self,
180 node_manager: &NodeManagerRef,
181 region_routes: &[RegionRoute],
182 kind: Option<alter_request::Kind>,
183 ) -> Vec<Result<RegionResponse>> {
184 self.dispatch_alter_region_requests(node_manager, region_routes, kind, true)
185 .await
186 }
187
188 async fn dispatch_alter_region_requests(
189 &self,
190 node_manager: &NodeManagerRef,
191 region_routes: &[RegionRoute],
192 kind: Option<alter_request::Kind>,
193 include_followers: bool,
194 ) -> Vec<Result<RegionResponse>> {
195 let region_distribution = region_distribution(region_routes);
196 let mut peers = find_leaders(region_routes)
197 .into_iter()
198 .map(|p| (p.id, p))
199 .collect::<HashMap<_, _>>();
200 if include_followers {
201 peers.extend(find_followers(region_routes).into_iter().map(|p| (p.id, p)));
202 }
203 let total_num_region = region_distribution
204 .values()
205 .map(|r| {
206 r.leader_regions.len()
207 + if include_followers {
208 r.follower_regions.len()
209 } else {
210 0
211 }
212 })
213 .sum::<usize>();
214 let mut alter_region_tasks = Vec::with_capacity(total_num_region);
215 for (datanode_id, region_role_set) in region_distribution {
216 let mut region_ids = region_role_set.leader_regions;
217 if include_followers {
218 region_ids.extend(region_role_set.follower_regions);
219 }
220 if region_ids.is_empty() {
221 continue;
222 }
223 let peer = peers.get(&datanode_id).unwrap();
225 let requester = node_manager.datanode(peer).await;
226
227 for region_id in region_ids {
228 let region_id = RegionId::new(self.table_id, region_id);
229 let request = make_alter_region_request(region_id, kind.clone());
230
231 let requester = requester.clone();
232 let peer = peer.clone();
233
234 alter_region_tasks.push(async move {
235 requester
236 .handle(request)
237 .await
238 .map_err(add_peer_context_if_needed(peer))
239 });
240 }
241 }
242
243 future::join_all(alter_region_tasks)
244 .await
245 .into_iter()
246 .collect::<Vec<_>>()
247 }
248
249 pub(crate) async fn invalidate_table_cache(
251 &self,
252 cache_invalidator: &CacheInvalidatorRef,
253 ) -> Result<()> {
254 let ctx = Context {
255 subject: Some(format!(
256 "Invalidate table cache by altering table {}, table_id: {}",
257 self.table.table_ref(),
258 self.table_id,
259 )),
260 };
261
262 cache_invalidator
263 .invalidate(
264 &ctx,
265 &[
266 CacheIdent::TableName(self.table.clone()),
267 CacheIdent::TableId(self.table_id),
268 ],
269 )
270 .await?;
271
272 Ok(())
273 }
274}
275
276pub(crate) fn make_alter_region_request(
278 region_id: RegionId,
279 kind: Option<alter_request::Kind>,
280) -> RegionRequest {
281 RegionRequest {
282 header: Some(RegionRequestHeader {
283 tracing_context: TracingContext::from_current_span().to_w3c(),
284 ..Default::default()
285 }),
286 body: Some(Body::Alter(AlterRequest {
287 region_id: region_id.as_u64(),
288 kind,
289 ..Default::default()
290 })),
291 }
292}
293
294fn build_new_table_info(
301 table_info: &TableInfo,
302 alter_table_expr: AlterTableExpr,
303) -> Result<TableInfo> {
304 let table_info = table_info.clone();
305 let schema_name = &table_info.schema_name;
306 let catalog_name = &table_info.catalog_name;
307 let table_name = &table_info.name;
308 let table_id = table_info.ident.table_id;
309 let request = alter_expr_to_request(table_id, alter_table_expr, Some(&table_info.meta))
310 .context(error::ConvertAlterTableRequestSnafu)?;
311
312 let new_meta = table_info
313 .meta
314 .builder_with_alter_kind(table_name, &request.alter_kind)
315 .context(error::TableSnafu)?
316 .build()
317 .with_context(|_| error::BuildTableMetaSnafu {
318 table_name: format_full_table_name(catalog_name, schema_name, table_name),
319 })?;
320
321 let mut new_info = table_info.clone();
322 new_info.meta = new_meta;
323 new_info.ident.version = table_info.ident.version + 1;
324 match request.alter_kind {
325 AlterKind::AddColumns { columns } => {
326 new_info.meta.next_column_id += columns.len() as u32;
330 }
331 AlterKind::RenameTable { new_table_name } => {
332 new_info.name = new_table_name.clone();
333 }
334 AlterKind::DropColumns { .. }
335 | AlterKind::ModifyColumnTypes { .. }
336 | AlterKind::SetTableOptions { .. }
337 | AlterKind::UnsetTableOptions { .. }
338 | AlterKind::SetRepartitionColumnHint { .. }
339 | AlterKind::UnsetRepartitionColumnHint
340 | AlterKind::SetIndexes { .. }
341 | AlterKind::UnsetIndexes { .. }
342 | AlterKind::DropDefaults { .. }
343 | AlterKind::SetDefaults { .. } => {}
344 }
345
346 info!(
347 "Built new table info: {:?} for table {}, table_id: {}",
348 new_info.meta, table_name, table_id
349 );
350 Ok(new_info)
351}