standalone/
information_extension.rs1use std::sync::Arc;
16
17use catalog::information_schema::{DatanodeInspectRequest, InformationExtension};
18use client::SendableRecordBatchStream;
19use client::api::v1::meta::RegionRole;
20use common_error::ext::BoxedError;
21use common_meta::cluster::{NodeInfo, NodeStatus};
22use common_meta::datanode::RegionStat;
23use common_meta::key::flow::flow_state::FlowStat;
24use common_meta::peer::Peer;
25use common_procedure::{ProcedureInfo, ProcedureManagerRef};
26use common_query::request::QueryRequest;
27use common_stat::{ResourceStatImpl, ResourceStatRef};
28use datanode::region_server::RegionServer;
29use flow::FlowDualEngineRef;
30use snafu::ResultExt;
31use store_api::storage::RegionId;
32use tokio::sync::RwLock;
33
34pub struct StandaloneInformationExtension {
35 region_server: RegionServer,
36 procedure_manager: ProcedureManagerRef,
37 start_time_ms: u64,
38 flow_engine: RwLock<Option<FlowDualEngineRef>>,
39 resource_stat: ResourceStatRef,
40}
41
42impl StandaloneInformationExtension {
43 pub fn new(region_server: RegionServer, procedure_manager: ProcedureManagerRef) -> Self {
44 let mut resource_stat = ResourceStatImpl::default();
45 resource_stat.start_collect_cpu_usage();
46 Self {
47 region_server,
48 procedure_manager,
49 start_time_ms: common_time::util::current_time_millis() as u64,
50 flow_engine: RwLock::new(None),
51 resource_stat: Arc::new(resource_stat),
52 }
53 }
54
55 pub async fn set_flow_engine(&self, flow_engine: FlowDualEngineRef) {
57 let mut guard = self.flow_engine.write().await;
58 *guard = Some(flow_engine);
59 }
60}
61
62#[async_trait::async_trait]
63impl InformationExtension for StandaloneInformationExtension {
64 type Error = catalog::error::Error;
65
66 async fn nodes(&self) -> std::result::Result<Vec<NodeInfo>, Self::Error> {
67 let build_info = common_version::build_info();
68 let node_info = NodeInfo {
69 peer: Peer {
73 id: 0,
74 addr: "".to_string(),
75 },
76 last_activity_ts: -1,
77 status: NodeStatus::Standalone,
78 version: build_info.version.to_string(),
79 git_commit: build_info.commit_short.to_string(),
80 start_time_ms: self.start_time_ms,
83 total_cpu_millicores: self.resource_stat.get_total_cpu_millicores(),
84 total_memory_bytes: self.resource_stat.get_total_memory_bytes(),
85 cpu_usage_millicores: self.resource_stat.get_cpu_usage_millicores(),
86 memory_usage_bytes: self.resource_stat.get_memory_usage_bytes(),
87 hostname: hostname::get()
88 .unwrap_or_default()
89 .to_string_lossy()
90 .to_string(),
91 env_vars: Default::default(),
92 schedulable: None,
93 };
94 Ok(vec![node_info])
95 }
96
97 async fn procedures(&self) -> std::result::Result<Vec<(String, ProcedureInfo)>, Self::Error> {
98 self.procedure_manager
99 .list_procedures()
100 .await
101 .map_err(BoxedError::new)
102 .map(|procedures| {
103 procedures
104 .into_iter()
105 .map(|procedure| {
106 let status = procedure.state.as_str_name().to_string();
107 (status, procedure)
108 })
109 .collect::<Vec<_>>()
110 })
111 .context(catalog::error::ListProceduresSnafu)
112 }
113
114 async fn region_stats(&self) -> std::result::Result<Vec<RegionStat>, Self::Error> {
115 let stats = self
116 .region_server
117 .reportable_regions()
118 .into_iter()
119 .map(|stat| {
120 let region_stat = self
121 .region_server
122 .region_statistic(stat.region_id)
123 .unwrap_or_default();
124 RegionStat {
125 id: stat.region_id,
126 rcus: 0,
127 wcus: 0,
128 approximate_bytes: region_stat.estimated_disk_size(),
129 engine: stat.engine,
130 role: RegionRole::from(stat.role).into(),
131 num_rows: region_stat.num_rows,
132 memtable_size: region_stat.memtable_size,
133 manifest_size: region_stat.manifest_size,
134 sst_size: region_stat.sst_size,
135 sst_num: region_stat.sst_num,
136 index_size: region_stat.index_size,
137 region_manifest: region_stat.manifest.into(),
138 data_topic_latest_entry_id: region_stat.data_topic_latest_entry_id,
139 metadata_topic_latest_entry_id: region_stat.metadata_topic_latest_entry_id,
140 written_bytes: region_stat.written_bytes,
141 ingested_parquet_bytes: region_stat.ingested_parquet_bytes,
142 query_cpu_time: region_stat.query_cpu_time,
143 query_scanned_bytes: region_stat.query_scanned_bytes,
144 min_timestamp: region_stat.min_timestamp,
145 max_timestamp: region_stat.max_timestamp,
146 }
147 })
148 .collect::<Vec<_>>();
149 Ok(stats)
150 }
151
152 async fn flow_stats(&self) -> std::result::Result<Option<FlowStat>, Self::Error> {
153 Ok(Some(
154 self.flow_engine
155 .read()
156 .await
157 .as_ref()
158 .unwrap()
159 .gen_state_report()
160 .await,
161 ))
162 }
163
164 async fn inspect_datanode(
165 &self,
166 request: DatanodeInspectRequest,
167 ) -> std::result::Result<SendableRecordBatchStream, Self::Error> {
168 let req = QueryRequest {
169 plan: request
170 .build_plan()
171 .context(catalog::error::DatafusionSnafu)?,
172 region_id: RegionId::default(),
173 header: None,
174 };
175
176 self.region_server
177 .handle_read(req)
178 .await
179 .map_err(BoxedError::new)
180 .context(catalog::error::InternalSnafu)
181 }
182}