1mod 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 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 pub fn frontend_default_options() -> Self {
120 Self::new(0, Role::Frontend)
122 .enable_store()
123 .enable_heartbeat()
124 .enable_procedure()
125 .enable_access_cluster_info()
126 }
127
128 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 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 pub fn enable_store(self) -> Self {
156 Self {
157 enable_store: true,
158 ..self
159 }
160 }
161
162 #[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#[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#[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; 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 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 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#[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 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 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 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 pub async fn heartbeat(&self) -> Result<(HeartbeatSender, HeartbeatStream, HeartbeatConfig)> {
759 self.heartbeat_client()?.heartbeat().await
760 }
761
762 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 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 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 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 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 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 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 pub async fn query_procedure_state(&self, pid: &str) -> Result<ProcedureStateResponse> {
831 self.procedure_client()?.query_procedure_state(pid).await
832 }
833
834 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 pub async fn reconcile(&self, request: ReconcileRequest) -> Result<ReconcileResponse> {
853 self.procedure_client()?.reconcile(request).await
854 }
855
856 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 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 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 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 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 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 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 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 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 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}