common_meta/ddl/
drop_view.rs1use async_trait::async_trait;
16use common_event_recorder::Event;
17use common_procedure::error::{FromJsonSnafu, ToJsonSnafu};
18use common_procedure::{
19 Context as ProcedureContext, EventContext, EventTrigger, LockKey, Procedure,
20 Result as ProcedureResult, Status,
21};
22use common_telemetry::info;
23use serde::{Deserialize, Serialize};
24use snafu::{OptionExt, ResultExt, ensure};
25use strum::AsRefStr;
26use table::metadata::{TableId, TableInfo, TableType};
27use table::table_reference::TableReference;
28
29use crate::cache_invalidator::Context;
30use crate::ddl::DdlContext;
31use crate::ddl::event::view::{DROP_VIEW_EVENT_TYPE, ViewDdlEvent};
32use crate::ddl::utils::map_to_procedure_error;
33use crate::error::{self, Result};
34use crate::instruction::CacheIdent;
35use crate::key::table_name::TableNameKey;
36use crate::lock_key::{CatalogLock, SchemaLock, TableLock};
37use crate::metrics;
38use crate::rpc::ddl::DropViewTask;
39
40pub struct DropViewProcedure {
42 pub(crate) context: DdlContext,
44 pub(crate) data: DropViewData,
46}
47
48impl DropViewProcedure {
49 pub const TYPE_NAME: &'static str = "metasrv-procedure::DropView";
50
51 pub fn new(task: DropViewTask, context: DdlContext) -> Self {
52 Self {
53 context,
54 data: DropViewData {
55 state: DropViewState::Prepare,
56 task,
57 },
58 }
59 }
60
61 pub fn from_json(json: &str, context: DdlContext) -> ProcedureResult<Self> {
62 let data: DropViewData = serde_json::from_str(json).context(FromJsonSnafu)?;
63
64 Ok(Self { context, data })
65 }
66
67 #[cfg(test)]
68 pub(crate) fn state(&self) -> DropViewState {
69 self.data.state
70 }
71
72 pub(crate) async fn on_prepare(&mut self) -> Result<Status> {
76 let table_ref = self.data.table_ref();
77
78 let exists = self
79 .context
80 .table_metadata_manager
81 .table_name_manager()
82 .exists(TableNameKey::new(
83 table_ref.catalog,
84 table_ref.schema,
85 table_ref.table,
86 ))
87 .await?;
88
89 if !exists && self.data.task.drop_if_exists {
90 return Ok(Status::done());
91 }
92
93 ensure!(
94 exists,
95 error::ViewNotFoundSnafu {
96 view_name: table_ref.to_string(),
97 }
98 );
99
100 self.check_view_metadata().await?;
101 self.data.state = DropViewState::DeleteMetadata;
102
103 Ok(Status::executing(true))
104 }
105
106 async fn check_view_metadata(&mut self) -> Result<()> {
107 let view_id = self.data.view_id();
108 let table_info_value = self
109 .context
110 .table_metadata_manager
111 .table_info_manager()
112 .get(view_id)
113 .await?
114 .with_context(|| error::TableInfoNotFoundSnafu {
115 table: self.data.table_ref().to_string(),
116 })?;
117
118 self.ensure_is_view(&table_info_value.table_info)?;
119 self.ensure_view_info_exists(view_id).await?;
120
121 Ok(())
122 }
123
124 fn ensure_is_view(&self, table_info: &TableInfo) -> Result<()> {
125 ensure!(
126 table_info.table_type == TableType::View,
127 error::InvalidViewInfoSnafu {
128 err_msg: format!("{} is not a view", self.data.table_ref()),
129 }
130 );
131 Ok(())
132 }
133
134 async fn ensure_view_info_exists(&self, view_id: TableId) -> Result<()> {
135 self.context
136 .table_metadata_manager
137 .view_info_manager()
138 .get(view_id)
139 .await?
140 .with_context(|| error::ViewNotFoundSnafu {
141 view_name: self.data.table_ref().to_string(),
142 })?;
143 Ok(())
144 }
145
146 async fn on_delete_metadata(&mut self) -> Result<Status> {
147 let view_id = self.data.view_id();
148 self.context
149 .table_metadata_manager
150 .destroy_view_info(view_id, &self.data.table_ref().into())
151 .await?;
152
153 info!("Deleted view metadata for view {view_id}");
154
155 self.data.state = DropViewState::InvalidateViewCache;
156 Ok(Status::executing(true))
157 }
158
159 async fn on_broadcast(&mut self) -> Result<Status> {
160 let view_id = self.data.view_id();
161 let ctx = Context {
162 subject: Some("Invalidate view cache by dropping view".to_string()),
163 };
164
165 self.context
166 .cache_invalidator
167 .invalidate(
168 &ctx,
169 &[
170 CacheIdent::TableId(view_id),
171 CacheIdent::TableName(self.data.table_ref().into()),
172 ],
173 )
174 .await?;
175
176 Ok(Status::done())
177 }
178}
179
180#[async_trait]
181impl Procedure for DropViewProcedure {
182 fn type_name(&self) -> &str {
183 Self::TYPE_NAME
184 }
185
186 async fn execute(&mut self, _ctx: &ProcedureContext) -> ProcedureResult<Status> {
187 let state = &self.data.state;
188 let _timer = metrics::METRIC_META_PROCEDURE_DROP_VIEW
189 .with_label_values(&[state.as_ref()])
190 .start_timer();
191
192 match self.data.state {
193 DropViewState::Prepare => self.on_prepare().await,
194 DropViewState::DeleteMetadata => self.on_delete_metadata().await,
195 DropViewState::InvalidateViewCache => self.on_broadcast().await,
196 }
197 .map_err(map_to_procedure_error)
198 }
199
200 fn dump(&self) -> ProcedureResult<String> {
201 serde_json::to_string(&self.data).context(ToJsonSnafu)
202 }
203
204 fn lock_key(&self) -> LockKey {
205 let table_ref = &self.data.table_ref();
206 let view_id = self.data.view_id();
207 let lock_key = vec![
208 CatalogLock::Read(table_ref.catalog).into(),
209 SchemaLock::read(table_ref.catalog, table_ref.schema).into(),
210 TableLock::Write(view_id).into(),
211 ];
212
213 LockKey::new(lock_key)
214 }
215
216 fn event(&self, ctx: &EventContext<'_>) -> Option<Box<dyn Event>> {
217 if !ctx.event_type_filter.allows(DROP_VIEW_EVENT_TYPE) {
218 return None;
219 }
220
221 let event = match &ctx.trigger {
222 EventTrigger::Submitted => {
223 let table_ref = self.data.table_ref();
224 ViewDdlEvent::drop_submitted(
225 table_ref.catalog,
226 table_ref.schema,
227 table_ref.table,
228 self.data.view_id(),
229 self.data.task.drop_if_exists,
230 )
231 }
232 _ => {
233 let table_ref = self.data.table_ref();
234 ViewDdlEvent::drop_lifecycle(
235 table_ref.catalog,
236 table_ref.schema,
237 table_ref.table,
238 self.data.view_id(),
239 )
240 }
241 };
242
243 Some(Box::new(event))
244 }
245}
246
247#[derive(Debug, Serialize, Deserialize)]
249pub(crate) struct DropViewData {
250 state: DropViewState,
251 task: DropViewTask,
252}
253
254impl DropViewData {
255 fn table_ref(&self) -> TableReference<'_> {
256 self.task.table_ref()
257 }
258
259 fn view_id(&self) -> TableId {
260 self.task.view_id
261 }
262}
263
264#[derive(Debug, Serialize, Deserialize, AsRefStr, PartialEq, Clone, Copy)]
266pub(crate) enum DropViewState {
267 Prepare,
269 DeleteMetadata,
271 InvalidateViewCache,
273}