Skip to main content

meta_client/
client.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15mod ask_leader;
16mod cluster;
17mod config;
18pub mod heartbeat;
19mod load_balance;
20mod procedure;
21mod store;
22mod util;
23
24use std::fmt::Debug;
25use std::sync::Arc;
26use std::time::Duration;
27
28use api::v1::meta::heartbeat_request::NodeWorkloads;
29use api::v1::meta::{
30    MetasrvNodeInfo, ProcedureDetailResponse, ReconcileRequest, ReconcileResponse, Role,
31};
32pub use ask_leader::{AskLeader, LeaderProvider, LeaderProviderRef};
33use cluster::Client as ClusterClient;
34pub use cluster::ClusterKvBackend;
35use common_error::ext::BoxedError;
36use common_grpc::channel_manager::{ChannelConfig, ChannelManager};
37use common_meta::cluster::{
38    ClusterInfo, MetasrvStatus, NodeInfo, NodeInfoKey, NodeStatus, Role as ClusterRole,
39};
40use common_meta::datanode::{DatanodeStatKey, DatanodeStatValue, RegionStat};
41use common_meta::distributed_time_constants::default_distributed_time_constants;
42use common_meta::error::{
43    self as meta_error, ExternalSnafu, Result as MetaResult, UnsupportedSnafu,
44};
45use common_meta::key::flow::flow_state::{FlowStat, FlowStateManager};
46use common_meta::kv_backend::KvBackendRef;
47use common_meta::peer::PeerDiscovery;
48use common_meta::procedure_executor::{ExecutorContext, ProcedureExecutor};
49use common_meta::range_stream::PaginationStream;
50use common_meta::rpc::KeyValue;
51use common_meta::rpc::ddl::{
52    CREATE_DATABASE_CREATOR_EXTENSION_KEY, CreateDatabaseTask, DdlTask, SubmitDdlTaskRequest,
53    SubmitDdlTaskResponse,
54};
55use common_meta::rpc::procedure::{
56    AddRegionFollowerRequest, AddTableFollowerRequest, GcRegionsRequest, GcResponse,
57    GcTableRequest, ManageRegionFollowerRequest, MigrateRegionRequest, MigrateRegionResponse,
58    ProcedureStateResponse, RemoveRegionFollowerRequest, RemoveTableFollowerRequest,
59};
60use common_meta::rpc::store::{
61    BatchDeleteRequest, BatchDeleteResponse, BatchGetRequest, BatchGetResponse, BatchPutRequest,
62    BatchPutResponse, CompareAndPutRequest, CompareAndPutResponse, DeleteRangeRequest,
63    DeleteRangeResponse, PutRequest, PutResponse, RangeRequest, RangeResponse,
64};
65use common_options::plugin_options::PluginOptionsDeserializer;
66use common_telemetry::info;
67use common_time::util::DefaultSystemTimer;
68use config::Client as ConfigClient;
69use futures::TryStreamExt;
70use heartbeat::{Client as HeartbeatClient, HeartbeatConfig};
71use procedure::Client as ProcedureClient;
72pub use procedure::{procedure_actor, procedure_event_context};
73use serde::de::DeserializeOwned;
74use snafu::{OptionExt, ResultExt};
75use store::Client as StoreClient;
76
77pub use self::heartbeat::{HeartbeatSender, HeartbeatStream};
78use crate::client::ask_leader::{LeaderProviderFactoryImpl, LeaderProviderFactoryRef};
79use crate::error::{
80    ConvertMetaConfigSnafu, ConvertMetaRequestSnafu, ConvertMetaResponseSnafu, Error,
81    GetFlowStatSnafu, MissingQueryContextSnafu, NotStartedSnafu, Result,
82};
83
84pub type Id = u64;
85
86const DEFAULT_ASK_LEADER_MAX_RETRY: usize = 3;
87const DEFAULT_SUBMIT_DDL_MAX_RETRY: usize = 3;
88const DEFAULT_CLUSTER_CLIENT_MAX_RETRY: usize = 3;
89const DEFAULT_DDL_TIMEOUT: Duration = Duration::from_secs(10);
90
91#[derive(Clone, Debug, Default)]
92pub struct MetaClientBuilder {
93    id: Id,
94    role: Role,
95    enable_heartbeat: bool,
96    enable_store: bool,
97    #[cfg(test)]
98    enable_direct_store_writes: bool,
99    enable_procedure: bool,
100    enable_access_cluster_info: bool,
101    region_follower: Option<RegionFollowerClientRef>,
102    channel_manager: Option<ChannelManager>,
103    ddl_channel_manager: Option<ChannelManager>,
104    /// The default ddl timeout for each request.
105    ddl_timeout: Option<Duration>,
106    heartbeat_channel_manager: Option<ChannelManager>,
107}
108
109impl MetaClientBuilder {
110    pub fn new(member_id: u64, role: Role) -> Self {
111        Self {
112            id: member_id,
113            role,
114            ..Default::default()
115        }
116    }
117
118    /// Returns the role of Frontend's default options.
119    pub fn frontend_default_options() -> Self {
120        // Frontend does not need a member id.
121        Self::new(0, Role::Frontend)
122            .enable_store()
123            .enable_heartbeat()
124            .enable_procedure()
125            .enable_access_cluster_info()
126    }
127
128    /// Returns the role of Datanode's default options.
129    pub fn datanode_default_options(member_id: u64) -> Self {
130        Self::new(member_id, Role::Datanode)
131            .enable_store()
132            .enable_heartbeat()
133    }
134
135    /// Returns the role of Flownode's default options.
136    pub fn flownode_default_options(member_id: u64) -> Self {
137        Self::new(member_id, Role::Flownode)
138            .enable_store()
139            .enable_heartbeat()
140            .enable_procedure()
141            .enable_access_cluster_info()
142    }
143
144    pub fn enable_heartbeat(self) -> Self {
145        Self {
146            enable_heartbeat: true,
147            ..self
148        }
149    }
150
151    /// Enables the Store client in read-only mode.
152    ///
153    /// Store write methods fail fast by default. Metadata writes from production
154    /// frontend/datanode/flownode clients should go through metasrv procedures.
155    pub fn enable_store(self) -> Self {
156        Self {
157            enable_store: true,
158            ..self
159        }
160    }
161
162    /// Enables direct Store write RPCs for tests.
163    ///
164    /// Production metadata writes should use metasrv-owned write paths instead.
165    #[cfg(test)]
166    pub(super) fn enable_direct_store_writes_for_test(self) -> Self {
167        Self {
168            enable_store: true,
169            enable_direct_store_writes: true,
170            ..self
171        }
172    }
173
174    pub fn enable_procedure(self) -> Self {
175        Self {
176            enable_procedure: true,
177            ..self
178        }
179    }
180
181    pub fn enable_access_cluster_info(self) -> Self {
182        Self {
183            enable_access_cluster_info: true,
184            ..self
185        }
186    }
187
188    pub fn channel_manager(self, channel_manager: ChannelManager) -> Self {
189        Self {
190            channel_manager: Some(channel_manager),
191            ..self
192        }
193    }
194
195    pub fn ddl_channel_manager(self, channel_manager: ChannelManager) -> Self {
196        Self {
197            ddl_channel_manager: Some(channel_manager),
198            ..self
199        }
200    }
201
202    pub fn ddl_timeout(self, timeout: Duration) -> Self {
203        Self {
204            ddl_timeout: Some(timeout),
205            ..self
206        }
207    }
208
209    pub fn heartbeat_channel_manager(self, channel_manager: ChannelManager) -> Self {
210        Self {
211            heartbeat_channel_manager: Some(channel_manager),
212            ..self
213        }
214    }
215
216    pub fn with_region_follower(self, region_follower: RegionFollowerClientRef) -> Self {
217        Self {
218            region_follower: Some(region_follower),
219            ..self
220        }
221    }
222
223    pub fn build(self) -> MetaClient {
224        let mgr = self.channel_manager.unwrap_or_default();
225        let heartbeat_channel_manager = self
226            .heartbeat_channel_manager
227            .clone()
228            .unwrap_or_else(|| mgr.clone());
229
230        let heartbeat = self.enable_heartbeat.then(|| {
231            if self.heartbeat_channel_manager.is_some() {
232                info!("Enable heartbeat channel using the heartbeat channel manager.");
233            }
234
235            HeartbeatClient::new(self.id, self.role, heartbeat_channel_manager.clone())
236        });
237        let config = self
238            .enable_heartbeat
239            .then(|| ConfigClient::new(self.id, self.role, mgr.clone()));
240        let store = self.enable_store.then(|| {
241            #[cfg(test)]
242            {
243                if self.enable_direct_store_writes {
244                    return StoreClient::new_writable(self.id, self.role, mgr.clone());
245                }
246            }
247
248            StoreClient::new(self.id, self.role, mgr.clone())
249        });
250        let procedure = self.enable_procedure.then(|| {
251            let mgr = self.ddl_channel_manager.unwrap_or(mgr.clone());
252            ProcedureClient::new(
253                self.id,
254                self.role,
255                mgr,
256                DEFAULT_SUBMIT_DDL_MAX_RETRY,
257                self.ddl_timeout.unwrap_or(DEFAULT_DDL_TIMEOUT),
258            )
259        });
260        let cluster = self
261            .enable_access_cluster_info
262            .then(|| ClusterClient::new(mgr.clone(), DEFAULT_CLUSTER_CLIENT_MAX_RETRY));
263        let region_follower = self.region_follower.clone();
264
265        MetaClient {
266            id: self.id,
267            channel_manager: mgr.clone(),
268            leader_provider_factory: Arc::new(LeaderProviderFactoryImpl::new(
269                self.id,
270                self.role,
271                DEFAULT_ASK_LEADER_MAX_RETRY,
272                heartbeat_channel_manager,
273            )),
274            heartbeat,
275            config,
276            store,
277            procedure,
278            cluster,
279            region_follower,
280        }
281    }
282}
283
284#[derive(Debug)]
285pub struct MetaClient {
286    id: Id,
287    channel_manager: ChannelManager,
288    leader_provider_factory: LeaderProviderFactoryRef,
289    heartbeat: Option<HeartbeatClient>,
290    config: Option<ConfigClient>,
291    store: Option<StoreClient>,
292    procedure: Option<ProcedureClient>,
293    cluster: Option<ClusterClient>,
294    region_follower: Option<RegionFollowerClientRef>,
295}
296
297impl MetaClient {
298    pub fn new(id: Id, role: Role) -> Self {
299        Self {
300            id,
301            channel_manager: ChannelManager::default(),
302            leader_provider_factory: Arc::new(LeaderProviderFactoryImpl::new(
303                id,
304                role,
305                DEFAULT_ASK_LEADER_MAX_RETRY,
306                ChannelManager::default(),
307            )),
308            heartbeat: None,
309            config: None,
310            store: None,
311            procedure: None,
312            cluster: None,
313            region_follower: None,
314        }
315    }
316}
317
318pub type RegionFollowerClientRef = Arc<dyn RegionFollowerClient>;
319
320/// A trait for clients that can manage region followers.
321///
322/// The executor context carries the actor and the event input of the
323/// submission, so implementations can forward them to the metasrv and the
324/// region follower procedures record who submitted the operation.
325#[async_trait::async_trait]
326pub trait RegionFollowerClient: Sync + Send + Debug {
327    async fn add_region_follower(
328        &self,
329        ctx: &ExecutorContext,
330        request: AddRegionFollowerRequest,
331    ) -> Result<()>;
332
333    async fn remove_region_follower(
334        &self,
335        ctx: &ExecutorContext,
336        request: RemoveRegionFollowerRequest,
337    ) -> Result<()>;
338
339    async fn add_table_follower(
340        &self,
341        ctx: &ExecutorContext,
342        request: AddTableFollowerRequest,
343    ) -> Result<()>;
344
345    async fn remove_table_follower(
346        &self,
347        ctx: &ExecutorContext,
348        request: RemoveTableFollowerRequest,
349    ) -> Result<()>;
350
351    async fn start(&self, urls: &[&str]) -> Result<()>;
352
353    async fn start_with(&self, leader_provider: LeaderProviderRef) -> Result<()>;
354}
355
356#[async_trait::async_trait]
357impl ProcedureExecutor for MetaClient {
358    async fn submit_ddl_task(
359        &self,
360        ctx: ExecutorContext,
361        request: SubmitDdlTaskRequest,
362    ) -> MetaResult<SubmitDdlTaskResponse> {
363        MetaClient::submit_ddl_task(self, ctx, request)
364            .await
365            .map_err(BoxedError::new)
366            .context(meta_error::ExternalSnafu)
367    }
368
369    async fn migrate_region(
370        &self,
371        ctx: &ExecutorContext,
372        request: MigrateRegionRequest,
373    ) -> MetaResult<MigrateRegionResponse> {
374        self.migrate_region(ctx, request)
375            .await
376            .map_err(BoxedError::new)
377            .context(meta_error::ExternalSnafu)
378    }
379
380    async fn reconcile(
381        &self,
382        _ctx: &ExecutorContext,
383        request: ReconcileRequest,
384    ) -> MetaResult<ReconcileResponse> {
385        self.reconcile(request)
386            .await
387            .map_err(BoxedError::new)
388            .context(meta_error::ExternalSnafu)
389    }
390
391    async fn manage_region_follower(
392        &self,
393        ctx: &ExecutorContext,
394        request: ManageRegionFollowerRequest,
395    ) -> MetaResult<()> {
396        if let Some(region_follower) = &self.region_follower {
397            match request {
398                ManageRegionFollowerRequest::AddRegionFollower(add_region_follower_request) => {
399                    region_follower
400                        .add_region_follower(ctx, add_region_follower_request)
401                        .await
402                }
403                ManageRegionFollowerRequest::RemoveRegionFollower(
404                    remove_region_follower_request,
405                ) => {
406                    region_follower
407                        .remove_region_follower(ctx, remove_region_follower_request)
408                        .await
409                }
410                ManageRegionFollowerRequest::AddTableFollower(add_table_follower_request) => {
411                    region_follower
412                        .add_table_follower(ctx, add_table_follower_request)
413                        .await
414                }
415                ManageRegionFollowerRequest::RemoveTableFollower(remove_table_follower_request) => {
416                    region_follower
417                        .remove_table_follower(ctx, remove_table_follower_request)
418                        .await
419                }
420            }
421            .map_err(BoxedError::new)
422            .context(meta_error::ExternalSnafu)
423        } else {
424            UnsupportedSnafu {
425                operation: "manage_region_follower",
426            }
427            .fail()
428        }
429    }
430
431    async fn query_procedure_state(
432        &self,
433        _ctx: &ExecutorContext,
434        pid: &str,
435    ) -> MetaResult<ProcedureStateResponse> {
436        self.query_procedure_state(pid)
437            .await
438            .map_err(BoxedError::new)
439            .context(meta_error::ExternalSnafu)
440    }
441
442    async fn gc_regions(
443        &self,
444        ctx: &ExecutorContext,
445        request: GcRegionsRequest,
446    ) -> MetaResult<GcResponse> {
447        self.gc_regions(ctx, request)
448            .await
449            .map_err(BoxedError::new)
450            .context(meta_error::ExternalSnafu)
451    }
452
453    async fn gc_table(
454        &self,
455        ctx: &ExecutorContext,
456        request: GcTableRequest,
457    ) -> MetaResult<GcResponse> {
458        self.gc_table(ctx, request)
459            .await
460            .map_err(BoxedError::new)
461            .context(meta_error::ExternalSnafu)
462    }
463
464    async fn list_procedures(&self, _ctx: &ExecutorContext) -> MetaResult<ProcedureDetailResponse> {
465        self.procedure_client()
466            .map_err(BoxedError::new)
467            .context(meta_error::ExternalSnafu)?
468            .list_procedures()
469            .await
470            .map_err(BoxedError::new)
471            .context(meta_error::ExternalSnafu)
472    }
473}
474
475// TODO(zyy17): Allow deprecated fields for backward compatibility. Remove this when the deprecated fields are removed from the proto.
476#[allow(deprecated)]
477#[async_trait::async_trait]
478impl ClusterInfo for MetaClient {
479    type Error = Error;
480
481    async fn list_nodes(&self, role: Option<ClusterRole>) -> Result<Vec<NodeInfo>> {
482        let cluster_client = self.cluster_client()?;
483
484        let (get_metasrv_nodes, nodes_key_prefix) = match role {
485            None => (true, Some(NodeInfoKey::key_prefix())),
486            Some(ClusterRole::Metasrv) => (true, None),
487            Some(role) => (false, Some(NodeInfoKey::key_prefix_with_role(role))),
488        };
489
490        let mut nodes = if get_metasrv_nodes {
491            let last_activity_ts = -1; // Metasrv does not provide this information.
492
493            let (leader, followers): (Option<MetasrvNodeInfo>, Vec<MetasrvNodeInfo>) =
494                cluster_client.get_metasrv_peers().await?;
495            followers
496                .into_iter()
497                .map(|node| {
498                    if let Some(node_info) = node.info {
499                        NodeInfo {
500                            peer: node.peer.unwrap_or_default(),
501                            last_activity_ts,
502                            status: NodeStatus::Metasrv(MetasrvStatus { is_leader: false }),
503                            version: node_info.version,
504                            git_commit: node_info.git_commit,
505                            start_time_ms: node_info.start_time_ms,
506                            total_cpu_millicores: node_info.total_cpu_millicores,
507                            total_memory_bytes: node_info.total_memory_bytes,
508                            cpu_usage_millicores: node_info.cpu_usage_millicores,
509                            memory_usage_bytes: node_info.memory_usage_bytes,
510                            hostname: node_info.hostname,
511                            env_vars: Default::default(),
512                            schedulable: None,
513                        }
514                    } else {
515                        // TODO(zyy17): It's for backward compatibility. Remove this when the deprecated fields are removed from the proto.
516                        NodeInfo {
517                            peer: node.peer.unwrap_or_default(),
518                            last_activity_ts,
519                            status: NodeStatus::Metasrv(MetasrvStatus { is_leader: false }),
520                            version: node.version,
521                            git_commit: node.git_commit,
522                            start_time_ms: node.start_time_ms,
523                            total_cpu_millicores: node.cpus as i64,
524                            total_memory_bytes: node.memory_bytes as i64,
525                            cpu_usage_millicores: 0,
526                            memory_usage_bytes: 0,
527                            hostname: "".to_string(),
528                            env_vars: Default::default(),
529                            schedulable: None,
530                        }
531                    }
532                })
533                .chain(leader.into_iter().map(|node| {
534                    if let Some(node_info) = node.info {
535                        NodeInfo {
536                            peer: node.peer.unwrap_or_default(),
537                            last_activity_ts,
538                            status: NodeStatus::Metasrv(MetasrvStatus { is_leader: true }),
539                            version: node_info.version,
540                            git_commit: node_info.git_commit,
541                            start_time_ms: node_info.start_time_ms,
542                            total_cpu_millicores: node_info.total_cpu_millicores,
543                            total_memory_bytes: node_info.total_memory_bytes,
544                            cpu_usage_millicores: node_info.cpu_usage_millicores,
545                            memory_usage_bytes: node_info.memory_usage_bytes,
546                            hostname: node_info.hostname,
547                            env_vars: Default::default(),
548                            schedulable: None,
549                        }
550                    } else {
551                        // TODO(zyy17): It's for backward compatibility. Remove this when the deprecated fields are removed from the proto.
552                        NodeInfo {
553                            peer: node.peer.unwrap_or_default(),
554                            last_activity_ts,
555                            status: NodeStatus::Metasrv(MetasrvStatus { is_leader: true }),
556                            version: node.version,
557                            git_commit: node.git_commit,
558                            start_time_ms: node.start_time_ms,
559                            total_cpu_millicores: node.cpus as i64,
560                            total_memory_bytes: node.memory_bytes as i64,
561                            cpu_usage_millicores: 0,
562                            memory_usage_bytes: 0,
563                            hostname: "".to_string(),
564                            env_vars: Default::default(),
565                            schedulable: None,
566                        }
567                    }
568                }))
569                .collect::<Vec<_>>()
570        } else {
571            Vec::new()
572        };
573
574        if let Some(prefix) = nodes_key_prefix {
575            let req = RangeRequest::new().with_prefix(prefix);
576            let res = cluster_client.range(req).await?;
577            for kv in res.kvs {
578                nodes.push(NodeInfo::try_from(kv.value).context(ConvertMetaResponseSnafu)?);
579            }
580        }
581
582        Ok(nodes)
583    }
584
585    async fn list_region_stats(&self) -> Result<Vec<RegionStat>> {
586        let cluster_kv_backend = Arc::new(self.cluster_client()?);
587        let range_prefix = DatanodeStatKey::prefix_key();
588        let req = RangeRequest::new().with_prefix(range_prefix);
589        let stream =
590            PaginationStream::new(cluster_kv_backend, req, 256, decode_stats).into_stream();
591        let mut datanode_stats = stream
592            .try_collect::<Vec<_>>()
593            .await
594            .context(ConvertMetaResponseSnafu)?;
595        let region_stats = datanode_stats
596            .iter_mut()
597            .flat_map(|datanode_stat| {
598                let last = datanode_stat.stats.pop();
599                last.map(|stat| stat.region_stats).unwrap_or_default()
600            })
601            .collect::<Vec<_>>();
602
603        Ok(region_stats)
604    }
605
606    async fn list_flow_stats(&self) -> Result<Option<FlowStat>> {
607        let cluster_backend = ClusterKvBackend::new(Arc::new(self.cluster_client()?));
608        let cluster_backend = Arc::new(cluster_backend) as KvBackendRef;
609        let flow_state_manager = FlowStateManager::new(cluster_backend);
610        let res = flow_state_manager.get().await.context(GetFlowStatSnafu)?;
611
612        Ok(res.map(|r| r.into()))
613    }
614}
615
616// TODO(weny): the discovery using client side timestamp may be inaccurate,
617// maybe we need to use the timestamp from metasrv in the future.
618#[async_trait::async_trait]
619impl PeerDiscovery for MetaClient {
620    async fn active_frontends(&self) -> MetaResult<Vec<NodeInfo>> {
621        let nodes = self
622            .list_nodes(Some(ClusterRole::Frontend))
623            .await
624            .map_err(BoxedError::new)
625            .context(ExternalSnafu)?;
626        Ok(util::alive_frontends(
627            &DefaultSystemTimer,
628            nodes,
629            // TODO(weny): the heartbeat interval should be received from metasrv
630            // instead of using the default value.
631            default_distributed_time_constants().frontend_heartbeat_interval,
632        ))
633    }
634
635    async fn active_datanodes(
636        &self,
637        filter: Option<for<'a> fn(&'a NodeWorkloads) -> bool>,
638    ) -> MetaResult<Vec<NodeInfo>> {
639        let nodes = self
640            .list_nodes(Some(ClusterRole::Datanode))
641            .await
642            .map_err(BoxedError::new)
643            .context(ExternalSnafu)?;
644        Ok(util::alive_datanodes(
645            &DefaultSystemTimer,
646            nodes,
647            default_distributed_time_constants().datanode_lease,
648            filter,
649        ))
650    }
651
652    async fn active_flownodes(
653        &self,
654        filter: Option<for<'a> fn(&'a NodeWorkloads) -> bool>,
655    ) -> MetaResult<Vec<NodeInfo>> {
656        let nodes = self
657            .list_nodes(Some(ClusterRole::Flownode))
658            .await
659            .map_err(BoxedError::new)
660            .context(ExternalSnafu)?;
661        Ok(util::alive_flownodes(
662            &DefaultSystemTimer,
663            nodes,
664            default_distributed_time_constants().flownode_lease,
665            filter,
666        ))
667    }
668}
669
670fn decode_stats(kv: KeyValue) -> MetaResult<DatanodeStatValue> {
671    DatanodeStatValue::try_from(kv.value)
672        .map_err(BoxedError::new)
673        .context(ExternalSnafu)
674}
675
676impl MetaClient {
677    pub async fn start<U, A>(&mut self, urls: A) -> Result<()>
678    where
679        U: AsRef<str>,
680        A: AsRef<[U]> + Clone,
681    {
682        info!("MetaClient channel config: {:?}", self.channel_config());
683
684        let urls = urls.as_ref().iter().map(|u| u.as_ref()).collect::<Vec<_>>();
685        let leader_provider = self.leader_provider_factory.create(&urls);
686
687        self.start_with(leader_provider, urls).await
688    }
689
690    /// Start the client with a [LeaderProvider] and other Metasrv peers' addresses.
691    pub(crate) async fn start_with<U, A>(
692        &mut self,
693        leader_provider: LeaderProviderRef,
694        peers: A,
695    ) -> Result<()>
696    where
697        U: AsRef<str>,
698        A: AsRef<[U]> + Clone,
699    {
700        if let Some(client) = &self.region_follower {
701            info!("Starting region follower client ...");
702            client.start_with(leader_provider.clone()).await?;
703        }
704
705        if let Some(client) = &self.heartbeat {
706            info!("Starting heartbeat client ...");
707            client.start_with(leader_provider.clone()).await?;
708        }
709
710        if let Some(client) = &self.config {
711            info!("Starting config client ...");
712            client.start_with(leader_provider.clone()).await?;
713        }
714
715        if let Some(client) = &mut self.store {
716            info!("Starting store client ...");
717            client.start(peers.clone()).await?;
718        }
719
720        if let Some(client) = &self.procedure {
721            info!("Starting procedure client ...");
722            client.start_with(leader_provider.clone()).await?;
723        }
724
725        if let Some(client) = &mut self.cluster {
726            info!("Starting cluster client ...");
727            client.start_with(leader_provider).await?;
728        }
729        Ok(())
730    }
731
732    /// Ask the leader address of `metasrv`, and the heartbeat component
733    /// needs to create a bidirectional streaming to the leader.
734    pub async fn ask_leader(&self) -> Result<String> {
735        self.heartbeat_client()?.ask_leader().await
736    }
737
738    pub async fn pull_config<T, U>(&self, deserializer: T) -> Result<U>
739    where
740        T: PluginOptionsDeserializer<U>,
741        U: DeserializeOwned,
742    {
743        let res = self.config_client()?.pull_config().await?;
744        let v = deserializer
745            .deserialize(&res.payload)
746            .context(ConvertMetaConfigSnafu)?;
747        Ok(v)
748    }
749
750    /// Returns a heartbeat bidirectional streaming: (sender, receiver), the
751    /// other end is the leader of `metasrv`.
752    ///
753    /// The `datanode` needs to use the sender to continuously send heartbeat
754    /// packets (some self-state data), and the receiver can receive a response
755    /// from "metasrv" (which may contain some scheduling instructions).
756    ///
757    /// Returns the heartbeat sender, stream, and configuration received from Metasrv.
758    pub async fn heartbeat(&self) -> Result<(HeartbeatSender, HeartbeatStream, HeartbeatConfig)> {
759        self.heartbeat_client()?.heartbeat().await
760    }
761
762    /// Range gets the keys in the range from the key-value store.
763    pub async fn range(&self, req: RangeRequest) -> Result<RangeResponse> {
764        self.store_client()?
765            .range(req.into())
766            .await?
767            .try_into()
768            .context(ConvertMetaResponseSnafu)
769    }
770
771    /// Put puts the given key into the key-value store.
772    pub async fn put(&self, req: PutRequest) -> Result<PutResponse> {
773        self.store_client()?
774            .put(req.into())
775            .await?
776            .try_into()
777            .context(ConvertMetaResponseSnafu)
778    }
779
780    /// BatchGet atomically get values by the given keys from the key-value store.
781    pub async fn batch_get(&self, req: BatchGetRequest) -> Result<BatchGetResponse> {
782        self.store_client()?
783            .batch_get(req.into())
784            .await?
785            .try_into()
786            .context(ConvertMetaResponseSnafu)
787    }
788
789    /// BatchPut atomically puts the given keys into the key-value store.
790    pub async fn batch_put(&self, req: BatchPutRequest) -> Result<BatchPutResponse> {
791        self.store_client()?
792            .batch_put(req.into())
793            .await?
794            .try_into()
795            .context(ConvertMetaResponseSnafu)
796    }
797
798    /// BatchDelete atomically deletes the given keys from the key-value store.
799    pub async fn batch_delete(&self, req: BatchDeleteRequest) -> Result<BatchDeleteResponse> {
800        self.store_client()?
801            .batch_delete(req.into())
802            .await?
803            .try_into()
804            .context(ConvertMetaResponseSnafu)
805    }
806
807    /// CompareAndPut atomically puts the value to the given updated
808    /// value if the current value == the expected value.
809    pub async fn compare_and_put(
810        &self,
811        req: CompareAndPutRequest,
812    ) -> Result<CompareAndPutResponse> {
813        self.store_client()?
814            .compare_and_put(req.into())
815            .await?
816            .try_into()
817            .context(ConvertMetaResponseSnafu)
818    }
819
820    /// DeleteRange deletes the given range from the key-value store.
821    pub async fn delete_range(&self, req: DeleteRangeRequest) -> Result<DeleteRangeResponse> {
822        self.store_client()?
823            .delete_range(req.into())
824            .await?
825            .try_into()
826            .context(ConvertMetaResponseSnafu)
827    }
828
829    /// Query the procedure state by its id.
830    pub async fn query_procedure_state(&self, pid: &str) -> Result<ProcedureStateResponse> {
831        self.procedure_client()?.query_procedure_state(pid).await
832    }
833
834    /// Submit a region migration task.
835    pub async fn migrate_region(
836        &self,
837        context: &ExecutorContext,
838        request: MigrateRegionRequest,
839    ) -> Result<MigrateRegionResponse> {
840        self.procedure_client()?
841            .migrate_region(
842                context,
843                request.region_id,
844                request.from_peer,
845                request.to_peer,
846                request.timeout,
847            )
848            .await
849    }
850
851    /// Reconcile the procedure state.
852    pub async fn reconcile(&self, request: ReconcileRequest) -> Result<ReconcileResponse> {
853        self.procedure_client()?.reconcile(request).await
854    }
855
856    /// Manually trigger GC for specific regions.
857    pub async fn gc_regions(
858        &self,
859        context: &ExecutorContext,
860        request: GcRegionsRequest,
861    ) -> Result<GcResponse> {
862        self.procedure_client()?.gc_regions(context, request).await
863    }
864
865    /// Manually trigger GC for a table (all its regions).
866    pub async fn gc_table(
867        &self,
868        context: &ExecutorContext,
869        request: GcTableRequest,
870    ) -> Result<GcResponse> {
871        self.procedure_client()?.gc_table(context, request).await
872    }
873
874    /// Submit a DDL task.
875    pub async fn submit_ddl_task(
876        &self,
877        context: ExecutorContext,
878        request: SubmitDdlTaskRequest,
879    ) -> Result<SubmitDdlTaskResponse> {
880        let event_context = procedure_event_context(&context);
881        let actor = procedure_actor(&context);
882        let mut query_context = context.query_context.context(MissingQueryContextSnafu)?;
883        query_context
884            .extensions
885            .remove(CREATE_DATABASE_CREATOR_EXTENSION_KEY);
886        if let DdlTask::CreateDatabase(CreateDatabaseTask {
887            creator: Some(creator),
888            ..
889        }) = &request.task
890        {
891            query_context.extensions.insert(
892                CREATE_DATABASE_CREATOR_EXTENSION_KEY.to_string(),
893                serde_json::to_string(creator).context(ConvertMetaConfigSnafu)?,
894            );
895        }
896
897        let mut request: api::v1::meta::DdlTaskRequest =
898            request.try_into().context(ConvertMetaRequestSnafu)?;
899        request.query_context = Some(api::v1::QueryContext::from(query_context));
900        request.event_context = event_context;
901        request.actor = actor;
902
903        self.procedure_client()?
904            .submit_ddl_task(request)
905            .await?
906            .try_into()
907            .context(ConvertMetaResponseSnafu)
908    }
909
910    pub fn heartbeat_client(&self) -> Result<HeartbeatClient> {
911        self.heartbeat.clone().context(NotStartedSnafu {
912            name: "heartbeat_client",
913        })
914    }
915
916    pub fn config_client(&self) -> Result<ConfigClient> {
917        self.config.clone().context(NotStartedSnafu {
918            name: "config_client",
919        })
920    }
921
922    pub fn store_client(&self) -> Result<StoreClient> {
923        self.store.clone().context(NotStartedSnafu {
924            name: "store_client",
925        })
926    }
927
928    pub fn procedure_client(&self) -> Result<ProcedureClient> {
929        self.procedure.clone().context(NotStartedSnafu {
930            name: "procedure_client",
931        })
932    }
933
934    pub fn cluster_client(&self) -> Result<ClusterClient> {
935        self.cluster.clone().context(NotStartedSnafu {
936            name: "cluster_client",
937        })
938    }
939
940    pub fn channel_config(&self) -> &ChannelConfig {
941        self.channel_manager.config()
942    }
943
944    pub fn id(&self) -> Id {
945        self.id
946    }
947}
948
949#[cfg(test)]
950mod tests {
951    use std::sync::atomic::{AtomicUsize, Ordering};
952    use std::sync::{Arc, Mutex};
953
954    use api::v1::meta::{HeartbeatRequest, Peer};
955    use common_base::readable_size::ReadableSize;
956    use common_meta::kv_backend::{KvBackend, KvBackendRef, ResettableKvBackendRef, TxnService};
957    use rand::Rng;
958
959    use super::*;
960    use crate::error;
961    use crate::mocks::{self, MockMetaContext};
962
963    const TEST_KEY_PREFIX: &str = "__unit_test__meta__";
964
965    struct TestClient {
966        ns: String,
967        client: MetaClient,
968        meta_ctx: MockMetaContext,
969    }
970
971    impl TestClient {
972        async fn new(ns: impl Into<String>) -> Self {
973            // can also test with etcd: mocks::mock_client_with_etcdstore("127.0.0.1:2379").await;
974            let (client, meta_ctx) = mocks::mock_client_with_memstore().await;
975            Self {
976                ns: ns.into(),
977                client,
978                meta_ctx,
979            }
980        }
981
982        async fn new_with_grpc_message_sizes(
983            ns: impl Into<String>,
984            server_max_recv_message_size: ReadableSize,
985            server_max_send_message_size: ReadableSize,
986            client_max_recv_message_size: ReadableSize,
987            client_max_send_message_size: ReadableSize,
988        ) -> Self {
989            let (client, meta_ctx) = mocks::mock_client_with_memstore_and_grpc_message_sizes(
990                server_max_recv_message_size,
991                server_max_send_message_size,
992                client_max_recv_message_size,
993                client_max_send_message_size,
994            )
995            .await;
996            Self {
997                ns: ns.into(),
998                client,
999                meta_ctx,
1000            }
1001        }
1002
1003        fn key(&self, name: &str) -> Vec<u8> {
1004            format!("{}-{}-{}", TEST_KEY_PREFIX, self.ns, name).into_bytes()
1005        }
1006
1007        async fn gen_data(&self) {
1008            for i in 0..10 {
1009                let req = PutRequest::new()
1010                    .with_key(self.key(&format!("key-{i}")))
1011                    .with_value(format!("{}-{}", "value", i).into_bytes())
1012                    .with_prev_kv();
1013                let res = self.client.put(req).await;
1014                let _ = res.unwrap();
1015            }
1016        }
1017
1018        async fn clear_data(&self) {
1019            let req =
1020                DeleteRangeRequest::new().with_prefix(format!("{}-{}", TEST_KEY_PREFIX, self.ns));
1021            let res = self.client.delete_range(req).await;
1022            let _ = res.unwrap();
1023        }
1024
1025        #[allow(dead_code)]
1026        fn kv_backend(&self) -> KvBackendRef {
1027            self.meta_ctx.kv_backend.clone()
1028        }
1029
1030        fn in_memory(&self) -> Option<ResettableKvBackendRef> {
1031            self.meta_ctx.in_memory.clone()
1032        }
1033    }
1034
1035    async fn new_client(ns: impl Into<String>) -> TestClient {
1036        let client = TestClient::new(ns).await;
1037        client.clear_data().await;
1038        client
1039    }
1040
1041    #[tokio::test]
1042    async fn test_meta_client_builder() {
1043        let urls = &["127.0.0.1:3001", "127.0.0.1:3002"];
1044
1045        let mut meta_client = MetaClientBuilder::new(0, Role::Datanode)
1046            .enable_heartbeat()
1047            .build();
1048        let _ = meta_client.heartbeat_client().unwrap();
1049        assert!(meta_client.store_client().is_err());
1050        meta_client.start(urls).await.unwrap();
1051
1052        let mut meta_client = MetaClientBuilder::new(0, Role::Datanode).build();
1053        assert!(meta_client.heartbeat_client().is_err());
1054        assert!(meta_client.store_client().is_err());
1055        meta_client.start(urls).await.unwrap();
1056
1057        let mut meta_client = MetaClientBuilder::new(0, Role::Datanode)
1058            .enable_store()
1059            .build();
1060        assert!(meta_client.heartbeat_client().is_err());
1061        let _ = meta_client.store_client().unwrap();
1062        meta_client.start(urls).await.unwrap();
1063
1064        let mut meta_client = MetaClientBuilder::new(2, Role::Datanode)
1065            .enable_heartbeat()
1066            .enable_store()
1067            .build();
1068        assert_eq!(2, meta_client.id());
1069        assert_eq!(2, meta_client.id());
1070        let _ = meta_client.heartbeat_client().unwrap();
1071        let _ = meta_client.store_client().unwrap();
1072        meta_client.start(urls).await.unwrap();
1073    }
1074
1075    #[tokio::test]
1076    async fn test_not_start_heartbeat_client() {
1077        let urls = &["127.0.0.1:3001", "127.0.0.1:3002"];
1078        let mut meta_client = MetaClientBuilder::new(0, Role::Datanode)
1079            .enable_store()
1080            .build();
1081        meta_client.start(urls).await.unwrap();
1082        let res = meta_client.ask_leader().await;
1083        assert!(matches!(res.err(), Some(error::Error::NotStarted { .. })));
1084    }
1085
1086    #[tokio::test]
1087    async fn test_not_start_store_client() {
1088        let urls = &["127.0.0.1:3001", "127.0.0.1:3002"];
1089        let mut meta_client = MetaClientBuilder::new(0, Role::Datanode)
1090            .enable_heartbeat()
1091            .build();
1092
1093        meta_client.start(urls).await.unwrap();
1094        let res = meta_client.put(PutRequest::default()).await;
1095        assert!(matches!(res.err(), Some(error::Error::NotStarted { .. })));
1096    }
1097
1098    #[tokio::test]
1099    async fn test_store_writes_are_read_only_by_default() {
1100        let meta_client = MetaClientBuilder::new(0, Role::Datanode)
1101            .enable_store()
1102            .build();
1103
1104        let res = meta_client.put(PutRequest::default()).await;
1105        assert!(matches!(
1106            res.err(),
1107            Some(error::Error::ReadOnlyKvBackend { .. })
1108        ));
1109    }
1110
1111    #[tokio::test]
1112    async fn test_ask_leader() {
1113        let tc = new_client("test_ask_leader").await;
1114        tc.client.ask_leader().await.unwrap();
1115    }
1116
1117    #[tokio::test]
1118    async fn test_heartbeat() {
1119        let tc = new_client("test_heartbeat").await;
1120        let (sender, mut receiver, _config) = tc.client.heartbeat().await.unwrap();
1121        // send heartbeats
1122
1123        let request_sent = Arc::new(AtomicUsize::new(0));
1124        let request_sent_clone = request_sent.clone();
1125        let _handle = tokio::spawn(async move {
1126            for _ in 0..5 {
1127                let req = HeartbeatRequest {
1128                    peer: Some(Peer {
1129                        id: 1,
1130                        addr: "meta_client_peer".to_string(),
1131                    }),
1132                    ..Default::default()
1133                };
1134                sender.send(req).await.unwrap();
1135                request_sent_clone.fetch_add(1, Ordering::Relaxed);
1136            }
1137        });
1138
1139        let heartbeat_count = Arc::new(AtomicUsize::new(0));
1140        let heartbeat_count_clone = heartbeat_count.clone();
1141        let handle = tokio::spawn(async move {
1142            while let Some(_resp) = receiver.message().await.unwrap() {
1143                heartbeat_count_clone.fetch_add(1, Ordering::Relaxed);
1144            }
1145        });
1146
1147        handle.await.unwrap();
1148        //+1 for the initial response
1149        assert_eq!(
1150            request_sent.load(Ordering::Relaxed) + 1,
1151            heartbeat_count.load(Ordering::Relaxed)
1152        );
1153    }
1154
1155    #[tokio::test]
1156    async fn test_range_get() {
1157        let tc = new_client("test_range_get").await;
1158        tc.gen_data().await;
1159
1160        let key = tc.key("key-0");
1161        let req = RangeRequest::new().with_key(key.as_slice());
1162        let res = tc.client.range(req).await;
1163        let mut kvs = res.unwrap().take_kvs();
1164        assert_eq!(1, kvs.len());
1165        let mut kv = kvs.pop().unwrap();
1166        assert_eq!(key, kv.take_key());
1167        assert_eq!(b"value-0".to_vec(), kv.take_value());
1168    }
1169
1170    #[tokio::test]
1171    async fn test_range_get_prefix() {
1172        let tc = new_client("test_range_get_prefix").await;
1173        tc.gen_data().await;
1174
1175        let req = RangeRequest::new().with_prefix(tc.key("key-"));
1176        let res = tc.client.range(req).await;
1177        let kvs = res.unwrap().take_kvs();
1178        assert_eq!(10, kvs.len());
1179        for (i, mut kv) in kvs.into_iter().enumerate() {
1180            assert_eq!(tc.key(&format!("key-{i}")), kv.take_key());
1181            assert_eq!(format!("{}-{}", "value", i).into_bytes(), kv.take_value());
1182        }
1183    }
1184
1185    #[tokio::test]
1186    async fn test_range() {
1187        let tc = new_client("test_range").await;
1188        tc.gen_data().await;
1189
1190        let req = RangeRequest::new().with_range(tc.key("key-5"), tc.key("key-8"));
1191        let res = tc.client.range(req).await;
1192        let kvs = res.unwrap().take_kvs();
1193        assert_eq!(3, kvs.len());
1194        for (i, mut kv) in kvs.into_iter().enumerate() {
1195            assert_eq!(tc.key(&format!("key-{}", i + 5)), kv.take_key());
1196            assert_eq!(
1197                format!("{}-{}", "value", i + 5).into_bytes(),
1198                kv.take_value()
1199            );
1200        }
1201    }
1202
1203    #[tokio::test]
1204    async fn test_range_keys_only() {
1205        let tc = new_client("test_range_keys_only").await;
1206        tc.gen_data().await;
1207
1208        let req = RangeRequest::new()
1209            .with_range(tc.key("key-5"), tc.key("key-8"))
1210            .with_keys_only();
1211        let res = tc.client.range(req).await;
1212        let kvs = res.unwrap().take_kvs();
1213        assert_eq!(3, kvs.len());
1214        for (i, mut kv) in kvs.into_iter().enumerate() {
1215            assert_eq!(tc.key(&format!("key-{}", i + 5)), kv.take_key());
1216            assert!(kv.take_value().is_empty());
1217        }
1218    }
1219
1220    #[tokio::test]
1221    async fn test_put() {
1222        let tc = new_client("test_put").await;
1223
1224        let req = PutRequest::new()
1225            .with_key(tc.key("key"))
1226            .with_value(b"value".to_vec());
1227        let res = tc.client.put(req).await;
1228        assert!(res.unwrap().prev_kv.is_none());
1229    }
1230
1231    #[tokio::test]
1232    async fn test_put_with_prev_kv() {
1233        let tc = new_client("test_put_with_prev_kv").await;
1234
1235        let key = tc.key("key");
1236        let req = PutRequest::new()
1237            .with_key(key.as_slice())
1238            .with_value(b"value".to_vec())
1239            .with_prev_kv();
1240        let res = tc.client.put(req).await;
1241        assert!(res.unwrap().prev_kv.is_none());
1242
1243        let req = PutRequest::new()
1244            .with_key(key.as_slice())
1245            .with_value(b"value1".to_vec())
1246            .with_prev_kv();
1247        let res = tc.client.put(req).await;
1248        let mut kv = res.unwrap().prev_kv.unwrap();
1249        assert_eq!(key, kv.take_key());
1250        assert_eq!(b"value".to_vec(), kv.take_value());
1251    }
1252
1253    #[tokio::test]
1254    async fn test_batch_put() {
1255        let tc = new_client("test_batch_put").await;
1256
1257        let mut req = BatchPutRequest::new();
1258        for i in 0..275 {
1259            req = req.add_kv(
1260                tc.key(&format!("key-{}", i)),
1261                format!("value-{}", i).into_bytes(),
1262            );
1263        }
1264
1265        let res = tc.client.batch_put(req).await;
1266        assert_eq!(0, res.unwrap().take_prev_kvs().len());
1267
1268        let req = RangeRequest::new().with_prefix(tc.key("key-"));
1269        let res = tc.client.range(req).await;
1270        let kvs = res.unwrap().take_kvs();
1271        assert_eq!(275, kvs.len());
1272    }
1273
1274    #[tokio::test]
1275    async fn test_batch_get() {
1276        let tc = new_client("test_batch_get").await;
1277        tc.gen_data().await;
1278
1279        let mut req = BatchGetRequest::default();
1280        for i in 0..256 {
1281            req = req.add_key(tc.key(&format!("key-{}", i)));
1282        }
1283        let res = tc.client.batch_get(req).await.unwrap();
1284        assert_eq!(10, res.kvs.len());
1285
1286        let req = BatchGetRequest::default()
1287            .add_key(tc.key("key-1"))
1288            .add_key(tc.key("key-999"));
1289        let res = tc.client.batch_get(req).await.unwrap();
1290        assert_eq!(1, res.kvs.len());
1291    }
1292
1293    #[tokio::test]
1294    async fn test_batch_put_with_prev_kv() {
1295        let tc = new_client("test_batch_put_with_prev_kv").await;
1296
1297        let key = tc.key("key");
1298        let key2 = tc.key("key2");
1299        let req = BatchPutRequest::new().add_kv(key.as_slice(), b"value".to_vec());
1300        let res = tc.client.batch_put(req).await;
1301        assert_eq!(0, res.unwrap().take_prev_kvs().len());
1302
1303        let req = BatchPutRequest::new()
1304            .add_kv(key.as_slice(), b"value-".to_vec())
1305            .add_kv(key2.as_slice(), b"value2-".to_vec())
1306            .with_prev_kv();
1307        let res = tc.client.batch_put(req).await;
1308        let mut kvs = res.unwrap().take_prev_kvs();
1309        assert_eq!(1, kvs.len());
1310        let mut kv = kvs.pop().unwrap();
1311        assert_eq!(key, kv.take_key());
1312        assert_eq!(b"value".to_vec(), kv.take_value());
1313    }
1314
1315    #[tokio::test]
1316    async fn test_compare_and_put() {
1317        let tc = new_client("test_compare_and_put").await;
1318
1319        let key = tc.key("key");
1320        let req = CompareAndPutRequest::new()
1321            .with_key(key.as_slice())
1322            .with_expect(b"expect".to_vec())
1323            .with_value(b"value".to_vec());
1324        let res = tc.client.compare_and_put(req).await;
1325        assert!(!res.unwrap().is_success());
1326
1327        // create if absent
1328        let req = CompareAndPutRequest::new()
1329            .with_key(key.as_slice())
1330            .with_value(b"value".to_vec());
1331        let res = tc.client.compare_and_put(req).await;
1332        let mut res = res.unwrap();
1333        assert!(res.is_success());
1334        assert!(res.take_prev_kv().is_none());
1335
1336        // compare and put fail
1337        let req = CompareAndPutRequest::new()
1338            .with_key(key.as_slice())
1339            .with_expect(b"not_eq".to_vec())
1340            .with_value(b"value2".to_vec());
1341        let res = tc.client.compare_and_put(req).await;
1342        let mut res = res.unwrap();
1343        assert!(!res.is_success());
1344        assert_eq!(b"value".to_vec(), res.take_prev_kv().unwrap().take_value());
1345
1346        // compare and put success
1347        let req = CompareAndPutRequest::new()
1348            .with_key(key.as_slice())
1349            .with_expect(b"value".to_vec())
1350            .with_value(b"value2".to_vec());
1351        let res = tc.client.compare_and_put(req).await;
1352        let mut res = res.unwrap();
1353        assert!(res.is_success());
1354
1355        // If compare-and-put is success, previous value doesn't need to be returned.
1356        assert!(res.take_prev_kv().is_none());
1357    }
1358
1359    #[tokio::test]
1360    async fn test_delete_with_key() {
1361        let tc = new_client("test_delete_with_key").await;
1362        tc.gen_data().await;
1363
1364        let req = DeleteRangeRequest::new()
1365            .with_key(tc.key("key-0"))
1366            .with_prev_kv();
1367        let res = tc.client.delete_range(req).await;
1368        let mut res = res.unwrap();
1369        assert_eq!(1, res.deleted());
1370        let mut kvs = res.take_prev_kvs();
1371        assert_eq!(1, kvs.len());
1372        let mut kv = kvs.pop().unwrap();
1373        assert_eq!(b"value-0".to_vec(), kv.take_value());
1374    }
1375
1376    #[tokio::test]
1377    async fn test_delete_with_prefix() {
1378        let tc = new_client("test_delete_with_prefix").await;
1379        tc.gen_data().await;
1380
1381        let req = DeleteRangeRequest::new()
1382            .with_prefix(tc.key("key-"))
1383            .with_prev_kv();
1384        let res = tc.client.delete_range(req).await;
1385        let mut res = res.unwrap();
1386        assert_eq!(10, res.deleted());
1387        let kvs = res.take_prev_kvs();
1388        assert_eq!(10, kvs.len());
1389        for (i, mut kv) in kvs.into_iter().enumerate() {
1390            assert_eq!(format!("{}-{}", "value", i).into_bytes(), kv.take_value());
1391        }
1392    }
1393
1394    #[tokio::test]
1395    async fn test_delete_with_range() {
1396        let tc = new_client("test_delete_with_range").await;
1397        tc.gen_data().await;
1398
1399        let req = DeleteRangeRequest::new()
1400            .with_range(tc.key("key-2"), tc.key("key-7"))
1401            .with_prev_kv();
1402        let res = tc.client.delete_range(req).await;
1403        let mut res = res.unwrap();
1404        assert_eq!(5, res.deleted());
1405        let kvs = res.take_prev_kvs();
1406        assert_eq!(5, kvs.len());
1407        for (i, mut kv) in kvs.into_iter().enumerate() {
1408            assert_eq!(
1409                format!("{}-{}", "value", i + 2).into_bytes(),
1410                kv.take_value()
1411            );
1412        }
1413    }
1414
1415    fn mock_decoder(kv: KeyValue) -> MetaResult<Vec<u8>> {
1416        Ok(kv.value)
1417    }
1418
1419    struct RecordingKvBackend {
1420        inner: KvBackendRef,
1421        limits: Arc<Mutex<Vec<i64>>>,
1422    }
1423
1424    #[async_trait::async_trait]
1425    impl TxnService for RecordingKvBackend {
1426        type Error = meta_error::Error;
1427    }
1428
1429    #[async_trait::async_trait]
1430    impl KvBackend for RecordingKvBackend {
1431        fn name(&self) -> &str {
1432            "RecordingKvBackend"
1433        }
1434
1435        fn as_any(&self) -> &dyn std::any::Any {
1436            self
1437        }
1438
1439        async fn range(&self, req: RangeRequest) -> MetaResult<RangeResponse> {
1440            self.limits.lock().unwrap().push(req.limit);
1441            self.inner.range(req).await
1442        }
1443
1444        async fn put(&self, req: PutRequest) -> MetaResult<PutResponse> {
1445            self.inner.put(req).await
1446        }
1447
1448        async fn batch_put(&self, req: BatchPutRequest) -> MetaResult<BatchPutResponse> {
1449            self.inner.batch_put(req).await
1450        }
1451
1452        async fn batch_get(&self, req: BatchGetRequest) -> MetaResult<BatchGetResponse> {
1453            self.inner.batch_get(req).await
1454        }
1455
1456        async fn delete_range(&self, req: DeleteRangeRequest) -> MetaResult<DeleteRangeResponse> {
1457            self.inner.delete_range(req).await
1458        }
1459
1460        async fn batch_delete(&self, req: BatchDeleteRequest) -> MetaResult<BatchDeleteResponse> {
1461            self.inner.batch_delete(req).await
1462        }
1463    }
1464
1465    async fn adaptive_range_with_message_sizes(
1466        server_max_recv_message_size: ReadableSize,
1467        server_max_send_message_size: ReadableSize,
1468        client_max_recv_message_size: ReadableSize,
1469        client_max_send_message_size: ReadableSize,
1470    ) -> (Vec<Vec<u8>>, Vec<Vec<u8>>, Vec<i64>) {
1471        let tx = TestClient::new_with_grpc_message_sizes(
1472            "test_cluster_client",
1473            server_max_recv_message_size,
1474            server_max_send_message_size,
1475            client_max_recv_message_size,
1476            client_max_send_message_size,
1477        )
1478        .await;
1479        let in_memory = tx.in_memory().unwrap();
1480        let cluster_client = tx.client.cluster_client().unwrap();
1481        let mut rng = rand::rng();
1482
1483        let mut expected = Vec::new();
1484        for i in 0..4 {
1485            let data: Vec<u8> = (0..256 * 1024).map(|_| rng.random::<u8>()).collect();
1486            in_memory
1487                .put(
1488                    PutRequest::new()
1489                        .with_key(format!("__prefix/{i}").as_bytes())
1490                        .with_value(data.clone()),
1491                )
1492                .await
1493                .unwrap();
1494            expected.push(data);
1495        }
1496
1497        let req = RangeRequest::new().with_prefix(b"__prefix/");
1498        let limits = Arc::new(Mutex::new(Vec::new()));
1499        let recording_backend = RecordingKvBackend {
1500            inner: Arc::new(cluster_client),
1501            limits: limits.clone(),
1502        };
1503        let stream =
1504            PaginationStream::new(Arc::new(recording_backend), req, 4, mock_decoder).into_stream();
1505
1506        let res = stream.try_collect::<Vec<_>>().await.unwrap();
1507        let limits = limits.lock().unwrap().clone();
1508        (expected, res, limits)
1509    }
1510
1511    #[tokio::test]
1512    async fn test_cluster_client_adaptive_range() {
1513        let (expected, res, limits) = adaptive_range_with_message_sizes(
1514            ReadableSize::mb(2),
1515            ReadableSize::mb(16),
1516            ReadableSize::mb(1),
1517            ReadableSize::mb(2),
1518        )
1519        .await;
1520
1521        assert_eq!(expected, res);
1522        assert_eq!(vec![4, 2, 2], limits);
1523    }
1524
1525    #[tokio::test]
1526    async fn test_cluster_client_adaptive_range_server_limit() {
1527        let (expected, res, limits) = adaptive_range_with_message_sizes(
1528            ReadableSize::mb(2),
1529            ReadableSize::mb(1),
1530            ReadableSize::mb(16),
1531            ReadableSize::mb(2),
1532        )
1533        .await;
1534
1535        assert_eq!(expected, res);
1536        assert_eq!(vec![4, 2, 2], limits);
1537    }
1538}