catalog/system_schema/information_schema/
flow_statistics.rs1use std::sync::{Arc, Weak};
16
17use common_catalog::consts::INFORMATION_SCHEMA_FLOW_STATISTICS_TABLE_ID;
18use common_error::ext::BoxedError;
19use common_meta::key::FlowId;
20use common_meta::key::flow::FlowMetadataManager;
21use common_meta::key::flow::flow_state::FlowStat;
22use common_recordbatch::adapter::RecordBatchStreamAdapter;
23use common_recordbatch::{DfSendableRecordBatchStream, RecordBatch, SendableRecordBatchStream};
24use common_time::util::current_time_millis;
25use datafusion::execution::TaskContext;
26use datafusion::physical_plan::stream::RecordBatchStreamAdapter as DfRecordBatchStreamAdapter;
27use datafusion::physical_plan::streaming::PartitionStream as DfPartitionStream;
28use datatypes::prelude::ConcreteDataType as CDT;
29use datatypes::scalars::ScalarVectorBuilder;
30use datatypes::schema::{ColumnSchema, Schema, SchemaRef};
31use datatypes::timestamp::TimestampMillisecond;
32use datatypes::value::Value;
33use datatypes::vectors::{
34 Int64VectorBuilder, StringVectorBuilder, TimestampMillisecondVectorBuilder,
35 UInt32VectorBuilder, UInt64VectorBuilder, VectorRef,
36};
37use futures::TryStreamExt;
38use snafu::ResultExt;
39use store_api::storage::{ScanRequest, TableId};
40
41use crate::CatalogManager;
42use crate::error::{CreateRecordBatchSnafu, InternalSnafu, ListFlowsSnafu, Result};
43use crate::information_schema::{FLOW_STATISTICS, Predicates};
44use crate::system_schema::SystemTable;
45use crate::system_schema::information_schema::{InformationSchemaTableScope, InformationTable};
46use crate::system_schema::utils;
47
48const INIT_CAPACITY: usize = 42;
49
50pub const FLOW_ID: &str = "flow_id";
52pub const FLOW_NAME: &str = "flow_name";
53pub const START_TIME: &str = "start_time";
54pub const LAST_EXECUTION_TIME: &str = "last_execution_time";
55pub const UPTIME_SECONDS: &str = "uptime_seconds";
56pub const STATE_SIZE: &str = "state_size";
57
58#[derive(Debug)]
60pub(super) struct InformationSchemaFlowStatistics {
61 schema: SchemaRef,
62 catalog_name: String,
63 catalog_manager: Weak<dyn CatalogManager>,
64 flow_metadata_manager: Arc<FlowMetadataManager>,
65}
66
67impl InformationSchemaFlowStatistics {
68 pub(super) fn new(
69 catalog_name: String,
70 catalog_manager: Weak<dyn CatalogManager>,
71 flow_metadata_manager: Arc<FlowMetadataManager>,
72 ) -> Self {
73 Self {
74 schema: Self::schema(),
75 catalog_name,
76 catalog_manager,
77 flow_metadata_manager,
78 }
79 }
80
81 pub(crate) fn schema() -> SchemaRef {
82 Arc::new(Schema::new(
83 vec![
84 (FLOW_ID, CDT::uint32_datatype(), false),
85 (FLOW_NAME, CDT::string_datatype(), false),
86 (START_TIME, CDT::timestamp_millisecond_datatype(), true),
87 (
88 LAST_EXECUTION_TIME,
89 CDT::timestamp_millisecond_datatype(),
90 true,
91 ),
92 (UPTIME_SECONDS, CDT::int64_datatype(), true),
93 (STATE_SIZE, CDT::uint64_datatype(), true),
94 ]
95 .into_iter()
96 .map(|(name, ty, nullable)| ColumnSchema::new(name, ty, nullable))
97 .collect(),
98 ))
99 }
100
101 fn builder(&self) -> InformationSchemaFlowStatisticsBuilder {
102 InformationSchemaFlowStatisticsBuilder::new(
103 self.schema.clone(),
104 self.catalog_name.clone(),
105 self.catalog_manager.clone(),
106 &self.flow_metadata_manager,
107 )
108 }
109}
110
111impl InformationTable for InformationSchemaFlowStatistics {
112 fn scope(&self) -> InformationSchemaTableScope {
113 InformationSchemaTableScope::Catalog
114 }
115}
116
117impl SystemTable for InformationSchemaFlowStatistics {
118 fn table_id(&self) -> TableId {
119 INFORMATION_SCHEMA_FLOW_STATISTICS_TABLE_ID
120 }
121
122 fn table_name(&self) -> &'static str {
123 FLOW_STATISTICS
124 }
125
126 fn schema(&self) -> SchemaRef {
127 self.schema.clone()
128 }
129
130 fn to_stream(&self, request: ScanRequest) -> Result<SendableRecordBatchStream> {
131 let schema = self.schema.arrow_schema().clone();
132 let mut builder = self.builder();
133 let stream = Box::pin(DfRecordBatchStreamAdapter::new(
134 schema,
135 futures::stream::once(async move {
136 builder
137 .make_flow_statistics(Some(request))
138 .await
139 .map(|x| x.into_df_record_batch())
140 .map_err(|err| datafusion::error::DataFusionError::External(Box::new(err)))
141 }),
142 ));
143 Ok(Box::pin(
144 RecordBatchStreamAdapter::try_new(stream)
145 .map_err(BoxedError::new)
146 .context(InternalSnafu)?,
147 ))
148 }
149}
150
151struct InformationSchemaFlowStatisticsBuilder {
153 schema: SchemaRef,
154 catalog_name: String,
155 catalog_manager: Weak<dyn CatalogManager>,
156 flow_metadata_manager: Arc<FlowMetadataManager>,
157
158 flow_ids: UInt32VectorBuilder,
159 flow_names: StringVectorBuilder,
160 start_times: TimestampMillisecondVectorBuilder,
161 last_execution_times: TimestampMillisecondVectorBuilder,
162 uptime_seconds: Int64VectorBuilder,
163 state_sizes: UInt64VectorBuilder,
164}
165
166impl InformationSchemaFlowStatisticsBuilder {
167 fn new(
168 schema: SchemaRef,
169 catalog_name: String,
170 catalog_manager: Weak<dyn CatalogManager>,
171 flow_metadata_manager: &Arc<FlowMetadataManager>,
172 ) -> Self {
173 Self {
174 schema,
175 catalog_name,
176 catalog_manager,
177 flow_metadata_manager: flow_metadata_manager.clone(),
178
179 flow_ids: UInt32VectorBuilder::with_capacity(INIT_CAPACITY),
180 flow_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
181 start_times: TimestampMillisecondVectorBuilder::with_capacity(INIT_CAPACITY),
182 last_execution_times: TimestampMillisecondVectorBuilder::with_capacity(INIT_CAPACITY),
183 uptime_seconds: Int64VectorBuilder::with_capacity(INIT_CAPACITY),
184 state_sizes: UInt64VectorBuilder::with_capacity(INIT_CAPACITY),
185 }
186 }
187
188 async fn make_flow_statistics(&mut self, request: Option<ScanRequest>) -> Result<RecordBatch> {
190 let catalog_name = self.catalog_name.clone();
191 let predicates = Predicates::from_scan_request(&request);
192
193 let flow_info_manager = self.flow_metadata_manager.clone();
194
195 let mut stream = flow_info_manager
196 .flow_name_manager()
197 .flow_names(&catalog_name)
198 .await;
199
200 let flow_stat = {
201 let information_extension = utils::information_extension(&self.catalog_manager)?;
202 information_extension.flow_stats().await?
203 };
204
205 let now = current_time_millis();
206
207 while let Some((flow_name, flow_id)) = stream
208 .try_next()
209 .await
210 .map_err(BoxedError::new)
211 .context(ListFlowsSnafu {
212 catalog: &catalog_name,
213 })?
214 {
215 self.add_flow_statistic(&predicates, flow_id.flow_id(), &flow_name, &flow_stat, now);
216 }
217
218 self.finish()
219 }
220
221 fn add_flow_statistic(
222 &mut self,
223 predicates: &Predicates,
224 flow_id: FlowId,
225 flow_name: &str,
226 flow_stat: &Option<FlowStat>,
227 now: i64,
228 ) {
229 let row = [
230 (FLOW_ID, &Value::from(flow_id)),
231 (FLOW_NAME, &Value::from(flow_name.to_string())),
232 ];
233 if !predicates.eval(&row) {
234 return;
235 }
236
237 let start_time = flow_stat
238 .as_ref()
239 .and_then(|stat| stat.start_time_map.get(&flow_id).copied());
240
241 self.flow_ids.push(Some(flow_id));
242 self.flow_names.push(Some(flow_name));
243 self.start_times
244 .push(start_time.map(TimestampMillisecond::new));
245 self.last_execution_times
246 .push(flow_stat.as_ref().and_then(|stat| {
247 stat.last_exec_time_map
248 .get(&flow_id)
249 .map(|v| TimestampMillisecond::new(*v))
250 }));
251 self.uptime_seconds
252 .push(start_time.map(|start| ((now - start) / 1000).max(0)));
253 self.state_sizes.push(
254 flow_stat
255 .as_ref()
256 .and_then(|stat| stat.state_size.get(&flow_id).map(|v| *v as u64)),
257 );
258 }
259
260 fn finish(&mut self) -> Result<RecordBatch> {
261 let columns: Vec<VectorRef> = vec![
262 Arc::new(self.flow_ids.finish()),
263 Arc::new(self.flow_names.finish()),
264 Arc::new(self.start_times.finish()),
265 Arc::new(self.last_execution_times.finish()),
266 Arc::new(self.uptime_seconds.finish()),
267 Arc::new(self.state_sizes.finish()),
268 ];
269 RecordBatch::new(self.schema.clone(), columns).context(CreateRecordBatchSnafu)
270 }
271}
272
273impl DfPartitionStream for InformationSchemaFlowStatistics {
274 fn schema(&self) -> &arrow_schema::SchemaRef {
275 self.schema.arrow_schema()
276 }
277
278 fn execute(&self, _: Arc<TaskContext>) -> DfSendableRecordBatchStream {
279 let schema: Arc<arrow_schema::Schema> = self.schema.arrow_schema().clone();
280 let mut builder = self.builder();
281 Box::pin(DfRecordBatchStreamAdapter::new(
282 schema,
283 futures::stream::once(async move {
284 builder
285 .make_flow_statistics(None)
286 .await
287 .map(|x| x.into_df_record_batch())
288 .map_err(Into::into)
289 }),
290 ))
291 }
292}