Skip to main content

standalone/
information_extension.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use 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    /// Set the flow engine for the standalone instance.
56    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            // For the standalone:
70            // - id always 0
71            // - empty string for peer_addr
72            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            // Use `self.start_time_ms` instead.
81            // It's not precise but enough.
82            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}