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 };
93 Ok(vec![node_info])
94 }
95
96 async fn procedures(&self) -> std::result::Result<Vec<(String, ProcedureInfo)>, Self::Error> {
97 self.procedure_manager
98 .list_procedures()
99 .await
100 .map_err(BoxedError::new)
101 .map(|procedures| {
102 procedures
103 .into_iter()
104 .map(|procedure| {
105 let status = procedure.state.as_str_name().to_string();
106 (status, procedure)
107 })
108 .collect::<Vec<_>>()
109 })
110 .context(catalog::error::ListProceduresSnafu)
111 }
112
113 async fn region_stats(&self) -> std::result::Result<Vec<RegionStat>, Self::Error> {
114 let stats = self
115 .region_server
116 .reportable_regions()
117 .into_iter()
118 .map(|stat| {
119 let region_stat = self
120 .region_server
121 .region_statistic(stat.region_id)
122 .unwrap_or_default();
123 RegionStat {
124 id: stat.region_id,
125 rcus: 0,
126 wcus: 0,
127 approximate_bytes: region_stat.estimated_disk_size(),
128 engine: stat.engine,
129 role: RegionRole::from(stat.role).into(),
130 num_rows: region_stat.num_rows,
131 memtable_size: region_stat.memtable_size,
132 manifest_size: region_stat.manifest_size,
133 sst_size: region_stat.sst_size,
134 sst_num: region_stat.sst_num,
135 index_size: region_stat.index_size,
136 region_manifest: region_stat.manifest.into(),
137 data_topic_latest_entry_id: region_stat.data_topic_latest_entry_id,
138 metadata_topic_latest_entry_id: region_stat.metadata_topic_latest_entry_id,
139 written_bytes: region_stat.written_bytes,
140 }
141 })
142 .collect::<Vec<_>>();
143 Ok(stats)
144 }
145
146 async fn flow_stats(&self) -> std::result::Result<Option<FlowStat>, Self::Error> {
147 Ok(Some(
148 self.flow_engine
149 .read()
150 .await
151 .as_ref()
152 .unwrap()
153 .gen_state_report()
154 .await,
155 ))
156 }
157
158 async fn inspect_datanode(
159 &self,
160 request: DatanodeInspectRequest,
161 ) -> std::result::Result<SendableRecordBatchStream, Self::Error> {
162 let req = QueryRequest {
163 plan: request
164 .build_plan()
165 .context(catalog::error::DatafusionSnafu)?,
166 region_id: RegionId::default(),
167 header: None,
168 };
169
170 self.region_server
171 .handle_read(req)
172 .await
173 .map_err(BoxedError::new)
174 .context(catalog::error::InternalSnafu)
175 }
176}