Skip to main content

risingwave_rpc_client/
meta_client.rs

1// Copyright 2022 RisingWave Labs
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::collections::{BTreeMap, HashMap, HashSet};
16use std::fmt::{Debug, Display};
17use std::sync::Arc;
18use std::sync::atomic::AtomicBool;
19use std::sync::atomic::Ordering::Relaxed;
20use std::thread;
21use std::time::{Duration, SystemTime};
22
23use anyhow::{Context, anyhow};
24use async_trait::async_trait;
25use cluster_limit_service_client::ClusterLimitServiceClient;
26use either::Either;
27use futures::stream::BoxStream;
28use list_rate_limits_response::RateLimitInfo;
29use lru::LruCache;
30use replace_job_plan::ReplaceJob;
31use risingwave_common::RW_VERSION;
32use risingwave_common::catalog::{
33    AlterDatabaseParam, FunctionId, IndexId, ObjectId, SecretId, TableId,
34};
35use risingwave_common::config::{MAX_CONNECTION_WINDOW_SIZE, MetaConfig};
36use risingwave_common::hash::WorkerSlotMapping;
37use risingwave_common::id::{
38    ConnectionId, DatabaseId, JobId, SchemaId, SinkId, SubscriptionId, UserId, ViewId, WorkerId,
39};
40use risingwave_common::monitor::EndpointExt;
41use risingwave_common::system_param::AdaptiveParallelismStrategy;
42use risingwave_common::system_param::reader::SystemParamsReader;
43use risingwave_common::telemetry::report::TelemetryInfoFetcher;
44use risingwave_common::util::addr::HostAddr;
45use risingwave_common::util::meta_addr::MetaAddressStrategy;
46use risingwave_common::util::resource_util::cpu::total_cpu_available;
47use risingwave_common::util::resource_util::hostname;
48use risingwave_common::util::resource_util::memory::system_memory_available_bytes;
49use risingwave_error::bail;
50use risingwave_error::tonic::ErrorIsFromTonicServerImpl;
51use risingwave_hummock_sdk::change_log::{TableChangeLog, TableChangeLogs};
52use risingwave_hummock_sdk::version::{HummockVersion, HummockVersionDelta};
53use risingwave_hummock_sdk::{
54    CompactionGroupId, HummockEpoch, HummockVersionId, ObjectIdRange, SyncResult,
55};
56use risingwave_pb::backup_service::backup_service_client::BackupServiceClient;
57use risingwave_pb::backup_service::*;
58use risingwave_pb::catalog::{
59    Connection, PbComment, PbDatabase, PbFunction, PbIndex, PbSchema, PbSink, PbSource,
60    PbSubscription, PbTable, PbView, Table,
61};
62use risingwave_pb::cloud_service::cloud_service_client::CloudServiceClient;
63use risingwave_pb::cloud_service::*;
64use risingwave_pb::common::worker_node::Property;
65use risingwave_pb::common::{HostAddress, OptionalUint32, OptionalUint64, WorkerNode, WorkerType};
66use risingwave_pb::configured_monitor_service_client;
67use risingwave_pb::connector_service::sink_coordination_service_client::SinkCoordinationServiceClient;
68use risingwave_pb::ddl_service::alter_owner_request::Object;
69use risingwave_pb::ddl_service::create_iceberg_table_request::{PbSinkJobInfo, PbTableJobInfo};
70use risingwave_pb::ddl_service::ddl_service_client::DdlServiceClient;
71use risingwave_pb::ddl_service::*;
72use risingwave_pb::hummock::compact_task::TaskStatus;
73use risingwave_pb::hummock::get_compaction_score_response::PickerInfo;
74use risingwave_pb::hummock::get_table_change_logs_request::PbTableFilter;
75use risingwave_pb::hummock::hummock_manager_service_client::HummockManagerServiceClient;
76use risingwave_pb::hummock::rise_ctl_update_compaction_config_request::mutable_config::MutableConfig;
77use risingwave_pb::hummock::subscribe_compaction_event_request::Register;
78use risingwave_pb::hummock::write_limits::WriteLimit;
79use risingwave_pb::hummock::*;
80use risingwave_pb::iceberg_compaction::subscribe_iceberg_compaction_event_request::Register as IcebergRegister;
81use risingwave_pb::iceberg_compaction::{
82    SubscribeIcebergCompactionEventRequest, SubscribeIcebergCompactionEventResponse,
83    subscribe_iceberg_compaction_event_request,
84};
85use risingwave_pb::id::{ActorId, FragmentId, HummockSstableId, SourceId};
86use risingwave_pb::meta::alter_connector_props_request::{
87    AlterConnectorPropsObject, AlterIcebergTableIds, ExtraOptions,
88};
89use risingwave_pb::meta::cancel_creating_jobs_request::PbJobs;
90use risingwave_pb::meta::cluster_service_client::ClusterServiceClient;
91use risingwave_pb::meta::event_log_service_client::EventLogServiceClient;
92use risingwave_pb::meta::heartbeat_service_client::HeartbeatServiceClient;
93use risingwave_pb::meta::hosted_iceberg_catalog_service_client::HostedIcebergCatalogServiceClient;
94use risingwave_pb::meta::list_actor_splits_response::ActorSplit;
95use risingwave_pb::meta::list_actor_states_response::ActorState;
96use risingwave_pb::meta::list_cdc_progress_response::PbCdcProgress;
97use risingwave_pb::meta::list_iceberg_tables_response::IcebergTable;
98use risingwave_pb::meta::list_refresh_table_states_response::RefreshTableState;
99use risingwave_pb::meta::list_streaming_job_states_response::StreamingJobState;
100use risingwave_pb::meta::list_table_fragments_response::TableFragmentInfo;
101use risingwave_pb::meta::meta_member_service_client::MetaMemberServiceClient;
102use risingwave_pb::meta::notification_service_client::NotificationServiceClient;
103use risingwave_pb::meta::scale_service_client::ScaleServiceClient;
104use risingwave_pb::meta::serving_service_client::ServingServiceClient;
105use risingwave_pb::meta::session_param_service_client::SessionParamServiceClient;
106use risingwave_pb::meta::stream_manager_service_client::StreamManagerServiceClient;
107use risingwave_pb::meta::system_params_service_client::SystemParamsServiceClient;
108use risingwave_pb::meta::telemetry_info_service_client::TelemetryInfoServiceClient;
109use risingwave_pb::meta::{FragmentDistribution, *};
110use risingwave_pb::monitor_service::monitor_service_client::MonitorServiceClient;
111use risingwave_pb::monitor_service::stack_trace_request::ActorTracesFormat;
112use risingwave_pb::monitor_service::{StackTraceRequest, StackTraceResponse};
113use risingwave_pb::secret::PbSecretRef;
114use risingwave_pb::stream_plan::StreamFragmentGraph;
115use risingwave_pb::user::alter_default_privilege_request::Operation as AlterDefaultPrivilegeOperation;
116use risingwave_pb::user::update_user_request::UpdateField;
117use risingwave_pb::user::user_service_client::UserServiceClient;
118use risingwave_pb::user::*;
119use thiserror_ext::AsReport;
120use tokio::sync::mpsc::{Receiver, UnboundedSender, unbounded_channel};
121use tokio::sync::oneshot::Sender;
122use tokio::sync::{RwLock, mpsc, oneshot};
123use tokio::task::JoinHandle;
124use tokio::time::{self};
125use tokio_retry::strategy::{ExponentialBackoff, jitter};
126use tokio_stream::wrappers::UnboundedReceiverStream;
127use tonic::transport::Endpoint;
128use tonic::{Code, Request, Streaming};
129
130use crate::channel::{Channel, WrappedChannelExt};
131use crate::error::{Result, RpcError};
132use crate::hummock_meta_client::{
133    CompactionEventItem, HummockMetaClient, HummockMetaClientChangeLogInfo,
134    IcebergCompactionEventItem,
135};
136use crate::meta_rpc_client_method_impl;
137
138/// Client to meta server. Cloning the instance is lightweight.
139#[derive(Clone, Debug)]
140pub struct MetaClient {
141    worker_id: WorkerId,
142    worker_type: WorkerType,
143    host_addr: HostAddr,
144    inner: GrpcMetaClient,
145    meta_config: Arc<MetaConfig>,
146    cluster_id: String,
147    shutting_down: Arc<AtomicBool>,
148}
149
150impl MetaClient {
151    pub fn worker_id(&self) -> WorkerId {
152        self.worker_id
153    }
154
155    pub fn host_addr(&self) -> &HostAddr {
156        &self.host_addr
157    }
158
159    pub fn worker_type(&self) -> WorkerType {
160        self.worker_type
161    }
162
163    pub fn cluster_id(&self) -> &str {
164        &self.cluster_id
165    }
166
167    /// Subscribe to notification from meta.
168    pub async fn subscribe(
169        &self,
170        subscribe_type: SubscribeType,
171    ) -> Result<Streaming<SubscribeResponse>> {
172        let request = SubscribeRequest {
173            subscribe_type: subscribe_type as i32,
174            host: Some(self.host_addr.to_protobuf()),
175            worker_id: self.worker_id(),
176        };
177
178        let retry_strategy = GrpcMetaClient::retry_strategy_to_bound(
179            Duration::from_secs(self.meta_config.max_heartbeat_interval_secs as u64),
180            true,
181        );
182
183        tokio_retry::Retry::spawn(retry_strategy, || async {
184            let request = request.clone();
185            self.inner.subscribe(request).await
186        })
187        .await
188    }
189
190    pub async fn create_connection(
191        &self,
192        connection_name: String,
193        database_id: DatabaseId,
194        schema_id: SchemaId,
195        owner_id: UserId,
196        req: create_connection_request::Payload,
197    ) -> Result<WaitVersion> {
198        let request = CreateConnectionRequest {
199            name: connection_name,
200            database_id,
201            schema_id,
202            owner_id,
203            payload: Some(req),
204        };
205        let resp = self.inner.create_connection(request).await?;
206        Ok(resp
207            .version
208            .ok_or_else(|| anyhow!("wait version not set"))?)
209    }
210
211    pub async fn create_secret(
212        &self,
213        secret_name: String,
214        database_id: DatabaseId,
215        schema_id: SchemaId,
216        owner_id: UserId,
217        value: Vec<u8>,
218    ) -> Result<WaitVersion> {
219        let request = CreateSecretRequest {
220            name: secret_name,
221            database_id,
222            schema_id,
223            owner_id,
224            value,
225        };
226        let resp = self.inner.create_secret(request).await?;
227        Ok(resp
228            .version
229            .ok_or_else(|| anyhow!("wait version not set"))?)
230    }
231
232    pub async fn list_connections(&self, _name: Option<&str>) -> Result<Vec<Connection>> {
233        let request = ListConnectionsRequest {};
234        let resp = self.inner.list_connections(request).await?;
235        Ok(resp.connections)
236    }
237
238    pub async fn drop_connection(
239        &self,
240        connection_id: ConnectionId,
241        cascade: bool,
242    ) -> Result<WaitVersion> {
243        let request = DropConnectionRequest {
244            connection_id,
245            cascade,
246        };
247        let resp = self.inner.drop_connection(request).await?;
248        Ok(resp
249            .version
250            .ok_or_else(|| anyhow!("wait version not set"))?)
251    }
252
253    pub async fn drop_secret(&self, secret_id: SecretId, cascade: bool) -> Result<WaitVersion> {
254        let request = DropSecretRequest { secret_id, cascade };
255        let resp = self.inner.drop_secret(request).await?;
256        Ok(resp
257            .version
258            .ok_or_else(|| anyhow!("wait version not set"))?)
259    }
260
261    /// Register the current node to the cluster and set the corresponding worker id.
262    ///
263    /// Retry if there's connection issue with the meta node. Exit the process if the registration fails.
264    pub async fn register_new(
265        addr_strategy: MetaAddressStrategy,
266        worker_type: WorkerType,
267        addr: &HostAddr,
268        property: Property,
269        meta_config: Arc<MetaConfig>,
270    ) -> (Self, SystemParamsReader) {
271        let ret =
272            Self::register_new_inner(addr_strategy, worker_type, addr, property, meta_config).await;
273
274        match ret {
275            Ok(ret) => ret,
276            Err(err) => {
277                tracing::error!(error = %err.as_report(), "failed to register worker, exiting...");
278                std::process::exit(1);
279            }
280        }
281    }
282
283    async fn register_new_inner(
284        addr_strategy: MetaAddressStrategy,
285        worker_type: WorkerType,
286        addr: &HostAddr,
287        property: Property,
288        meta_config: Arc<MetaConfig>,
289    ) -> Result<(Self, SystemParamsReader)> {
290        tracing::info!("register meta client using strategy: {}", addr_strategy);
291
292        // Retry until reaching `max_heartbeat_interval_secs`
293        let retry_strategy = GrpcMetaClient::retry_strategy_to_bound(
294            Duration::from_secs(meta_config.max_heartbeat_interval_secs as u64),
295            true,
296        );
297
298        let init_result: Result<_> = tokio_retry::RetryIf::spawn(
299            retry_strategy,
300            || async {
301                let grpc_meta_client =
302                    GrpcMetaClient::new(&addr_strategy, meta_config.clone()).await?;
303
304                let add_worker_resp = grpc_meta_client
305                    .add_worker_node(AddWorkerNodeRequest {
306                        worker_type: worker_type as i32,
307                        host: Some(addr.to_protobuf()),
308                        property: Some(property.clone()),
309                        resource: Some(risingwave_pb::common::worker_node::Resource {
310                            rw_version: RW_VERSION.to_owned(),
311                            total_memory_bytes: system_memory_available_bytes() as _,
312                            total_cpu_cores: total_cpu_available() as _,
313                            hostname: hostname(),
314                        }),
315                    })
316                    .await
317                    .context("failed to add worker node")?;
318
319                let system_params_resp = grpc_meta_client
320                    .get_system_params(GetSystemParamsRequest {})
321                    .await
322                    .context("failed to get initial system params")?;
323
324                Ok((add_worker_resp, system_params_resp, grpc_meta_client))
325            },
326            // Only retry if there's any transient connection issue.
327            // If the error is from our implementation or business, do not retry it.
328            |e: &RpcError| !e.is_from_tonic_server_impl(),
329        )
330        .await;
331
332        let (add_worker_resp, system_params_resp, grpc_meta_client) = init_result?;
333        let worker_id = add_worker_resp
334            .node_id
335            .expect("AddWorkerNodeResponse::node_id is empty");
336
337        let meta_client = Self {
338            worker_id,
339            worker_type,
340            host_addr: addr.clone(),
341            inner: grpc_meta_client,
342            meta_config: meta_config.clone(),
343            cluster_id: add_worker_resp.cluster_id,
344            shutting_down: Arc::new(false.into()),
345        };
346
347        static REPORT_PANIC: std::sync::Once = std::sync::Once::new();
348        REPORT_PANIC.call_once(|| {
349            let meta_client_clone = meta_client.clone();
350            std::panic::update_hook(move |default_hook, info| {
351                // Try to report panic event to meta node.
352                meta_client_clone.try_add_panic_event_blocking(info, None);
353                default_hook(info);
354            });
355        });
356
357        Ok((meta_client, system_params_resp.params.unwrap().into()))
358    }
359
360    /// Activate the current node in cluster to confirm it's ready to serve.
361    pub async fn activate(&self, addr: &HostAddr) -> Result<()> {
362        let request = ActivateWorkerNodeRequest {
363            host: Some(addr.to_protobuf()),
364            node_id: self.worker_id,
365        };
366        let retry_strategy = GrpcMetaClient::retry_strategy_to_bound(
367            Duration::from_secs(self.meta_config.max_heartbeat_interval_secs as u64),
368            true,
369        );
370        tokio_retry::Retry::spawn(retry_strategy, || async {
371            let request = request.clone();
372            self.inner.activate_worker_node(request).await
373        })
374        .await?;
375
376        Ok(())
377    }
378
379    /// Send heartbeat signal to meta service.
380    pub async fn send_heartbeat(&self) -> Result<()> {
381        let request = HeartbeatRequest {
382            node_id: self.worker_id,
383            resource: Some(risingwave_pb::common::worker_node::Resource {
384                rw_version: RW_VERSION.to_owned(),
385                total_memory_bytes: system_memory_available_bytes() as _,
386                total_cpu_cores: total_cpu_available() as _,
387                hostname: hostname(),
388            }),
389        };
390        let resp = self.inner.heartbeat(request).await?;
391        if let Some(status) = resp.status
392            && status.code() == risingwave_pb::common::status::Code::UnknownWorker
393        {
394            // Ignore the error if we're already shutting down.
395            // Otherwise, exit the process.
396            if !self.shutting_down.load(Relaxed) {
397                tracing::error!(message = status.message, "worker expired");
398                std::process::exit(1);
399            }
400        }
401        Ok(())
402    }
403
404    pub async fn create_database(&self, db: PbDatabase) -> Result<WaitVersion> {
405        let request = CreateDatabaseRequest { db: Some(db) };
406        let resp = self.inner.create_database(request).await?;
407        // TODO: handle error in `resp.status` here
408        Ok(resp
409            .version
410            .ok_or_else(|| anyhow!("wait version not set"))?)
411    }
412
413    pub async fn create_schema(&self, schema: PbSchema) -> Result<WaitVersion> {
414        let request = CreateSchemaRequest {
415            schema: Some(schema),
416        };
417        let resp = self.inner.create_schema(request).await?;
418        // TODO: handle error in `resp.status` here
419        Ok(resp
420            .version
421            .ok_or_else(|| anyhow!("wait version not set"))?)
422    }
423
424    pub async fn create_materialized_view(
425        &self,
426        table: PbTable,
427        graph: StreamFragmentGraph,
428        dependencies: HashSet<ObjectId>,
429        resource_type: streaming_job_resource_type::ResourceType,
430        if_not_exists: bool,
431        refresh_interval_sec: Option<u64>,
432    ) -> Result<WaitVersion> {
433        let request = CreateMaterializedViewRequest {
434            materialized_view: Some(table),
435            fragment_graph: Some(graph),
436            resource_type: Some(PbStreamingJobResourceType {
437                resource_type: Some(resource_type),
438            }),
439            dependencies: dependencies.into_iter().collect(),
440            if_not_exists,
441            refresh_interval_sec,
442        };
443        let resp = self.inner.create_materialized_view(request).await?;
444        // TODO: handle error in `resp.status` here
445        Ok(resp
446            .version
447            .ok_or_else(|| anyhow!("wait version not set"))?)
448    }
449
450    pub async fn drop_materialized_view(
451        &self,
452        table_id: TableId,
453        cascade: bool,
454    ) -> Result<WaitVersion> {
455        let request = DropMaterializedViewRequest { table_id, cascade };
456
457        let resp = self.inner.drop_materialized_view(request).await?;
458        Ok(resp
459            .version
460            .ok_or_else(|| anyhow!("wait version not set"))?)
461    }
462
463    pub async fn create_source(
464        &self,
465        source: PbSource,
466        graph: Option<StreamFragmentGraph>,
467        if_not_exists: bool,
468    ) -> Result<WaitVersion> {
469        let request = CreateSourceRequest {
470            source: Some(source),
471            fragment_graph: graph,
472            if_not_exists,
473        };
474
475        let resp = self.inner.create_source(request).await?;
476        Ok(resp
477            .version
478            .ok_or_else(|| anyhow!("wait version not set"))?)
479    }
480
481    pub async fn create_sink(
482        &self,
483        sink: PbSink,
484        graph: StreamFragmentGraph,
485        dependencies: HashSet<ObjectId>,
486        resource_type: streaming_job_resource_type::ResourceType,
487        if_not_exists: bool,
488        since_timestamp_epoch: Option<u64>,
489    ) -> Result<WaitVersion> {
490        let request = CreateSinkRequest {
491            sink: Some(sink),
492            fragment_graph: Some(graph),
493            dependencies: dependencies.into_iter().collect(),
494            if_not_exists,
495            resource_type: Some(PbStreamingJobResourceType {
496                resource_type: Some(resource_type),
497            }),
498            since_timestamp_epoch,
499        };
500
501        let resp = self.inner.create_sink(request).await?;
502        Ok(resp
503            .version
504            .ok_or_else(|| anyhow!("wait version not set"))?)
505    }
506
507    pub async fn create_subscription(&self, subscription: PbSubscription) -> Result<WaitVersion> {
508        let request = CreateSubscriptionRequest {
509            subscription: Some(subscription),
510        };
511
512        let resp = self.inner.create_subscription(request).await?;
513        Ok(resp
514            .version
515            .ok_or_else(|| anyhow!("wait version not set"))?)
516    }
517
518    pub async fn create_function(&self, function: PbFunction) -> Result<WaitVersion> {
519        let request = CreateFunctionRequest {
520            function: Some(function),
521        };
522        let resp = self.inner.create_function(request).await?;
523        Ok(resp
524            .version
525            .ok_or_else(|| anyhow!("wait version not set"))?)
526    }
527
528    pub async fn create_table(
529        &self,
530        source: Option<PbSource>,
531        table: PbTable,
532        graph: StreamFragmentGraph,
533        job_type: PbTableJobType,
534        if_not_exists: bool,
535        dependencies: HashSet<ObjectId>,
536    ) -> Result<WaitVersion> {
537        let request = CreateTableRequest {
538            materialized_view: Some(table),
539            fragment_graph: Some(graph),
540            source,
541            job_type: job_type as _,
542            if_not_exists,
543            dependencies: dependencies.into_iter().collect(),
544        };
545        let resp = self.inner.create_table(request).await?;
546        // TODO: handle error in `resp.status` here
547        Ok(resp
548            .version
549            .ok_or_else(|| anyhow!("wait version not set"))?)
550    }
551
552    pub async fn comment_on(&self, comment: PbComment) -> Result<WaitVersion> {
553        let request = CommentOnRequest {
554            comment: Some(comment),
555        };
556        let resp = self.inner.comment_on(request).await?;
557        Ok(resp
558            .version
559            .ok_or_else(|| anyhow!("wait version not set"))?)
560    }
561
562    pub async fn alter_name(
563        &self,
564        object: alter_name_request::Object,
565        name: &str,
566    ) -> Result<WaitVersion> {
567        let request = AlterNameRequest {
568            object: Some(object),
569            new_name: name.to_owned(),
570        };
571        let resp = self.inner.alter_name(request).await?;
572        Ok(resp
573            .version
574            .ok_or_else(|| anyhow!("wait version not set"))?)
575    }
576
577    pub async fn alter_owner(&self, object: Object, owner_id: UserId) -> Result<WaitVersion> {
578        let request = AlterOwnerRequest {
579            object: Some(object),
580            owner_id,
581        };
582        let resp = self.inner.alter_owner(request).await?;
583        Ok(resp
584            .version
585            .ok_or_else(|| anyhow!("wait version not set"))?)
586    }
587
588    pub async fn alter_subscription_retention(
589        &self,
590        subscription_id: SubscriptionId,
591        retention_seconds: u64,
592        definition: String,
593    ) -> Result<WaitVersion> {
594        let request = AlterSubscriptionRetentionRequest {
595            subscription_id,
596            retention_seconds,
597            definition,
598        };
599        let resp = self.inner.alter_subscription_retention(request).await?;
600        Ok(resp
601            .version
602            .ok_or_else(|| anyhow!("wait version not set"))?)
603    }
604
605    pub async fn alter_database_param(
606        &self,
607        database_id: DatabaseId,
608        param: AlterDatabaseParam,
609    ) -> Result<WaitVersion> {
610        let request = match param {
611            AlterDatabaseParam::BarrierIntervalMs(barrier_interval_ms) => {
612                let barrier_interval_ms = OptionalUint32 {
613                    value: barrier_interval_ms,
614                };
615                AlterDatabaseParamRequest {
616                    database_id,
617                    param: Some(alter_database_param_request::Param::BarrierIntervalMs(
618                        barrier_interval_ms,
619                    )),
620                }
621            }
622            AlterDatabaseParam::CheckpointFrequency(checkpoint_frequency) => {
623                let checkpoint_frequency = OptionalUint64 {
624                    value: checkpoint_frequency,
625                };
626                AlterDatabaseParamRequest {
627                    database_id,
628                    param: Some(alter_database_param_request::Param::CheckpointFrequency(
629                        checkpoint_frequency,
630                    )),
631                }
632            }
633        };
634        let resp = self.inner.alter_database_param(request).await?;
635        Ok(resp
636            .version
637            .ok_or_else(|| anyhow!("wait version not set"))?)
638    }
639
640    pub async fn alter_set_schema(
641        &self,
642        object: alter_set_schema_request::Object,
643        new_schema_id: SchemaId,
644    ) -> Result<WaitVersion> {
645        let request = AlterSetSchemaRequest {
646            new_schema_id,
647            object: Some(object),
648        };
649        let resp = self.inner.alter_set_schema(request).await?;
650        Ok(resp
651            .version
652            .ok_or_else(|| anyhow!("wait version not set"))?)
653    }
654
655    pub async fn alter_source(&self, source: PbSource) -> Result<WaitVersion> {
656        let request = AlterSourceRequest {
657            source: Some(source),
658        };
659        let resp = self.inner.alter_source(request).await?;
660        Ok(resp
661            .version
662            .ok_or_else(|| anyhow!("wait version not set"))?)
663    }
664
665    pub async fn alter_parallelism(
666        &self,
667        job_id: JobId,
668        parallelism: PbTableParallelism,
669        adaptive_parallelism_strategy: Option<AdaptiveParallelismStrategy>,
670        deferred: bool,
671    ) -> Result<()> {
672        let request = AlterParallelismRequest {
673            table_id: job_id,
674            parallelism: Some(parallelism),
675            deferred,
676            adaptive_parallelism_strategy: adaptive_parallelism_strategy
677                .map(|strategy| strategy.to_string()),
678        };
679
680        self.inner.alter_parallelism(request).await?;
681        Ok(())
682    }
683
684    pub async fn alter_backfill_parallelism(
685        &self,
686        job_id: JobId,
687        parallelism: Option<PbTableParallelism>,
688        adaptive_parallelism_strategy: Option<AdaptiveParallelismStrategy>,
689        deferred: bool,
690    ) -> Result<()> {
691        let request = AlterBackfillParallelismRequest {
692            table_id: job_id,
693            parallelism,
694            deferred,
695            adaptive_parallelism_strategy: adaptive_parallelism_strategy
696                .map(|strategy| strategy.to_string()),
697        };
698
699        self.inner.alter_backfill_parallelism(request).await?;
700        Ok(())
701    }
702
703    pub async fn alter_streaming_job_config(
704        &self,
705        job_id: JobId,
706        entries_to_add: HashMap<String, String>,
707        keys_to_remove: Vec<String>,
708    ) -> Result<()> {
709        let request = AlterStreamingJobConfigRequest {
710            job_id,
711            entries_to_add,
712            keys_to_remove,
713        };
714
715        self.inner.alter_streaming_job_config(request).await?;
716        Ok(())
717    }
718
719    pub async fn alter_fragment_parallelism(
720        &self,
721        fragment_ids: Vec<FragmentId>,
722        parallelism: Option<PbTableParallelism>,
723    ) -> Result<()> {
724        let request = AlterFragmentParallelismRequest {
725            fragment_ids,
726            parallelism,
727        };
728
729        self.inner.alter_fragment_parallelism(request).await?;
730        Ok(())
731    }
732
733    pub async fn alter_cdc_table_backfill_parallelism(
734        &self,
735        table_id: JobId,
736        parallelism: PbTableParallelism,
737    ) -> Result<()> {
738        let request = AlterCdcTableBackfillParallelismRequest {
739            table_id,
740            parallelism: Some(parallelism),
741        };
742        self.inner
743            .alter_cdc_table_backfill_parallelism(request)
744            .await?;
745        Ok(())
746    }
747
748    pub async fn alter_resource_group(
749        &self,
750        job_id: JobId,
751        resource_group: Option<String>,
752        deferred: bool,
753    ) -> Result<()> {
754        let request = AlterResourceGroupRequest {
755            job_id,
756            resource_group,
757            deferred,
758        };
759
760        self.inner.alter_resource_group(request).await?;
761        Ok(())
762    }
763
764    pub async fn alter_database_resource_group(
765        &self,
766        database_id: DatabaseId,
767        resource_group: Option<String>,
768        deferred: bool,
769    ) -> Result<WaitVersion> {
770        let request = AlterDatabaseResourceGroupRequest {
771            database_id,
772            resource_group,
773            deferred,
774        };
775
776        let resp = self.inner.alter_database_resource_group(request).await?;
777        Ok(resp
778            .version
779            .ok_or_else(|| anyhow!("wait version not set"))?)
780    }
781
782    pub async fn alter_swap_rename(
783        &self,
784        object: alter_swap_rename_request::Object,
785    ) -> Result<WaitVersion> {
786        let request = AlterSwapRenameRequest {
787            object: Some(object),
788        };
789        let resp = self.inner.alter_swap_rename(request).await?;
790        Ok(resp
791            .version
792            .ok_or_else(|| anyhow!("wait version not set"))?)
793    }
794
795    pub async fn alter_secret(
796        &self,
797        secret_id: SecretId,
798        secret_name: String,
799        database_id: DatabaseId,
800        schema_id: SchemaId,
801        owner_id: UserId,
802        value: Vec<u8>,
803    ) -> Result<WaitVersion> {
804        let request = AlterSecretRequest {
805            secret_id,
806            name: secret_name,
807            database_id,
808            schema_id,
809            owner_id,
810            value,
811        };
812        let resp = self.inner.alter_secret(request).await?;
813        Ok(resp
814            .version
815            .ok_or_else(|| anyhow!("wait version not set"))?)
816    }
817
818    pub async fn replace_job(
819        &self,
820        graph: StreamFragmentGraph,
821        replace_job: ReplaceJob,
822    ) -> Result<WaitVersion> {
823        let request = ReplaceJobPlanRequest {
824            plan: Some(ReplaceJobPlan {
825                fragment_graph: Some(graph),
826                replace_job: Some(replace_job),
827            }),
828        };
829        let resp = self.inner.replace_job_plan(request).await?;
830        // TODO: handle error in `resp.status` here
831        Ok(resp
832            .version
833            .ok_or_else(|| anyhow!("wait version not set"))?)
834    }
835
836    pub async fn auto_schema_change(&self, schema_change: SchemaChangeEnvelope) -> Result<()> {
837        let request = AutoSchemaChangeRequest {
838            schema_change: Some(schema_change),
839        };
840        let _ = self.inner.auto_schema_change(request).await?;
841        Ok(())
842    }
843
844    pub async fn create_view(
845        &self,
846        view: PbView,
847        dependencies: HashSet<ObjectId>,
848    ) -> Result<WaitVersion> {
849        let request = CreateViewRequest {
850            view: Some(view),
851            dependencies: dependencies.into_iter().collect(),
852        };
853        let resp = self.inner.create_view(request).await?;
854        // TODO: handle error in `resp.status` here
855        Ok(resp
856            .version
857            .ok_or_else(|| anyhow!("wait version not set"))?)
858    }
859
860    pub async fn create_index(
861        &self,
862        index: PbIndex,
863        table: PbTable,
864        graph: StreamFragmentGraph,
865        resource_type: streaming_job_resource_type::ResourceType,
866        if_not_exists: bool,
867    ) -> Result<WaitVersion> {
868        let request = CreateIndexRequest {
869            index: Some(index),
870            index_table: Some(table),
871            fragment_graph: Some(graph),
872            if_not_exists,
873            resource_type: Some(PbStreamingJobResourceType {
874                resource_type: Some(resource_type),
875            }),
876        };
877        let resp = self.inner.create_index(request).await?;
878        // TODO: handle error in `resp.status` here
879        Ok(resp
880            .version
881            .ok_or_else(|| anyhow!("wait version not set"))?)
882    }
883
884    pub async fn drop_table(
885        &self,
886        source_id: Option<SourceId>,
887        table_id: TableId,
888        cascade: bool,
889    ) -> Result<WaitVersion> {
890        let request = DropTableRequest {
891            source_id: source_id.map(risingwave_pb::ddl_service::drop_table_request::SourceId::Id),
892            table_id,
893            cascade,
894        };
895
896        let resp = self.inner.drop_table(request).await?;
897        Ok(resp
898            .version
899            .ok_or_else(|| anyhow!("wait version not set"))?)
900    }
901
902    pub async fn compact_iceberg_table(&self, sink_id: SinkId) -> Result<u64> {
903        let request = CompactIcebergTableRequest { sink_id };
904        let resp = self.inner.compact_iceberg_table(request).await?;
905        Ok(resp.task_id)
906    }
907
908    pub async fn expire_iceberg_table_snapshots(&self, sink_id: SinkId) -> Result<()> {
909        let request = ExpireIcebergTableSnapshotsRequest { sink_id };
910        let _resp = self.inner.expire_iceberg_table_snapshots(request).await?;
911        Ok(())
912    }
913
914    pub async fn drop_view(&self, view_id: ViewId, cascade: bool) -> Result<WaitVersion> {
915        let request = DropViewRequest { view_id, cascade };
916        let resp = self.inner.drop_view(request).await?;
917        Ok(resp
918            .version
919            .ok_or_else(|| anyhow!("wait version not set"))?)
920    }
921
922    pub async fn drop_source(&self, source_id: SourceId, cascade: bool) -> Result<WaitVersion> {
923        let request = DropSourceRequest { source_id, cascade };
924        let resp = self.inner.drop_source(request).await?;
925        Ok(resp
926            .version
927            .ok_or_else(|| anyhow!("wait version not set"))?)
928    }
929
930    pub async fn reset_source(&self, source_id: SourceId) -> Result<WaitVersion> {
931        let request = ResetSourceRequest { source_id };
932        let resp = self.inner.reset_source(request).await?;
933        Ok(resp
934            .version
935            .ok_or_else(|| anyhow!("wait version not set"))?)
936    }
937
938    pub async fn drop_sink(&self, sink_id: SinkId, cascade: bool) -> Result<WaitVersion> {
939        let request = DropSinkRequest { sink_id, cascade };
940        let resp = self.inner.drop_sink(request).await?;
941        Ok(resp
942            .version
943            .ok_or_else(|| anyhow!("wait version not set"))?)
944    }
945
946    pub async fn drop_subscription(
947        &self,
948        subscription_id: SubscriptionId,
949        cascade: bool,
950    ) -> Result<WaitVersion> {
951        let request = DropSubscriptionRequest {
952            subscription_id,
953            cascade,
954        };
955        let resp = self.inner.drop_subscription(request).await?;
956        Ok(resp
957            .version
958            .ok_or_else(|| anyhow!("wait version not set"))?)
959    }
960
961    pub async fn drop_index(&self, index_id: IndexId, cascade: bool) -> Result<WaitVersion> {
962        let request = DropIndexRequest { index_id, cascade };
963        let resp = self.inner.drop_index(request).await?;
964        Ok(resp
965            .version
966            .ok_or_else(|| anyhow!("wait version not set"))?)
967    }
968
969    pub async fn drop_function(
970        &self,
971        function_id: FunctionId,
972        cascade: bool,
973    ) -> Result<WaitVersion> {
974        let request = DropFunctionRequest {
975            function_id,
976            cascade,
977        };
978        let resp = self.inner.drop_function(request).await?;
979        Ok(resp
980            .version
981            .ok_or_else(|| anyhow!("wait version not set"))?)
982    }
983
984    pub async fn drop_database(&self, database_id: DatabaseId) -> Result<WaitVersion> {
985        let request = DropDatabaseRequest { database_id };
986        let resp = self.inner.drop_database(request).await?;
987        Ok(resp
988            .version
989            .ok_or_else(|| anyhow!("wait version not set"))?)
990    }
991
992    pub async fn drop_schema(&self, schema_id: SchemaId, cascade: bool) -> Result<WaitVersion> {
993        let request = DropSchemaRequest { schema_id, cascade };
994        let resp = self.inner.drop_schema(request).await?;
995        Ok(resp
996            .version
997            .ok_or_else(|| anyhow!("wait version not set"))?)
998    }
999
1000    // TODO: using UserInfoVersion instead as return type.
1001    pub async fn create_user(&self, user: UserInfo) -> Result<u64> {
1002        let request = CreateUserRequest { user: Some(user) };
1003        let resp = self.inner.create_user(request).await?;
1004        Ok(resp.version)
1005    }
1006
1007    pub async fn drop_user(&self, user_id: UserId) -> Result<u64> {
1008        let request = DropUserRequest { user_id };
1009        let resp = self.inner.drop_user(request).await?;
1010        Ok(resp.version)
1011    }
1012
1013    pub async fn update_user(
1014        &self,
1015        user: UserInfo,
1016        update_fields: Vec<UpdateField>,
1017    ) -> Result<u64> {
1018        let request = UpdateUserRequest {
1019            user: Some(user),
1020            update_fields: update_fields
1021                .into_iter()
1022                .map(|field| field as i32)
1023                .collect::<Vec<_>>(),
1024        };
1025        let resp = self.inner.update_user(request).await?;
1026        Ok(resp.version)
1027    }
1028
1029    pub async fn grant_privilege(
1030        &self,
1031        user_ids: Vec<UserId>,
1032        privileges: Vec<GrantPrivilege>,
1033        with_grant_option: bool,
1034        granted_by: UserId,
1035    ) -> Result<u64> {
1036        let request = GrantPrivilegeRequest {
1037            user_ids,
1038            privileges,
1039            with_grant_option,
1040            granted_by,
1041        };
1042        let resp = self.inner.grant_privilege(request).await?;
1043        Ok(resp.version)
1044    }
1045
1046    pub async fn revoke_privilege(
1047        &self,
1048        user_ids: Vec<UserId>,
1049        privileges: Vec<GrantPrivilege>,
1050        granted_by: UserId,
1051        revoke_by: UserId,
1052        revoke_grant_option: bool,
1053        cascade: bool,
1054    ) -> Result<u64> {
1055        let request = RevokePrivilegeRequest {
1056            user_ids,
1057            privileges,
1058            granted_by,
1059            revoke_by,
1060            revoke_grant_option,
1061            cascade,
1062        };
1063        let resp = self.inner.revoke_privilege(request).await?;
1064        Ok(resp.version)
1065    }
1066
1067    pub async fn alter_default_privilege(
1068        &self,
1069        user_ids: Vec<UserId>,
1070        database_id: DatabaseId,
1071        schema_ids: Vec<SchemaId>,
1072        operation: AlterDefaultPrivilegeOperation,
1073        granted_by: UserId,
1074    ) -> Result<()> {
1075        let request = AlterDefaultPrivilegeRequest {
1076            user_ids,
1077            database_id,
1078            schema_ids,
1079            operation: Some(operation),
1080            granted_by,
1081        };
1082        self.inner.alter_default_privilege(request).await?;
1083        Ok(())
1084    }
1085
1086    /// Unregister the current node from the cluster.
1087    pub async fn unregister(&self) -> Result<()> {
1088        let request = DeleteWorkerNodeRequest {
1089            host: Some(self.host_addr.to_protobuf()),
1090        };
1091        self.inner.delete_worker_node(request).await?;
1092        self.shutting_down.store(true, Relaxed);
1093        Ok(())
1094    }
1095
1096    /// Try to unregister the current worker from the cluster with best effort. Log the result.
1097    pub async fn try_unregister(&self) {
1098        match self.unregister().await {
1099            Ok(_) => {
1100                tracing::info!(
1101                    worker_id = %self.worker_id(),
1102                    "successfully unregistered from meta service",
1103                )
1104            }
1105            Err(e) => {
1106                tracing::warn!(
1107                    error = %e.as_report(),
1108                    worker_id = %self.worker_id(),
1109                    "failed to unregister from meta service",
1110                );
1111            }
1112        }
1113    }
1114
1115    pub async fn list_worker_nodes(
1116        &self,
1117        worker_type: Option<WorkerType>,
1118    ) -> Result<Vec<WorkerNode>> {
1119        let request = ListAllNodesRequest {
1120            worker_type: worker_type.map(Into::into),
1121            include_starting_nodes: true,
1122        };
1123        let resp = self.inner.list_all_nodes(request).await?;
1124        Ok(resp.nodes)
1125    }
1126
1127    /// Starts a heartbeat worker.
1128    pub fn start_heartbeat_loop(
1129        meta_client: MetaClient,
1130        min_interval: Duration,
1131    ) -> (JoinHandle<()>, Sender<()>) {
1132        let (shutdown_tx, mut shutdown_rx) = tokio::sync::oneshot::channel();
1133        let join_handle = tokio::spawn(async move {
1134            let mut min_interval_ticker = tokio::time::interval(min_interval);
1135            loop {
1136                tokio::select! {
1137                    biased;
1138                    // Shutdown
1139                    _ = &mut shutdown_rx => {
1140                        tracing::info!("Heartbeat loop is stopped");
1141                        return;
1142                    }
1143                    // Wait for interval
1144                    _ = min_interval_ticker.tick() => {},
1145                }
1146                tracing::debug!(target: "events::meta::client_heartbeat", "heartbeat");
1147                match tokio::time::timeout(
1148                    // TODO: decide better min_interval for timeout
1149                    min_interval * 3,
1150                    meta_client.send_heartbeat(),
1151                )
1152                .await
1153                {
1154                    Ok(Ok(_)) => {}
1155                    Ok(Err(err)) => {
1156                        tracing::warn!(error = %err.as_report(), "Failed to send_heartbeat");
1157                    }
1158                    Err(_) => {
1159                        tracing::warn!("Failed to send_heartbeat: timeout");
1160                    }
1161                }
1162            }
1163        });
1164        (join_handle, shutdown_tx)
1165    }
1166
1167    pub async fn risectl_list_state_tables(&self) -> Result<Vec<PbTable>> {
1168        let request = RisectlListStateTablesRequest {};
1169        let resp = self.inner.risectl_list_state_tables(request).await?;
1170        Ok(resp.tables)
1171    }
1172
1173    pub async fn risectl_resume_backfill(
1174        &self,
1175        request: RisectlResumeBackfillRequest,
1176    ) -> Result<()> {
1177        self.inner.risectl_resume_backfill(request).await?;
1178        Ok(())
1179    }
1180
1181    pub async fn flush(&self, database_id: DatabaseId) -> Result<HummockVersionId> {
1182        let request = FlushRequest { database_id };
1183        let resp = self.inner.flush(request).await?;
1184        Ok(resp.hummock_version_id)
1185    }
1186
1187    pub async fn wait(&self, job_id: Option<JobId>) -> Result<WaitVersion> {
1188        let request = WaitRequest { job_id };
1189        let resp = self.inner.wait(request).await?;
1190        Ok(resp
1191            .version
1192            .ok_or_else(|| anyhow!("wait version not set"))?)
1193    }
1194
1195    pub async fn recover(&self) -> Result<()> {
1196        let request = RecoverRequest {};
1197        self.inner.recover(request).await?;
1198        Ok(())
1199    }
1200
1201    pub async fn cancel_creating_jobs(&self, jobs: PbJobs) -> Result<Vec<u32>> {
1202        let request = CancelCreatingJobsRequest { jobs: Some(jobs) };
1203        let resp = self.inner.cancel_creating_jobs(request).await?;
1204        Ok(resp.canceled_jobs)
1205    }
1206
1207    pub async fn list_table_fragments(
1208        &self,
1209        job_ids: &[JobId],
1210    ) -> Result<HashMap<JobId, TableFragmentInfo>> {
1211        let request = ListTableFragmentsRequest {
1212            table_ids: job_ids.to_vec(),
1213        };
1214        let resp = self.inner.list_table_fragments(request).await?;
1215        Ok(resp.table_fragments)
1216    }
1217
1218    pub async fn list_streaming_job_states(&self) -> Result<Vec<StreamingJobState>> {
1219        let resp = self
1220            .inner
1221            .list_streaming_job_states(ListStreamingJobStatesRequest {})
1222            .await?;
1223        Ok(resp.states)
1224    }
1225
1226    pub async fn list_fragment_distributions(
1227        &self,
1228        include_node: bool,
1229    ) -> Result<Vec<FragmentDistribution>> {
1230        let resp = self
1231            .inner
1232            .list_fragment_distribution(ListFragmentDistributionRequest {
1233                include_node: Some(include_node),
1234            })
1235            .await?;
1236        Ok(resp.distributions)
1237    }
1238
1239    pub async fn list_creating_fragment_distribution(&self) -> Result<Vec<FragmentDistribution>> {
1240        let resp = self
1241            .inner
1242            .list_creating_fragment_distribution(ListCreatingFragmentDistributionRequest {
1243                include_node: Some(true),
1244            })
1245            .await?;
1246        Ok(resp.distributions)
1247    }
1248
1249    pub async fn get_fragment_by_id(
1250        &self,
1251        fragment_id: FragmentId,
1252    ) -> Result<Option<FragmentDistribution>> {
1253        let resp = self
1254            .inner
1255            .get_fragment_by_id(GetFragmentByIdRequest { fragment_id })
1256            .await?;
1257        Ok(resp.distribution)
1258    }
1259
1260    pub async fn get_fragment_vnodes(
1261        &self,
1262        fragment_id: FragmentId,
1263    ) -> Result<Vec<(ActorId, Vec<u32>)>> {
1264        let resp = self
1265            .inner
1266            .get_fragment_vnodes(GetFragmentVnodesRequest { fragment_id })
1267            .await?;
1268        Ok(resp
1269            .actor_vnodes
1270            .into_iter()
1271            .map(|actor| (actor.actor_id, actor.vnode_indices))
1272            .collect())
1273    }
1274
1275    pub async fn get_actor_vnodes(&self, actor_id: ActorId) -> Result<Vec<u32>> {
1276        let resp = self
1277            .inner
1278            .get_actor_vnodes(GetActorVnodesRequest { actor_id })
1279            .await?;
1280        Ok(resp.vnode_indices)
1281    }
1282
1283    pub async fn list_actor_states(&self) -> Result<Vec<ActorState>> {
1284        let resp = self
1285            .inner
1286            .list_actor_states(ListActorStatesRequest {})
1287            .await?;
1288        Ok(resp.states)
1289    }
1290
1291    pub async fn list_actor_splits(&self) -> Result<Vec<ActorSplit>> {
1292        let resp = self
1293            .inner
1294            .list_actor_splits(ListActorSplitsRequest {})
1295            .await?;
1296
1297        Ok(resp.actor_splits)
1298    }
1299
1300    pub async fn pause(&self) -> Result<PauseResponse> {
1301        let request = PauseRequest {};
1302        let resp = self.inner.pause(request).await?;
1303        Ok(resp)
1304    }
1305
1306    pub async fn resume(&self) -> Result<ResumeResponse> {
1307        let request = ResumeRequest {};
1308        let resp = self.inner.resume(request).await?;
1309        Ok(resp)
1310    }
1311
1312    pub async fn apply_throttle(
1313        &self,
1314        throttle_target: PbThrottleTarget,
1315        throttle_type: risingwave_pb::common::PbThrottleType,
1316        id: u32,
1317        rate: Option<u32>,
1318    ) -> Result<ApplyThrottleResponse> {
1319        let request = ApplyThrottleRequest {
1320            throttle_target: throttle_target as i32,
1321            throttle_type: throttle_type as i32,
1322            id,
1323            rate,
1324        };
1325        let resp = self.inner.apply_throttle(request).await?;
1326        Ok(resp)
1327    }
1328
1329    pub async fn get_cluster_recovery_status(&self) -> Result<RecoveryStatus> {
1330        let resp = self
1331            .inner
1332            .get_cluster_recovery_status(GetClusterRecoveryStatusRequest {})
1333            .await?;
1334        Ok(resp.get_status().unwrap())
1335    }
1336
1337    pub async fn get_cluster_info(&self) -> Result<GetClusterInfoResponse> {
1338        let request = GetClusterInfoRequest {};
1339        let resp = self.inner.get_cluster_info(request).await?;
1340        Ok(resp)
1341    }
1342
1343    pub async fn reschedule(
1344        &self,
1345        worker_reschedules: HashMap<u32, PbWorkerReschedule>,
1346        revision: u64,
1347        resolve_no_shuffle_upstream: bool,
1348    ) -> Result<(bool, u64)> {
1349        let request = RescheduleRequest {
1350            revision,
1351            resolve_no_shuffle_upstream,
1352            worker_reschedules,
1353        };
1354        let resp = self.inner.reschedule(request).await?;
1355        Ok((resp.success, resp.revision))
1356    }
1357
1358    pub async fn risectl_get_pinned_versions_summary(
1359        &self,
1360    ) -> Result<RiseCtlGetPinnedVersionsSummaryResponse> {
1361        let request = RiseCtlGetPinnedVersionsSummaryRequest {};
1362        self.inner
1363            .rise_ctl_get_pinned_versions_summary(request)
1364            .await
1365    }
1366
1367    pub async fn risectl_get_checkpoint_hummock_version(
1368        &self,
1369    ) -> Result<RiseCtlGetCheckpointVersionResponse> {
1370        let request = RiseCtlGetCheckpointVersionRequest {};
1371        self.inner.rise_ctl_get_checkpoint_version(request).await
1372    }
1373
1374    pub async fn risectl_pause_hummock_version_checkpoint(
1375        &self,
1376    ) -> Result<RiseCtlPauseVersionCheckpointResponse> {
1377        let request = RiseCtlPauseVersionCheckpointRequest {};
1378        self.inner.rise_ctl_pause_version_checkpoint(request).await
1379    }
1380
1381    pub async fn risectl_resume_hummock_version_checkpoint(
1382        &self,
1383    ) -> Result<RiseCtlResumeVersionCheckpointResponse> {
1384        let request = RiseCtlResumeVersionCheckpointRequest {};
1385        self.inner.rise_ctl_resume_version_checkpoint(request).await
1386    }
1387
1388    pub async fn init_metadata_for_replay(
1389        &self,
1390        tables: Vec<PbTable>,
1391        compaction_groups: Vec<CompactionGroupInfo>,
1392    ) -> Result<()> {
1393        let req = InitMetadataForReplayRequest {
1394            tables,
1395            compaction_groups,
1396        };
1397        let _resp = self.inner.init_metadata_for_replay(req).await?;
1398        Ok(())
1399    }
1400
1401    pub async fn replay_version_delta(
1402        &self,
1403        version_delta: HummockVersionDelta,
1404    ) -> Result<(HummockVersion, Vec<CompactionGroupId>)> {
1405        let req = ReplayVersionDeltaRequest {
1406            version_delta: Some(version_delta.into()),
1407        };
1408        let resp = self.inner.replay_version_delta(req).await?;
1409        Ok((
1410            HummockVersion::from_rpc_protobuf(&resp.version.unwrap()),
1411            resp.modified_compaction_groups,
1412        ))
1413    }
1414
1415    pub async fn list_version_deltas(
1416        &self,
1417        start_id: HummockVersionId,
1418        num_limit: u32,
1419        committed_epoch_limit: HummockEpoch,
1420    ) -> Result<Vec<HummockVersionDelta>> {
1421        let req = ListVersionDeltasRequest {
1422            start_id,
1423            num_limit,
1424            committed_epoch_limit,
1425        };
1426        Ok(self
1427            .inner
1428            .list_version_deltas(req)
1429            .await?
1430            .version_deltas
1431            .unwrap()
1432            .version_deltas
1433            .iter()
1434            .map(HummockVersionDelta::from_rpc_protobuf)
1435            .collect())
1436    }
1437
1438    pub async fn trigger_compaction_deterministic(
1439        &self,
1440        version_id: HummockVersionId,
1441        compaction_groups: Vec<CompactionGroupId>,
1442    ) -> Result<()> {
1443        let req = TriggerCompactionDeterministicRequest {
1444            version_id,
1445            compaction_groups,
1446        };
1447        self.inner.trigger_compaction_deterministic(req).await?;
1448        Ok(())
1449    }
1450
1451    pub async fn disable_commit_epoch(&self) -> Result<HummockVersion> {
1452        let req = DisableCommitEpochRequest {};
1453        Ok(HummockVersion::from_rpc_protobuf(
1454            &self
1455                .inner
1456                .disable_commit_epoch(req)
1457                .await?
1458                .current_version
1459                .unwrap(),
1460        ))
1461    }
1462
1463    pub async fn get_assigned_compact_task_num(&self) -> Result<usize> {
1464        let req = GetAssignedCompactTaskNumRequest {};
1465        let resp = self.inner.get_assigned_compact_task_num(req).await?;
1466        Ok(resp.num_tasks as usize)
1467    }
1468
1469    pub async fn risectl_list_compaction_group(&self) -> Result<Vec<CompactionGroupInfo>> {
1470        let req = RiseCtlListCompactionGroupRequest {};
1471        let resp = self.inner.rise_ctl_list_compaction_group(req).await?;
1472        Ok(resp.compaction_groups)
1473    }
1474
1475    pub async fn risectl_update_compaction_config(
1476        &self,
1477        compaction_groups: &[CompactionGroupId],
1478        configs: &[MutableConfig],
1479    ) -> Result<()> {
1480        let req = RiseCtlUpdateCompactionConfigRequest {
1481            compaction_group_ids: compaction_groups.to_vec(),
1482            configs: configs
1483                .iter()
1484                .map(
1485                    |c| rise_ctl_update_compaction_config_request::MutableConfig {
1486                        mutable_config: Some(c.clone()),
1487                    },
1488                )
1489                .collect(),
1490        };
1491        let _resp = self.inner.rise_ctl_update_compaction_config(req).await?;
1492        Ok(())
1493    }
1494
1495    pub async fn backup_meta(&self, remarks: Option<String>) -> Result<u64> {
1496        let req = BackupMetaRequest { remarks };
1497        let resp = self.inner.backup_meta(req).await?;
1498        Ok(resp.job_id)
1499    }
1500
1501    pub async fn get_backup_job_status(&self, job_id: u64) -> Result<(BackupJobStatus, String)> {
1502        let req = GetBackupJobStatusRequest { job_id };
1503        let resp = self.inner.get_backup_job_status(req).await?;
1504        Ok((resp.job_status(), resp.message))
1505    }
1506
1507    pub async fn delete_meta_snapshot(&self, snapshot_ids: &[u64]) -> Result<()> {
1508        let req = DeleteMetaSnapshotRequest {
1509            snapshot_ids: snapshot_ids.to_vec(),
1510        };
1511        let _resp = self.inner.delete_meta_snapshot(req).await?;
1512        Ok(())
1513    }
1514
1515    pub async fn get_meta_snapshot_manifest(&self) -> Result<MetaSnapshotManifest> {
1516        let req = GetMetaSnapshotManifestRequest {};
1517        let resp = self.inner.get_meta_snapshot_manifest(req).await?;
1518        Ok(resp.manifest.expect("should exist"))
1519    }
1520
1521    pub async fn get_telemetry_info(&self) -> Result<TelemetryInfoResponse> {
1522        let req = GetTelemetryInfoRequest {};
1523        let resp = self.inner.get_telemetry_info(req).await?;
1524        Ok(resp)
1525    }
1526
1527    pub async fn get_meta_store_endpoint(&self) -> Result<String> {
1528        let req = GetMetaStoreInfoRequest {};
1529        let resp = self.inner.get_meta_store_info(req).await?;
1530        Ok(resp.meta_store_endpoint)
1531    }
1532
1533    pub async fn alter_sink_props(
1534        &self,
1535        sink_id: SinkId,
1536        changed_props: BTreeMap<String, String>,
1537        changed_secret_refs: BTreeMap<String, PbSecretRef>,
1538        connector_conn_ref: Option<ConnectionId>,
1539    ) -> Result<()> {
1540        let req = AlterConnectorPropsRequest {
1541            object_id: sink_id.as_raw_id(),
1542            changed_props: changed_props.into_iter().collect(),
1543            changed_secret_refs: changed_secret_refs.into_iter().collect(),
1544            connector_conn_ref,
1545            object_type: AlterConnectorPropsObject::Sink as i32,
1546            extra_options: None,
1547        };
1548        let _resp = self.inner.alter_connector_props(req).await?;
1549        Ok(())
1550    }
1551
1552    pub async fn alter_iceberg_table_props(
1553        &self,
1554        table_id: TableId,
1555        sink_id: SinkId,
1556        source_id: SourceId,
1557        changed_props: BTreeMap<String, String>,
1558        changed_secret_refs: BTreeMap<String, PbSecretRef>,
1559        connector_conn_ref: Option<ConnectionId>,
1560    ) -> Result<()> {
1561        let req = AlterConnectorPropsRequest {
1562            object_id: table_id.as_raw_id(),
1563            changed_props: changed_props.into_iter().collect(),
1564            changed_secret_refs: changed_secret_refs.into_iter().collect(),
1565            connector_conn_ref,
1566            object_type: AlterConnectorPropsObject::IcebergTable as i32,
1567            extra_options: Some(ExtraOptions::AlterIcebergTableIds(AlterIcebergTableIds {
1568                sink_id,
1569                source_id,
1570            })),
1571        };
1572        let _resp = self.inner.alter_connector_props(req).await?;
1573        Ok(())
1574    }
1575
1576    pub async fn alter_source_connector_props(
1577        &self,
1578        source_id: SourceId,
1579        changed_props: BTreeMap<String, String>,
1580        changed_secret_refs: BTreeMap<String, PbSecretRef>,
1581        connector_conn_ref: Option<ConnectionId>,
1582    ) -> Result<()> {
1583        let req = AlterConnectorPropsRequest {
1584            object_id: source_id.as_raw_id(),
1585            changed_props: changed_props.into_iter().collect(),
1586            changed_secret_refs: changed_secret_refs.into_iter().collect(),
1587            connector_conn_ref,
1588            object_type: AlterConnectorPropsObject::Source as i32,
1589            extra_options: None,
1590        };
1591        let _resp = self.inner.alter_connector_props(req).await?;
1592        Ok(())
1593    }
1594
1595    pub async fn alter_connection_connector_props(
1596        &self,
1597        connection_id: u32,
1598        changed_props: BTreeMap<String, String>,
1599        changed_secret_refs: BTreeMap<String, PbSecretRef>,
1600    ) -> Result<()> {
1601        let req = AlterConnectorPropsRequest {
1602            object_id: connection_id,
1603            changed_props: changed_props.into_iter().collect(),
1604            changed_secret_refs: changed_secret_refs.into_iter().collect(),
1605            connector_conn_ref: None, // Connections don't reference other connections
1606            object_type: AlterConnectorPropsObject::Connection as i32,
1607            extra_options: None,
1608        };
1609        let _resp = self.inner.alter_connector_props(req).await?;
1610        Ok(())
1611    }
1612
1613    /// Orchestrated source property update with pause/update/resume workflow.
1614    /// This is the "safe" version that pauses sources before updating and resumes after.
1615    pub async fn alter_source_properties_safe(
1616        &self,
1617        source_id: SourceId,
1618        changed_props: BTreeMap<String, String>,
1619        changed_secret_refs: BTreeMap<String, PbSecretRef>,
1620        reset_splits: bool,
1621    ) -> Result<()> {
1622        let req = AlterSourcePropertiesSafeRequest {
1623            source_id: source_id.as_raw_id(),
1624            changed_props: changed_props.into_iter().collect(),
1625            changed_secret_refs: changed_secret_refs.into_iter().collect(),
1626            options: Some(PropertyUpdateOptions { reset_splits }),
1627        };
1628        let _resp = self.inner.alter_source_properties_safe(req).await?;
1629        Ok(())
1630    }
1631
1632    /// Reset source split assignments (UNSAFE - admin only).
1633    /// This clears persisted split metadata and triggers re-discovery.
1634    pub async fn reset_source_splits(&self, source_id: SourceId) -> Result<()> {
1635        let req = ResetSourceSplitsRequest {
1636            source_id: source_id.as_raw_id(),
1637        };
1638        let _resp = self.inner.reset_source_splits(req).await?;
1639        Ok(())
1640    }
1641
1642    /// Inject specific offsets into source splits (UNSAFE - admin only).
1643    /// This can cause data duplication or loss depending on the correctness of the provided offsets.
1644    pub async fn inject_source_offsets(
1645        &self,
1646        source_id: SourceId,
1647        split_offsets: HashMap<String, String>,
1648    ) -> Result<Vec<String>> {
1649        let req = InjectSourceOffsetsRequest {
1650            source_id: source_id.as_raw_id(),
1651            split_offsets,
1652        };
1653        let resp = self.inner.inject_source_offsets(req).await?;
1654        Ok(resp.applied_split_ids)
1655    }
1656
1657    pub async fn set_system_param(
1658        &self,
1659        param: String,
1660        value: Option<String>,
1661    ) -> Result<Option<SystemParamsReader>> {
1662        let req = SetSystemParamRequest { param, value };
1663        let resp = self.inner.set_system_param(req).await?;
1664        Ok(resp.params.map(SystemParamsReader::from))
1665    }
1666
1667    pub async fn get_session_params(&self) -> Result<String> {
1668        let req = GetSessionParamsRequest {};
1669        let resp = self.inner.get_session_params(req).await?;
1670        Ok(resp.params)
1671    }
1672
1673    pub async fn set_session_param(&self, param: String, value: Option<String>) -> Result<String> {
1674        let req = SetSessionParamRequest { param, value };
1675        let resp = self.inner.set_session_param(req).await?;
1676        Ok(resp.param)
1677    }
1678
1679    pub async fn get_ddl_progress(&self) -> Result<Vec<DdlProgress>> {
1680        let req = GetDdlProgressRequest {};
1681        let resp = self.inner.get_ddl_progress(req).await?;
1682        Ok(resp.ddl_progress)
1683    }
1684
1685    pub async fn split_compaction_group(
1686        &self,
1687        group_id: CompactionGroupId,
1688        table_ids_to_new_group: &[TableId],
1689        partition_vnode_count: u32,
1690    ) -> Result<CompactionGroupId> {
1691        let req = SplitCompactionGroupRequest {
1692            group_id,
1693            table_ids: table_ids_to_new_group.to_vec(),
1694            partition_vnode_count,
1695        };
1696        let resp = self.inner.split_compaction_group(req).await?;
1697        Ok(resp.new_group_id)
1698    }
1699
1700    pub async fn get_tables(
1701        &self,
1702        table_ids: Vec<TableId>,
1703        include_dropped_tables: bool,
1704    ) -> Result<HashMap<TableId, Table>> {
1705        let req = GetTablesRequest {
1706            table_ids,
1707            include_dropped_tables,
1708        };
1709        let resp = self.inner.get_tables(req).await?;
1710        Ok(resp.tables)
1711    }
1712
1713    pub async fn list_serving_vnode_mappings(
1714        &self,
1715    ) -> Result<HashMap<FragmentId, (JobId, WorkerSlotMapping)>> {
1716        let req = GetServingVnodeMappingsRequest {};
1717        let resp = self.inner.get_serving_vnode_mappings(req).await?;
1718        let mappings = resp
1719            .worker_slot_mappings
1720            .into_iter()
1721            .map(|p| {
1722                (
1723                    p.fragment_id,
1724                    (
1725                        resp.fragment_to_table
1726                            .get(&p.fragment_id)
1727                            .cloned()
1728                            .unwrap_or_default(),
1729                        WorkerSlotMapping::from_protobuf(p.mapping.as_ref().unwrap()),
1730                    ),
1731                )
1732            })
1733            .collect();
1734        Ok(mappings)
1735    }
1736
1737    pub async fn risectl_list_compaction_status(
1738        &self,
1739    ) -> Result<(
1740        Vec<CompactStatus>,
1741        Vec<CompactTaskAssignment>,
1742        Vec<CompactTaskProgress>,
1743    )> {
1744        let req = RiseCtlListCompactionStatusRequest {};
1745        let resp = self.inner.rise_ctl_list_compaction_status(req).await?;
1746        Ok((
1747            resp.compaction_statuses,
1748            resp.task_assignment,
1749            resp.task_progress,
1750        ))
1751    }
1752
1753    pub async fn get_compaction_score(
1754        &self,
1755        compaction_group_id: CompactionGroupId,
1756    ) -> Result<Vec<PickerInfo>> {
1757        let req = GetCompactionScoreRequest {
1758            compaction_group_id,
1759        };
1760        let resp = self.inner.get_compaction_score(req).await?;
1761        Ok(resp.scores)
1762    }
1763
1764    pub async fn risectl_rebuild_table_stats(&self) -> Result<()> {
1765        let req = RiseCtlRebuildTableStatsRequest {};
1766        let _resp = self.inner.rise_ctl_rebuild_table_stats(req).await?;
1767        Ok(())
1768    }
1769
1770    pub async fn list_branched_object(&self) -> Result<Vec<BranchedObject>> {
1771        let req = ListBranchedObjectRequest {};
1772        let resp = self.inner.list_branched_object(req).await?;
1773        Ok(resp.branched_objects)
1774    }
1775
1776    pub async fn list_active_write_limit(&self) -> Result<HashMap<CompactionGroupId, WriteLimit>> {
1777        let req = ListActiveWriteLimitRequest {};
1778        let resp = self.inner.list_active_write_limit(req).await?;
1779        Ok(resp.write_limits)
1780    }
1781
1782    pub async fn list_hummock_meta_config(&self) -> Result<HashMap<String, String>> {
1783        let req = ListHummockMetaConfigRequest {};
1784        let resp = self.inner.list_hummock_meta_config(req).await?;
1785        Ok(resp.configs)
1786    }
1787
1788    pub async fn get_table_change_logs(
1789        &self,
1790        epoch_only: bool,
1791        start_epoch_inclusive: Option<u64>,
1792        end_epoch_inclusive: Option<u64>,
1793        table_ids: Option<HashSet<TableId>>,
1794        exclude_empty: bool,
1795        limit: Option<u32>,
1796    ) -> Result<TableChangeLogs> {
1797        let req = GetTableChangeLogsRequest {
1798            epoch_only,
1799            start_epoch_inclusive,
1800            end_epoch_inclusive,
1801            table_ids: table_ids.map(|iter| PbTableFilter {
1802                table_ids: iter.into_iter().collect::<Vec<_>>(),
1803            }),
1804            exclude_empty,
1805            limit,
1806        };
1807        let resp = self.inner.get_table_change_logs(req).await?;
1808        Ok(resp
1809            .table_change_logs
1810            .into_iter()
1811            .map(|(id, change_log)| (TableId::new(id), TableChangeLog::from_protobuf(&change_log)))
1812            .collect())
1813    }
1814
1815    pub async fn delete_worker_node(&self, worker: HostAddress) -> Result<()> {
1816        let _resp = self
1817            .inner
1818            .delete_worker_node(DeleteWorkerNodeRequest { host: Some(worker) })
1819            .await?;
1820
1821        Ok(())
1822    }
1823
1824    pub async fn rw_cloud_validate_source(
1825        &self,
1826        source_type: SourceType,
1827        source_config: HashMap<String, String>,
1828    ) -> Result<RwCloudValidateSourceResponse> {
1829        let req = RwCloudValidateSourceRequest {
1830            source_type: source_type.into(),
1831            source_config,
1832        };
1833        let resp = self.inner.rw_cloud_validate_source(req).await?;
1834        Ok(resp)
1835    }
1836
1837    pub async fn sink_coordinate_client(&self) -> SinkCoordinationRpcClient {
1838        self.inner.core.read().await.sink_coordinate_client.clone()
1839    }
1840
1841    pub async fn list_compact_task_assignment(&self) -> Result<Vec<CompactTaskAssignment>> {
1842        let req = ListCompactTaskAssignmentRequest {};
1843        let resp = self.inner.list_compact_task_assignment(req).await?;
1844        Ok(resp.task_assignment)
1845    }
1846
1847    pub async fn list_event_log(&self) -> Result<Vec<EventLog>> {
1848        let req = ListEventLogRequest::default();
1849        let resp = self.inner.list_event_log(req).await?;
1850        Ok(resp.event_logs)
1851    }
1852
1853    pub async fn list_compact_task_progress(&self) -> Result<Vec<CompactTaskProgress>> {
1854        let req = ListCompactTaskProgressRequest {};
1855        let resp = self.inner.list_compact_task_progress(req).await?;
1856        Ok(resp.task_progress)
1857    }
1858
1859    #[cfg(madsim)]
1860    pub fn try_add_panic_event_blocking(
1861        &self,
1862        panic_info: impl Display,
1863        timeout_millis: Option<u64>,
1864    ) {
1865    }
1866
1867    /// If `timeout_millis` is None, default is used.
1868    #[cfg(not(madsim))]
1869    pub fn try_add_panic_event_blocking(
1870        &self,
1871        panic_info: impl Display,
1872        timeout_millis: Option<u64>,
1873    ) {
1874        let event = event_log::EventWorkerNodePanic {
1875            worker_id: self.worker_id,
1876            worker_type: self.worker_type.into(),
1877            host_addr: Some(self.host_addr.to_protobuf()),
1878            panic_info: format!("{panic_info}"),
1879        };
1880        let grpc_meta_client = self.inner.clone();
1881        let _ = thread::spawn(move || {
1882            let rt = tokio::runtime::Builder::new_current_thread()
1883                .enable_all()
1884                .build()
1885                .unwrap();
1886            let req = AddEventLogRequest {
1887                event: Some(add_event_log_request::Event::WorkerNodePanic(event)),
1888            };
1889            rt.block_on(async {
1890                let _ = tokio::time::timeout(
1891                    Duration::from_millis(timeout_millis.unwrap_or(1000)),
1892                    grpc_meta_client.add_event_log(req),
1893                )
1894                .await;
1895            });
1896        })
1897        .join();
1898    }
1899
1900    pub async fn add_sink_fail_evet(
1901        &self,
1902        sink_id: SinkId,
1903        sink_name: String,
1904        connector: String,
1905        error: String,
1906    ) -> Result<()> {
1907        let event = event_log::EventSinkFail {
1908            sink_id,
1909            sink_name,
1910            connector,
1911            error,
1912        };
1913        let req = AddEventLogRequest {
1914            event: Some(add_event_log_request::Event::SinkFail(event)),
1915        };
1916        self.inner.add_event_log(req).await?;
1917        Ok(())
1918    }
1919
1920    pub async fn add_cdc_auto_schema_change_fail_event(
1921        &self,
1922        source_id: SourceId,
1923        table_name: String,
1924        cdc_table_id: String,
1925        upstream_ddl: String,
1926        fail_info: String,
1927    ) -> Result<()> {
1928        let event = event_log::EventAutoSchemaChangeFail {
1929            table_id: source_id.as_cdc_table_id(),
1930            table_name,
1931            cdc_table_id,
1932            upstream_ddl,
1933            fail_info,
1934        };
1935        let req = AddEventLogRequest {
1936            event: Some(add_event_log_request::Event::AutoSchemaChangeFail(event)),
1937        };
1938        self.inner.add_event_log(req).await?;
1939        Ok(())
1940    }
1941
1942    pub async fn cancel_compact_task(&self, task_id: u64, task_status: TaskStatus) -> Result<bool> {
1943        let req = CancelCompactTaskRequest {
1944            task_id,
1945            task_status: task_status as _,
1946        };
1947        let resp = self.inner.cancel_compact_task(req).await?;
1948        Ok(resp.ret)
1949    }
1950
1951    pub async fn get_version_by_epoch(
1952        &self,
1953        epoch: HummockEpoch,
1954        table_id: TableId,
1955    ) -> Result<PbHummockVersion> {
1956        let req = GetVersionByEpochRequest { epoch, table_id };
1957        let resp = self.inner.get_version_by_epoch(req).await?;
1958        Ok(resp.version.unwrap())
1959    }
1960
1961    pub async fn get_cluster_limits(
1962        &self,
1963    ) -> Result<Vec<risingwave_common::util::cluster_limit::ClusterLimit>> {
1964        let req = GetClusterLimitsRequest {};
1965        let resp = self.inner.get_cluster_limits(req).await?;
1966        Ok(resp.active_limits.into_iter().map(|l| l.into()).collect())
1967    }
1968
1969    pub async fn merge_compaction_group(
1970        &self,
1971        left_group_id: CompactionGroupId,
1972        right_group_id: CompactionGroupId,
1973    ) -> Result<()> {
1974        let req = MergeCompactionGroupRequest {
1975            left_group_id,
1976            right_group_id,
1977        };
1978        self.inner.merge_compaction_group(req).await?;
1979        Ok(())
1980    }
1981
1982    /// List all rate limits for sources and backfills
1983    pub async fn list_rate_limits(&self) -> Result<Vec<RateLimitInfo>> {
1984        let request = ListRateLimitsRequest {};
1985        let resp = self.inner.list_rate_limits(request).await?;
1986        Ok(resp.rate_limits)
1987    }
1988
1989    pub async fn list_cdc_progress(&self) -> Result<HashMap<JobId, PbCdcProgress>> {
1990        let request = ListCdcProgressRequest {};
1991        let resp = self.inner.list_cdc_progress(request).await?;
1992        Ok(resp.cdc_progress)
1993    }
1994
1995    pub async fn list_refresh_table_states(&self) -> Result<Vec<RefreshTableState>> {
1996        let request = ListRefreshTableStatesRequest {};
1997        let resp = self.inner.list_refresh_table_states(request).await?;
1998        Ok(resp.states)
1999    }
2000
2001    pub async fn list_iceberg_compaction_status(
2002        &self,
2003    ) -> Result<Vec<list_iceberg_compaction_status_response::IcebergCompactionStatus>> {
2004        let request = ListIcebergCompactionStatusRequest {};
2005        let resp = self.inner.list_iceberg_compaction_status(request).await?;
2006        Ok(resp.statuses)
2007    }
2008
2009    pub async fn list_sink_log_store_tables(
2010        &self,
2011    ) -> Result<Vec<list_sink_log_store_tables_response::SinkLogStoreTable>> {
2012        let request = ListSinkLogStoreTablesRequest {};
2013        let resp = self.inner.list_sink_log_store_tables(request).await?;
2014        Ok(resp.tables)
2015    }
2016
2017    pub async fn create_iceberg_table(
2018        &self,
2019        table_job_info: PbTableJobInfo,
2020        sink_job_info: PbSinkJobInfo,
2021        iceberg_source: PbSource,
2022        if_not_exists: bool,
2023    ) -> Result<WaitVersion> {
2024        let request = CreateIcebergTableRequest {
2025            table_info: Some(table_job_info),
2026            sink_info: Some(sink_job_info),
2027            iceberg_source: Some(iceberg_source),
2028            if_not_exists,
2029        };
2030
2031        let resp = Box::pin(self.inner.create_iceberg_table(request)).await?;
2032        Ok(resp
2033            .version
2034            .ok_or_else(|| anyhow!("wait version not set"))?)
2035    }
2036
2037    pub async fn list_hosted_iceberg_tables(&self) -> Result<Vec<IcebergTable>> {
2038        let request = ListIcebergTablesRequest {};
2039        let resp = self.inner.list_iceberg_tables(request).await?;
2040        Ok(resp.iceberg_tables)
2041    }
2042
2043    /// Get the await tree of all nodes in the cluster.
2044    pub async fn get_cluster_stack_trace(
2045        &self,
2046        actor_traces_format: ActorTracesFormat,
2047    ) -> Result<StackTraceResponse> {
2048        let request = StackTraceRequest {
2049            actor_traces_format: actor_traces_format as i32,
2050        };
2051        let resp = self.inner.stack_trace(request).await?;
2052        Ok(resp)
2053    }
2054
2055    pub async fn set_sync_log_store_aligned(&self, job_id: JobId, aligned: bool) -> Result<()> {
2056        let request = SetSyncLogStoreAlignedRequest { job_id, aligned };
2057        self.inner.set_sync_log_store_aligned(request).await?;
2058        Ok(())
2059    }
2060
2061    pub async fn refresh(&self, request: RefreshRequest) -> Result<RefreshResponse> {
2062        self.inner.refresh(request).await
2063    }
2064
2065    pub async fn list_unmigrated_tables(&self) -> Result<HashMap<TableId, String>> {
2066        let request = ListUnmigratedTablesRequest {};
2067        let resp = self.inner.list_unmigrated_tables(request).await?;
2068        Ok(resp
2069            .tables
2070            .into_iter()
2071            .map(|table| (table.table_id, table.table_name))
2072            .collect())
2073    }
2074}
2075
2076#[async_trait]
2077impl HummockMetaClient for MetaClient {
2078    async fn unpin_version_before(&self, unpin_version_before: HummockVersionId) -> Result<()> {
2079        let req = UnpinVersionBeforeRequest {
2080            context_id: self.worker_id(),
2081            unpin_version_before,
2082        };
2083        self.inner.unpin_version_before(req).await?;
2084        Ok(())
2085    }
2086
2087    async fn get_current_version(&self) -> Result<HummockVersion> {
2088        let req = GetCurrentVersionRequest::default();
2089        Ok(HummockVersion::from_rpc_protobuf(
2090            &self
2091                .inner
2092                .get_current_version(req)
2093                .await?
2094                .current_version
2095                .unwrap(),
2096        ))
2097    }
2098
2099    async fn get_new_object_ids(&self, number: u32) -> Result<ObjectIdRange> {
2100        let resp = self
2101            .inner
2102            .get_new_object_ids(GetNewObjectIdsRequest { number })
2103            .await?;
2104        Ok(ObjectIdRange::new(resp.start_id, resp.end_id))
2105    }
2106
2107    async fn commit_epoch_with_change_log(
2108        &self,
2109        _epoch: HummockEpoch,
2110        _sync_result: SyncResult,
2111        _change_log_info: Option<HummockMetaClientChangeLogInfo>,
2112    ) -> Result<()> {
2113        panic!("Only meta service can commit_epoch in production.")
2114    }
2115
2116    async fn trigger_manual_compaction(
2117        &self,
2118        compaction_group_id: CompactionGroupId,
2119        table_id: JobId,
2120        level: u32,
2121        target_level: Option<u32>,
2122        sst_ids: Vec<HummockSstableId>,
2123        exclusive: bool,
2124    ) -> Result<bool> {
2125        // TODO: support key_range parameter
2126        let req = TriggerManualCompactionRequest {
2127            compaction_group_id,
2128            table_id,
2129            // if table_id not exist, manual_compaction will include all the sst
2130            // without check internal_table_id
2131            level,
2132            target_level,
2133            sst_ids,
2134            exclusive: Some(exclusive),
2135            ..Default::default()
2136        };
2137
2138        let resp = self.inner.trigger_manual_compaction(req).await?;
2139        Ok(resp.should_retry.unwrap_or(false))
2140    }
2141
2142    async fn trigger_full_gc(
2143        &self,
2144        sst_retention_time_sec: u64,
2145        prefix: Option<String>,
2146    ) -> Result<()> {
2147        self.inner
2148            .trigger_full_gc(TriggerFullGcRequest {
2149                sst_retention_time_sec,
2150                prefix,
2151            })
2152            .await?;
2153        Ok(())
2154    }
2155
2156    async fn subscribe_compaction_event(
2157        &self,
2158    ) -> Result<(
2159        UnboundedSender<SubscribeCompactionEventRequest>,
2160        BoxStream<'static, CompactionEventItem>,
2161    )> {
2162        let (request_sender, request_receiver) =
2163            unbounded_channel::<SubscribeCompactionEventRequest>();
2164        request_sender
2165            .send(SubscribeCompactionEventRequest {
2166                event: Some(subscribe_compaction_event_request::Event::Register(
2167                    Register {
2168                        context_id: self.worker_id(),
2169                    },
2170                )),
2171                create_at: SystemTime::now()
2172                    .duration_since(SystemTime::UNIX_EPOCH)
2173                    .expect("Clock may have gone backwards")
2174                    .as_millis() as u64,
2175            })
2176            .context("Failed to subscribe compaction event")?;
2177
2178        let stream = self
2179            .inner
2180            .subscribe_compaction_event(Request::new(UnboundedReceiverStream::new(
2181                request_receiver,
2182            )))
2183            .await?;
2184
2185        Ok((request_sender, Box::pin(stream)))
2186    }
2187
2188    async fn get_version_by_epoch(
2189        &self,
2190        epoch: HummockEpoch,
2191        table_id: TableId,
2192    ) -> Result<PbHummockVersion> {
2193        self.get_version_by_epoch(epoch, table_id).await
2194    }
2195
2196    async fn subscribe_iceberg_compaction_event(
2197        &self,
2198    ) -> Result<(
2199        UnboundedSender<SubscribeIcebergCompactionEventRequest>,
2200        BoxStream<'static, IcebergCompactionEventItem>,
2201    )> {
2202        let (request_sender, request_receiver) =
2203            unbounded_channel::<SubscribeIcebergCompactionEventRequest>();
2204        request_sender
2205            .send(SubscribeIcebergCompactionEventRequest {
2206                event: Some(subscribe_iceberg_compaction_event_request::Event::Register(
2207                    IcebergRegister {
2208                        context_id: self.worker_id(),
2209                    },
2210                )),
2211                create_at: SystemTime::now()
2212                    .duration_since(SystemTime::UNIX_EPOCH)
2213                    .expect("Clock may have gone backwards")
2214                    .as_millis() as u64,
2215            })
2216            .context("Failed to subscribe compaction event")?;
2217
2218        let stream = self
2219            .inner
2220            .subscribe_iceberg_compaction_event(Request::new(UnboundedReceiverStream::new(
2221                request_receiver,
2222            )))
2223            .await?;
2224
2225        Ok((request_sender, Box::pin(stream)))
2226    }
2227
2228    async fn get_table_change_logs(
2229        &self,
2230        epoch_only: bool,
2231        start_epoch_inclusive: Option<u64>,
2232        end_epoch_inclusive: Option<u64>,
2233        table_ids: Option<HashSet<TableId>>,
2234        exclude_empty: bool,
2235        limit: Option<u32>,
2236    ) -> Result<TableChangeLogs> {
2237        self.get_table_change_logs(
2238            epoch_only,
2239            start_epoch_inclusive,
2240            end_epoch_inclusive,
2241            table_ids,
2242            exclude_empty,
2243            limit,
2244        )
2245        .await
2246    }
2247}
2248
2249#[async_trait]
2250impl TelemetryInfoFetcher for MetaClient {
2251    async fn fetch_telemetry_info(&self) -> std::result::Result<Option<String>, String> {
2252        let resp = self
2253            .get_telemetry_info()
2254            .await
2255            .map_err(|e| e.to_report_string())?;
2256        let tracking_id = resp.get_tracking_id().ok();
2257        Ok(tracking_id.map(|id| id.to_owned()))
2258    }
2259}
2260
2261pub type SinkCoordinationRpcClient = SinkCoordinationServiceClient<Channel>;
2262
2263#[derive(Debug, Clone)]
2264struct GrpcMetaClientCore {
2265    cluster_client: ClusterServiceClient<Channel>,
2266    meta_member_client: MetaMemberServiceClient<Channel>,
2267    heartbeat_client: HeartbeatServiceClient<Channel>,
2268    ddl_client: DdlServiceClient<Channel>,
2269    hummock_client: HummockManagerServiceClient<Channel>,
2270    notification_client: NotificationServiceClient<Channel>,
2271    stream_client: StreamManagerServiceClient<Channel>,
2272    user_client: UserServiceClient<Channel>,
2273    scale_client: ScaleServiceClient<Channel>,
2274    backup_client: BackupServiceClient<Channel>,
2275    telemetry_client: TelemetryInfoServiceClient<Channel>,
2276    system_params_client: SystemParamsServiceClient<Channel>,
2277    session_params_client: SessionParamServiceClient<Channel>,
2278    serving_client: ServingServiceClient<Channel>,
2279    cloud_client: CloudServiceClient<Channel>,
2280    sink_coordinate_client: SinkCoordinationRpcClient,
2281    event_log_client: EventLogServiceClient<Channel>,
2282    cluster_limit_client: ClusterLimitServiceClient<Channel>,
2283    hosted_iceberg_catalog_service_client: HostedIcebergCatalogServiceClient<Channel>,
2284    monitor_client: MonitorServiceClient<Channel>,
2285}
2286
2287impl GrpcMetaClientCore {
2288    pub(crate) fn new(channel: Channel) -> Self {
2289        let cluster_client = ClusterServiceClient::new(channel.clone());
2290        let meta_member_client = MetaMemberClient::new(channel.clone());
2291        let heartbeat_client = HeartbeatServiceClient::new(channel.clone());
2292        let ddl_client =
2293            DdlServiceClient::new(channel.clone()).max_decoding_message_size(usize::MAX);
2294        let hummock_client =
2295            HummockManagerServiceClient::new(channel.clone()).max_decoding_message_size(usize::MAX);
2296        let notification_client =
2297            NotificationServiceClient::new(channel.clone()).max_decoding_message_size(usize::MAX);
2298        let stream_client =
2299            StreamManagerServiceClient::new(channel.clone()).max_decoding_message_size(usize::MAX);
2300        let user_client = UserServiceClient::new(channel.clone());
2301        let scale_client =
2302            ScaleServiceClient::new(channel.clone()).max_decoding_message_size(usize::MAX);
2303        let backup_client = BackupServiceClient::new(channel.clone());
2304        let telemetry_client =
2305            TelemetryInfoServiceClient::new(channel.clone()).max_decoding_message_size(usize::MAX);
2306        let system_params_client = SystemParamsServiceClient::new(channel.clone());
2307        let session_params_client = SessionParamServiceClient::new(channel.clone());
2308        let serving_client = ServingServiceClient::new(channel.clone());
2309        let cloud_client = CloudServiceClient::new(channel.clone());
2310        let sink_coordinate_client = SinkCoordinationServiceClient::new(channel.clone())
2311            .max_decoding_message_size(usize::MAX);
2312        let event_log_client = EventLogServiceClient::new(channel.clone());
2313        let cluster_limit_client = ClusterLimitServiceClient::new(channel.clone());
2314        let hosted_iceberg_catalog_service_client =
2315            HostedIcebergCatalogServiceClient::new(channel.clone());
2316        let monitor_client = configured_monitor_service_client(MonitorServiceClient::new(channel));
2317
2318        GrpcMetaClientCore {
2319            cluster_client,
2320            meta_member_client,
2321            heartbeat_client,
2322            ddl_client,
2323            hummock_client,
2324            notification_client,
2325            stream_client,
2326            user_client,
2327            scale_client,
2328            backup_client,
2329            telemetry_client,
2330            system_params_client,
2331            session_params_client,
2332            serving_client,
2333            cloud_client,
2334            sink_coordinate_client,
2335            event_log_client,
2336            cluster_limit_client,
2337            hosted_iceberg_catalog_service_client,
2338            monitor_client,
2339        }
2340    }
2341}
2342
2343/// Client to meta server. Cloning the instance is lightweight.
2344///
2345/// It is a wrapper of tonic client. See [`crate::meta_rpc_client_method_impl`].
2346#[derive(Debug, Clone)]
2347struct GrpcMetaClient {
2348    member_monitor_event_sender: mpsc::Sender<Sender<Result<()>>>,
2349    core: Arc<RwLock<GrpcMetaClientCore>>,
2350}
2351
2352type MetaMemberClient = MetaMemberServiceClient<Channel>;
2353
2354struct MetaMemberGroup {
2355    members: LruCache<http::Uri, Option<MetaMemberClient>>,
2356}
2357
2358struct MetaMemberManagement {
2359    core_ref: Arc<RwLock<GrpcMetaClientCore>>,
2360    members: Either<MetaMemberClient, MetaMemberGroup>,
2361    current_leader: http::Uri,
2362    meta_config: Arc<MetaConfig>,
2363}
2364
2365impl MetaMemberManagement {
2366    const META_MEMBER_REFRESH_PERIOD: Duration = Duration::from_secs(5);
2367
2368    fn host_address_to_uri(addr: HostAddress) -> http::Uri {
2369        format!("http://{}:{}", addr.host, addr.port)
2370            .parse()
2371            .unwrap()
2372    }
2373
2374    async fn recreate_core(&self, channel: Channel) {
2375        let mut core = self.core_ref.write().await;
2376        *core = GrpcMetaClientCore::new(channel);
2377    }
2378
2379    async fn refresh_members(&mut self) -> Result<()> {
2380        let leader_addr = match self.members.as_mut() {
2381            Either::Left(client) => {
2382                let resp = client
2383                    .to_owned()
2384                    .members(MembersRequest {})
2385                    .await
2386                    .map_err(RpcError::from_meta_status)?;
2387                let resp = resp.into_inner();
2388                resp.members.into_iter().find(|member| member.is_leader)
2389            }
2390            Either::Right(member_group) => {
2391                let mut fetched_members = None;
2392
2393                for (addr, client) in &mut member_group.members {
2394                    let members: Result<_> = try {
2395                        let mut client = match client {
2396                            Some(cached_client) => cached_client.to_owned(),
2397                            None => {
2398                                let endpoint = GrpcMetaClient::addr_to_endpoint(addr.clone());
2399                                let channel = GrpcMetaClient::connect_to_endpoint(endpoint)
2400                                    .await
2401                                    .context("failed to create client")
2402                                    .map_err(RpcError::from)?;
2403                                let new_client: MetaMemberClient =
2404                                    MetaMemberServiceClient::new(channel);
2405                                *client = Some(new_client.clone());
2406
2407                                new_client
2408                            }
2409                        };
2410
2411                        let resp = client
2412                            .members(MembersRequest {})
2413                            .await
2414                            .context("failed to fetch members")
2415                            .map_err(RpcError::from)?;
2416
2417                        resp.into_inner().members
2418                    };
2419
2420                    let fetched = members.is_ok();
2421                    fetched_members = Some(members);
2422                    if fetched {
2423                        break;
2424                    }
2425                }
2426
2427                let members = fetched_members
2428                    .context("no member available in the list")?
2429                    .context("could not refresh members")?;
2430
2431                // find new leader
2432                let mut leader = None;
2433                for member in members {
2434                    if member.is_leader {
2435                        leader = Some(member.clone());
2436                    }
2437
2438                    let addr = Self::host_address_to_uri(member.address.unwrap());
2439                    // We don't clean any expired addrs here to deal with some extreme situations.
2440                    if !member_group.members.contains(&addr) {
2441                        tracing::info!("new meta member joined: {}", addr);
2442                        member_group.members.put(addr, None);
2443                    }
2444                }
2445
2446                leader
2447            }
2448        };
2449
2450        if let Some(leader) = leader_addr {
2451            let discovered_leader = Self::host_address_to_uri(leader.address.unwrap());
2452
2453            if discovered_leader != self.current_leader {
2454                tracing::info!("new meta leader {} discovered", discovered_leader);
2455
2456                let retry_strategy = GrpcMetaClient::retry_strategy_to_bound(
2457                    Duration::from_secs(self.meta_config.meta_leader_lease_secs),
2458                    false,
2459                );
2460
2461                let channel = tokio_retry::Retry::spawn(retry_strategy, || async {
2462                    let endpoint = GrpcMetaClient::addr_to_endpoint(discovered_leader.clone());
2463                    GrpcMetaClient::connect_to_endpoint(endpoint).await
2464                })
2465                .await?;
2466
2467                self.recreate_core(channel).await;
2468                self.current_leader = discovered_leader;
2469            }
2470        }
2471
2472        Ok(())
2473    }
2474}
2475
2476impl GrpcMetaClient {
2477    // See `Endpoint::http2_keep_alive_interval`
2478    const ENDPOINT_KEEP_ALIVE_INTERVAL_SEC: u64 = 60;
2479    // See `Endpoint::keep_alive_timeout`
2480    const ENDPOINT_KEEP_ALIVE_TIMEOUT_SEC: u64 = 60;
2481    // Retry base interval in ms for connecting to meta server.
2482    const INIT_RETRY_BASE_INTERVAL_MS: u64 = 10;
2483    // Max retry times for connecting to meta server.
2484    const INIT_RETRY_MAX_INTERVAL_MS: u64 = 2000;
2485
2486    fn start_meta_member_monitor(
2487        &self,
2488        init_leader_addr: http::Uri,
2489        members: Either<MetaMemberClient, MetaMemberGroup>,
2490        force_refresh_receiver: Receiver<Sender<Result<()>>>,
2491        meta_config: Arc<MetaConfig>,
2492    ) -> Result<()> {
2493        let core_ref: Arc<RwLock<GrpcMetaClientCore>> = self.core.clone();
2494        let current_leader = init_leader_addr;
2495
2496        let enable_period_tick = matches!(members, Either::Right(_));
2497
2498        let member_management = MetaMemberManagement {
2499            core_ref,
2500            members,
2501            current_leader,
2502            meta_config,
2503        };
2504
2505        let mut force_refresh_receiver = force_refresh_receiver;
2506
2507        tokio::spawn(async move {
2508            let mut member_management = member_management;
2509            let mut ticker = time::interval(MetaMemberManagement::META_MEMBER_REFRESH_PERIOD);
2510
2511            loop {
2512                let event: Option<Sender<Result<()>>> = if enable_period_tick {
2513                    tokio::select! {
2514                        _ = ticker.tick() => None,
2515                        result_sender = force_refresh_receiver.recv() => {
2516                            if result_sender.is_none() {
2517                                break;
2518                            }
2519
2520                            result_sender
2521                        },
2522                    }
2523                } else {
2524                    let result_sender = force_refresh_receiver.recv().await;
2525
2526                    if result_sender.is_none() {
2527                        break;
2528                    }
2529
2530                    result_sender
2531                };
2532
2533                let tick_result = member_management.refresh_members().await;
2534                if let Err(e) = tick_result.as_ref() {
2535                    tracing::warn!(error = %e.as_report(),  "refresh meta member client failed");
2536                }
2537
2538                if let Some(sender) = event {
2539                    // ignore resp
2540                    let _resp = sender.send(tick_result);
2541                }
2542            }
2543        });
2544
2545        Ok(())
2546    }
2547
2548    async fn force_refresh_leader(&self) -> Result<()> {
2549        let (sender, receiver) = oneshot::channel();
2550
2551        self.member_monitor_event_sender
2552            .send(sender)
2553            .await
2554            .map_err(|e| anyhow!(e))?;
2555
2556        receiver.await.map_err(|e| anyhow!(e))?
2557    }
2558
2559    /// Connect to the meta server from `addrs`.
2560    pub async fn new(strategy: &MetaAddressStrategy, config: Arc<MetaConfig>) -> Result<Self> {
2561        let (channel, addr) = match strategy {
2562            MetaAddressStrategy::LoadBalance(addr) => {
2563                Self::try_build_rpc_channel(vec![addr.clone()]).await
2564            }
2565            MetaAddressStrategy::List(addrs) => Self::try_build_rpc_channel(addrs.clone()).await,
2566        }?;
2567        let (force_refresh_sender, force_refresh_receiver) = mpsc::channel(1);
2568        let client = GrpcMetaClient {
2569            member_monitor_event_sender: force_refresh_sender,
2570            core: Arc::new(RwLock::new(GrpcMetaClientCore::new(channel))),
2571        };
2572
2573        let meta_member_client = client.core.read().await.meta_member_client.clone();
2574        let members = match strategy {
2575            MetaAddressStrategy::LoadBalance(_) => Either::Left(meta_member_client),
2576            MetaAddressStrategy::List(addrs) => {
2577                let mut members = LruCache::new(20.try_into().unwrap());
2578                for addr in addrs {
2579                    members.put(addr.clone(), None);
2580                }
2581                members.put(addr.clone(), Some(meta_member_client));
2582
2583                Either::Right(MetaMemberGroup { members })
2584            }
2585        };
2586
2587        client.start_meta_member_monitor(addr, members, force_refresh_receiver, config.clone())?;
2588
2589        client.force_refresh_leader().await?;
2590
2591        Ok(client)
2592    }
2593
2594    fn addr_to_endpoint(addr: http::Uri) -> Endpoint {
2595        Endpoint::from(addr).initial_connection_window_size(MAX_CONNECTION_WINDOW_SIZE)
2596    }
2597
2598    pub(crate) async fn try_build_rpc_channel(
2599        addrs: impl IntoIterator<Item = http::Uri>,
2600    ) -> Result<(Channel, http::Uri)> {
2601        let endpoints: Vec<_> = addrs
2602            .into_iter()
2603            .map(|addr| (Self::addr_to_endpoint(addr.clone()), addr))
2604            .collect();
2605
2606        let mut last_error = None;
2607
2608        for (endpoint, addr) in endpoints {
2609            match Self::connect_to_endpoint(endpoint).await {
2610                Ok(channel) => {
2611                    tracing::info!("Connect to meta server {} successfully", addr);
2612                    return Ok((channel, addr));
2613                }
2614                Err(e) => {
2615                    tracing::warn!(
2616                        error = %e.as_report(),
2617                        "Failed to connect to meta server {}, trying again",
2618                        addr,
2619                    );
2620                    last_error = Some(e);
2621                }
2622            }
2623        }
2624
2625        if let Some(last_error) = last_error {
2626            Err(anyhow::anyhow!(last_error)
2627                .context("failed to connect to all meta servers")
2628                .into())
2629        } else {
2630            bail!("no meta server address provided")
2631        }
2632    }
2633
2634    async fn connect_to_endpoint(endpoint: Endpoint) -> Result<Channel> {
2635        let channel = endpoint
2636            .http2_keep_alive_interval(Duration::from_secs(Self::ENDPOINT_KEEP_ALIVE_INTERVAL_SEC))
2637            .keep_alive_timeout(Duration::from_secs(Self::ENDPOINT_KEEP_ALIVE_TIMEOUT_SEC))
2638            .connect_timeout(Duration::from_secs(5))
2639            .monitored_connect("grpc-meta-client", Default::default())
2640            .await?
2641            .wrapped();
2642
2643        Ok(channel)
2644    }
2645
2646    pub(crate) fn retry_strategy_to_bound(
2647        high_bound: Duration,
2648        exceed: bool,
2649    ) -> impl Iterator<Item = Duration> {
2650        let iter = ExponentialBackoff::from_millis(Self::INIT_RETRY_BASE_INTERVAL_MS)
2651            .max_delay(Duration::from_millis(Self::INIT_RETRY_MAX_INTERVAL_MS))
2652            .map(jitter);
2653
2654        let mut sum = Duration::default();
2655
2656        iter.take_while(move |duration| {
2657            sum += *duration;
2658
2659            if exceed {
2660                sum < high_bound + *duration
2661            } else {
2662                sum < high_bound
2663            }
2664        })
2665    }
2666}
2667
2668macro_rules! for_all_meta_rpc {
2669    ($macro:ident) => {
2670        $macro! {
2671             { cluster_client, add_worker_node, AddWorkerNodeRequest, AddWorkerNodeResponse }
2672            ,{ cluster_client, activate_worker_node, ActivateWorkerNodeRequest, ActivateWorkerNodeResponse }
2673            ,{ cluster_client, delete_worker_node, DeleteWorkerNodeRequest, DeleteWorkerNodeResponse }
2674            ,{ cluster_client, list_all_nodes, ListAllNodesRequest, ListAllNodesResponse }
2675            ,{ cluster_client, get_cluster_recovery_status, GetClusterRecoveryStatusRequest, GetClusterRecoveryStatusResponse }
2676            ,{ cluster_client, get_meta_store_info, GetMetaStoreInfoRequest, GetMetaStoreInfoResponse }
2677            ,{ heartbeat_client, heartbeat, HeartbeatRequest, HeartbeatResponse }
2678            ,{ stream_client, flush, FlushRequest, FlushResponse }
2679            ,{ stream_client, pause, PauseRequest, PauseResponse }
2680            ,{ stream_client, resume, ResumeRequest, ResumeResponse }
2681            ,{ stream_client, apply_throttle, ApplyThrottleRequest, ApplyThrottleResponse }
2682            ,{ stream_client, cancel_creating_jobs, CancelCreatingJobsRequest, CancelCreatingJobsResponse }
2683            ,{ stream_client, list_table_fragments, ListTableFragmentsRequest, ListTableFragmentsResponse }
2684            ,{ stream_client, list_streaming_job_states, ListStreamingJobStatesRequest, ListStreamingJobStatesResponse }
2685            ,{ stream_client, list_fragment_distribution, ListFragmentDistributionRequest, ListFragmentDistributionResponse }
2686            ,{ stream_client, list_creating_fragment_distribution, ListCreatingFragmentDistributionRequest, ListCreatingFragmentDistributionResponse }
2687            ,{ stream_client, list_sink_log_store_tables, ListSinkLogStoreTablesRequest, ListSinkLogStoreTablesResponse }
2688            ,{ stream_client, list_actor_states, ListActorStatesRequest, ListActorStatesResponse }
2689            ,{ stream_client, list_actor_splits, ListActorSplitsRequest, ListActorSplitsResponse }
2690            ,{ stream_client, recover, RecoverRequest, RecoverResponse }
2691            ,{ stream_client, list_rate_limits, ListRateLimitsRequest, ListRateLimitsResponse }
2692            ,{ stream_client, list_cdc_progress, ListCdcProgressRequest, ListCdcProgressResponse }
2693            ,{ stream_client, list_refresh_table_states, ListRefreshTableStatesRequest, ListRefreshTableStatesResponse }
2694            ,{ stream_client, list_iceberg_compaction_status, ListIcebergCompactionStatusRequest, ListIcebergCompactionStatusResponse }
2695            ,{ stream_client, alter_connector_props, AlterConnectorPropsRequest, AlterConnectorPropsResponse }
2696            ,{ stream_client, alter_source_properties_safe, AlterSourcePropertiesSafeRequest, AlterSourcePropertiesSafeResponse }
2697            ,{ stream_client, reset_source_splits, ResetSourceSplitsRequest, ResetSourceSplitsResponse }
2698            ,{ stream_client, inject_source_offsets, InjectSourceOffsetsRequest, InjectSourceOffsetsResponse }
2699            ,{ stream_client, get_fragment_by_id, GetFragmentByIdRequest, GetFragmentByIdResponse }
2700            ,{ stream_client, get_fragment_vnodes, GetFragmentVnodesRequest, GetFragmentVnodesResponse }
2701            ,{ stream_client, get_actor_vnodes, GetActorVnodesRequest, GetActorVnodesResponse }
2702            ,{ stream_client, set_sync_log_store_aligned, SetSyncLogStoreAlignedRequest, SetSyncLogStoreAlignedResponse }
2703            ,{ stream_client, refresh, RefreshRequest, RefreshResponse }
2704            ,{ stream_client, list_unmigrated_tables, ListUnmigratedTablesRequest, ListUnmigratedTablesResponse }
2705            ,{ ddl_client, create_table, CreateTableRequest, CreateTableResponse }
2706            ,{ ddl_client, alter_name, AlterNameRequest, AlterNameResponse }
2707            ,{ ddl_client, alter_owner, AlterOwnerRequest, AlterOwnerResponse }
2708            ,{ ddl_client, alter_subscription_retention, AlterSubscriptionRetentionRequest, AlterSubscriptionRetentionResponse }
2709            ,{ ddl_client, alter_set_schema, AlterSetSchemaRequest, AlterSetSchemaResponse }
2710            ,{ ddl_client, alter_parallelism, AlterParallelismRequest, AlterParallelismResponse }
2711            ,{ ddl_client, alter_backfill_parallelism, AlterBackfillParallelismRequest, AlterBackfillParallelismResponse }
2712            ,{ ddl_client, alter_streaming_job_config, AlterStreamingJobConfigRequest, AlterStreamingJobConfigResponse }
2713            ,{ ddl_client, alter_fragment_parallelism, AlterFragmentParallelismRequest, AlterFragmentParallelismResponse }
2714            ,{ ddl_client, alter_cdc_table_backfill_parallelism, AlterCdcTableBackfillParallelismRequest, AlterCdcTableBackfillParallelismResponse }
2715            ,{ ddl_client, alter_resource_group, AlterResourceGroupRequest, AlterResourceGroupResponse }
2716            ,{ ddl_client, alter_database_resource_group, AlterDatabaseResourceGroupRequest, AlterDatabaseResourceGroupResponse }
2717            ,{ ddl_client, alter_database_param, AlterDatabaseParamRequest, AlterDatabaseParamResponse }
2718            ,{ ddl_client, create_materialized_view, CreateMaterializedViewRequest, CreateMaterializedViewResponse }
2719            ,{ ddl_client, create_view, CreateViewRequest, CreateViewResponse }
2720            ,{ ddl_client, create_source, CreateSourceRequest, CreateSourceResponse }
2721            ,{ ddl_client, create_sink, CreateSinkRequest, CreateSinkResponse }
2722            ,{ ddl_client, create_subscription, CreateSubscriptionRequest, CreateSubscriptionResponse }
2723            ,{ ddl_client, create_schema, CreateSchemaRequest, CreateSchemaResponse }
2724            ,{ ddl_client, create_database, CreateDatabaseRequest, CreateDatabaseResponse }
2725            ,{ ddl_client, create_secret, CreateSecretRequest, CreateSecretResponse }
2726            ,{ ddl_client, create_index, CreateIndexRequest, CreateIndexResponse }
2727            ,{ ddl_client, create_function, CreateFunctionRequest, CreateFunctionResponse }
2728            ,{ ddl_client, drop_table, DropTableRequest, DropTableResponse }
2729            ,{ ddl_client, drop_materialized_view, DropMaterializedViewRequest, DropMaterializedViewResponse }
2730            ,{ ddl_client, drop_view, DropViewRequest, DropViewResponse }
2731            ,{ ddl_client, drop_source, DropSourceRequest, DropSourceResponse }
2732            ,{ ddl_client, reset_source, ResetSourceRequest, ResetSourceResponse }
2733            ,{ ddl_client, drop_secret, DropSecretRequest, DropSecretResponse}
2734            ,{ ddl_client, drop_sink, DropSinkRequest, DropSinkResponse }
2735            ,{ ddl_client, drop_subscription, DropSubscriptionRequest, DropSubscriptionResponse }
2736            ,{ ddl_client, drop_database, DropDatabaseRequest, DropDatabaseResponse }
2737            ,{ ddl_client, drop_schema, DropSchemaRequest, DropSchemaResponse }
2738            ,{ ddl_client, drop_index, DropIndexRequest, DropIndexResponse }
2739            ,{ ddl_client, drop_function, DropFunctionRequest, DropFunctionResponse }
2740            ,{ ddl_client, replace_job_plan, ReplaceJobPlanRequest, ReplaceJobPlanResponse }
2741            ,{ ddl_client, alter_source, AlterSourceRequest, AlterSourceResponse }
2742            ,{ ddl_client, risectl_list_state_tables, RisectlListStateTablesRequest, RisectlListStateTablesResponse }
2743            ,{ ddl_client, risectl_resume_backfill, RisectlResumeBackfillRequest, RisectlResumeBackfillResponse }
2744            ,{ ddl_client, get_ddl_progress, GetDdlProgressRequest, GetDdlProgressResponse }
2745            ,{ ddl_client, create_connection, CreateConnectionRequest, CreateConnectionResponse }
2746            ,{ ddl_client, list_connections, ListConnectionsRequest, ListConnectionsResponse }
2747            ,{ ddl_client, drop_connection, DropConnectionRequest, DropConnectionResponse }
2748            ,{ ddl_client, comment_on, CommentOnRequest, CommentOnResponse }
2749            ,{ ddl_client, get_tables, GetTablesRequest, GetTablesResponse }
2750            ,{ ddl_client, wait, WaitRequest, WaitResponse }
2751            ,{ ddl_client, auto_schema_change, AutoSchemaChangeRequest, AutoSchemaChangeResponse }
2752            ,{ ddl_client, alter_swap_rename, AlterSwapRenameRequest, AlterSwapRenameResponse }
2753            ,{ ddl_client, alter_secret, AlterSecretRequest, AlterSecretResponse }
2754            ,{ ddl_client, compact_iceberg_table, CompactIcebergTableRequest, CompactIcebergTableResponse }
2755            ,{ ddl_client, expire_iceberg_table_snapshots, ExpireIcebergTableSnapshotsRequest, ExpireIcebergTableSnapshotsResponse }
2756            ,{ ddl_client, create_iceberg_table, CreateIcebergTableRequest, CreateIcebergTableResponse }
2757            ,{ hummock_client, unpin_version_before, UnpinVersionBeforeRequest, UnpinVersionBeforeResponse }
2758            ,{ hummock_client, get_current_version, GetCurrentVersionRequest, GetCurrentVersionResponse }
2759            ,{ hummock_client, replay_version_delta, ReplayVersionDeltaRequest, ReplayVersionDeltaResponse }
2760            ,{ hummock_client, list_version_deltas, ListVersionDeltasRequest, ListVersionDeltasResponse }
2761            ,{ hummock_client, get_assigned_compact_task_num, GetAssignedCompactTaskNumRequest, GetAssignedCompactTaskNumResponse }
2762            ,{ hummock_client, trigger_compaction_deterministic, TriggerCompactionDeterministicRequest, TriggerCompactionDeterministicResponse }
2763            ,{ hummock_client, disable_commit_epoch, DisableCommitEpochRequest, DisableCommitEpochResponse }
2764            ,{ hummock_client, get_new_object_ids, GetNewObjectIdsRequest, GetNewObjectIdsResponse }
2765            ,{ hummock_client, trigger_manual_compaction, TriggerManualCompactionRequest, TriggerManualCompactionResponse }
2766            ,{ hummock_client, trigger_full_gc, TriggerFullGcRequest, TriggerFullGcResponse }
2767            ,{ hummock_client, rise_ctl_get_pinned_versions_summary, RiseCtlGetPinnedVersionsSummaryRequest, RiseCtlGetPinnedVersionsSummaryResponse }
2768            ,{ hummock_client, rise_ctl_list_compaction_group, RiseCtlListCompactionGroupRequest, RiseCtlListCompactionGroupResponse }
2769            ,{ hummock_client, rise_ctl_update_compaction_config, RiseCtlUpdateCompactionConfigRequest, RiseCtlUpdateCompactionConfigResponse }
2770            ,{ hummock_client, rise_ctl_get_checkpoint_version, RiseCtlGetCheckpointVersionRequest, RiseCtlGetCheckpointVersionResponse }
2771            ,{ hummock_client, rise_ctl_pause_version_checkpoint, RiseCtlPauseVersionCheckpointRequest, RiseCtlPauseVersionCheckpointResponse }
2772            ,{ hummock_client, rise_ctl_resume_version_checkpoint, RiseCtlResumeVersionCheckpointRequest, RiseCtlResumeVersionCheckpointResponse }
2773            ,{ hummock_client, init_metadata_for_replay, InitMetadataForReplayRequest, InitMetadataForReplayResponse }
2774            ,{ hummock_client, split_compaction_group, SplitCompactionGroupRequest, SplitCompactionGroupResponse }
2775            ,{ hummock_client, rise_ctl_list_compaction_status, RiseCtlListCompactionStatusRequest, RiseCtlListCompactionStatusResponse }
2776            ,{ hummock_client, get_compaction_score, GetCompactionScoreRequest, GetCompactionScoreResponse }
2777            ,{ hummock_client, rise_ctl_rebuild_table_stats, RiseCtlRebuildTableStatsRequest, RiseCtlRebuildTableStatsResponse }
2778            ,{ hummock_client, subscribe_compaction_event, impl tonic::IntoStreamingRequest<Message = SubscribeCompactionEventRequest>, Streaming<SubscribeCompactionEventResponse> }
2779            ,{ hummock_client, subscribe_iceberg_compaction_event, impl tonic::IntoStreamingRequest<Message = SubscribeIcebergCompactionEventRequest>, Streaming<SubscribeIcebergCompactionEventResponse> }
2780            ,{ hummock_client, list_branched_object, ListBranchedObjectRequest, ListBranchedObjectResponse }
2781            ,{ hummock_client, list_active_write_limit, ListActiveWriteLimitRequest, ListActiveWriteLimitResponse }
2782            ,{ hummock_client, list_hummock_meta_config, ListHummockMetaConfigRequest, ListHummockMetaConfigResponse }
2783            ,{ hummock_client, list_compact_task_assignment, ListCompactTaskAssignmentRequest, ListCompactTaskAssignmentResponse }
2784            ,{ hummock_client, list_compact_task_progress, ListCompactTaskProgressRequest, ListCompactTaskProgressResponse }
2785            ,{ hummock_client, cancel_compact_task, CancelCompactTaskRequest, CancelCompactTaskResponse}
2786            ,{ hummock_client, get_version_by_epoch, GetVersionByEpochRequest, GetVersionByEpochResponse }
2787            ,{ hummock_client, merge_compaction_group, MergeCompactionGroupRequest, MergeCompactionGroupResponse }
2788            ,{ hummock_client, get_table_change_logs, GetTableChangeLogsRequest, GetTableChangeLogsResponse }
2789            ,{ user_client, create_user, CreateUserRequest, CreateUserResponse }
2790            ,{ user_client, update_user, UpdateUserRequest, UpdateUserResponse }
2791            ,{ user_client, drop_user, DropUserRequest, DropUserResponse }
2792            ,{ user_client, grant_privilege, GrantPrivilegeRequest, GrantPrivilegeResponse }
2793            ,{ user_client, revoke_privilege, RevokePrivilegeRequest, RevokePrivilegeResponse }
2794            ,{ user_client, alter_default_privilege, AlterDefaultPrivilegeRequest, AlterDefaultPrivilegeResponse }
2795            ,{ scale_client, get_cluster_info, GetClusterInfoRequest, GetClusterInfoResponse }
2796            ,{ scale_client, reschedule, RescheduleRequest, RescheduleResponse }
2797            ,{ notification_client, subscribe, SubscribeRequest, Streaming<SubscribeResponse> }
2798            ,{ backup_client, backup_meta, BackupMetaRequest, BackupMetaResponse }
2799            ,{ backup_client, get_backup_job_status, GetBackupJobStatusRequest, GetBackupJobStatusResponse }
2800            ,{ backup_client, delete_meta_snapshot, DeleteMetaSnapshotRequest, DeleteMetaSnapshotResponse}
2801            ,{ backup_client, get_meta_snapshot_manifest, GetMetaSnapshotManifestRequest, GetMetaSnapshotManifestResponse}
2802            ,{ telemetry_client, get_telemetry_info, GetTelemetryInfoRequest, TelemetryInfoResponse}
2803            ,{ system_params_client, get_system_params, GetSystemParamsRequest, GetSystemParamsResponse }
2804            ,{ system_params_client, set_system_param, SetSystemParamRequest, SetSystemParamResponse }
2805            ,{ session_params_client, get_session_params, GetSessionParamsRequest, GetSessionParamsResponse }
2806            ,{ session_params_client, set_session_param, SetSessionParamRequest, SetSessionParamResponse }
2807            ,{ serving_client, get_serving_vnode_mappings, GetServingVnodeMappingsRequest, GetServingVnodeMappingsResponse }
2808            ,{ cloud_client, rw_cloud_validate_source, RwCloudValidateSourceRequest, RwCloudValidateSourceResponse }
2809            ,{ event_log_client, list_event_log, ListEventLogRequest, ListEventLogResponse }
2810            ,{ event_log_client, add_event_log, AddEventLogRequest, AddEventLogResponse }
2811            ,{ cluster_limit_client, get_cluster_limits, GetClusterLimitsRequest, GetClusterLimitsResponse }
2812            ,{ hosted_iceberg_catalog_service_client, list_iceberg_tables, ListIcebergTablesRequest, ListIcebergTablesResponse }
2813            ,{ monitor_client, stack_trace, StackTraceRequest, StackTraceResponse }
2814        }
2815    };
2816}
2817
2818impl GrpcMetaClient {
2819    async fn refresh_client_if_needed(&self, code: Code) {
2820        if matches!(
2821            code,
2822            Code::Unknown | Code::Unimplemented | Code::Unavailable
2823        ) {
2824            tracing::debug!("matching tonic code {}", code);
2825            let (result_sender, result_receiver) = oneshot::channel();
2826            if self
2827                .member_monitor_event_sender
2828                .try_send(result_sender)
2829                .is_ok()
2830            {
2831                if let Ok(Err(e)) = result_receiver.await {
2832                    tracing::warn!(error = %e.as_report(), "force refresh meta client failed");
2833                }
2834            } else {
2835                tracing::debug!("skipping the current refresh, somewhere else is already doing it")
2836            }
2837        }
2838    }
2839}
2840
2841impl GrpcMetaClient {
2842    for_all_meta_rpc! { meta_rpc_client_method_impl }
2843}