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 }
513 } else {
514 NodeInfo {
516 peer: node.peer.unwrap_or_default(),
517 last_activity_ts,
518 status: NodeStatus::Metasrv(MetasrvStatus { is_leader: false }),
519 version: node.version,
520 git_commit: node.git_commit,
521 start_time_ms: node.start_time_ms,
522 total_cpu_millicores: node.cpus as i64,
523 total_memory_bytes: node.memory_bytes as i64,
524 cpu_usage_millicores: 0,
525 memory_usage_bytes: 0,
526 hostname: "".to_string(),
527 env_vars: Default::default(),
528 }
529 }
530 })
531 .chain(leader.into_iter().map(|node| {
532 if let Some(node_info) = node.info {
533 NodeInfo {
534 peer: node.peer.unwrap_or_default(),
535 last_activity_ts,
536 status: NodeStatus::Metasrv(MetasrvStatus { is_leader: true }),
537 version: node_info.version,
538 git_commit: node_info.git_commit,
539 start_time_ms: node_info.start_time_ms,
540 total_cpu_millicores: node_info.total_cpu_millicores,
541 total_memory_bytes: node_info.total_memory_bytes,
542 cpu_usage_millicores: node_info.cpu_usage_millicores,
543 memory_usage_bytes: node_info.memory_usage_bytes,
544 hostname: node_info.hostname,
545 env_vars: Default::default(),
546 }
547 } else {
548 NodeInfo {
550 peer: node.peer.unwrap_or_default(),
551 last_activity_ts,
552 status: NodeStatus::Metasrv(MetasrvStatus { is_leader: true }),
553 version: node.version,
554 git_commit: node.git_commit,
555 start_time_ms: node.start_time_ms,
556 total_cpu_millicores: node.cpus as i64,
557 total_memory_bytes: node.memory_bytes as i64,
558 cpu_usage_millicores: 0,
559 memory_usage_bytes: 0,
560 hostname: "".to_string(),
561 env_vars: Default::default(),
562 }
563 }
564 }))
565 .collect::<Vec<_>>()
566 } else {
567 Vec::new()
568 };
569
570 if let Some(prefix) = nodes_key_prefix {
571 let req = RangeRequest::new().with_prefix(prefix);
572 let res = cluster_client.range(req).await?;
573 for kv in res.kvs {
574 nodes.push(NodeInfo::try_from(kv.value).context(ConvertMetaResponseSnafu)?);
575 }
576 }
577
578 Ok(nodes)
579 }
580
581 async fn list_region_stats(&self) -> Result<Vec<RegionStat>> {
582 let cluster_kv_backend = Arc::new(self.cluster_client()?);
583 let range_prefix = DatanodeStatKey::prefix_key();
584 let req = RangeRequest::new().with_prefix(range_prefix);
585 let stream =
586 PaginationStream::new(cluster_kv_backend, req, 256, decode_stats).into_stream();
587 let mut datanode_stats = stream
588 .try_collect::<Vec<_>>()
589 .await
590 .context(ConvertMetaResponseSnafu)?;
591 let region_stats = datanode_stats
592 .iter_mut()
593 .flat_map(|datanode_stat| {
594 let last = datanode_stat.stats.pop();
595 last.map(|stat| stat.region_stats).unwrap_or_default()
596 })
597 .collect::<Vec<_>>();
598
599 Ok(region_stats)
600 }
601
602 async fn list_flow_stats(&self) -> Result<Option<FlowStat>> {
603 let cluster_backend = ClusterKvBackend::new(Arc::new(self.cluster_client()?));
604 let cluster_backend = Arc::new(cluster_backend) as KvBackendRef;
605 let flow_state_manager = FlowStateManager::new(cluster_backend);
606 let res = flow_state_manager.get().await.context(GetFlowStatSnafu)?;
607
608 Ok(res.map(|r| r.into()))
609 }
610}
611
612#[async_trait::async_trait]
615impl PeerDiscovery for MetaClient {
616 async fn active_frontends(&self) -> MetaResult<Vec<NodeInfo>> {
617 let nodes = self
618 .list_nodes(Some(ClusterRole::Frontend))
619 .await
620 .map_err(BoxedError::new)
621 .context(ExternalSnafu)?;
622 Ok(util::alive_frontends(
623 &DefaultSystemTimer,
624 nodes,
625 default_distributed_time_constants().frontend_heartbeat_interval,
628 ))
629 }
630
631 async fn active_datanodes(
632 &self,
633 filter: Option<for<'a> fn(&'a NodeWorkloads) -> bool>,
634 ) -> MetaResult<Vec<NodeInfo>> {
635 let nodes = self
636 .list_nodes(Some(ClusterRole::Datanode))
637 .await
638 .map_err(BoxedError::new)
639 .context(ExternalSnafu)?;
640 Ok(util::alive_datanodes(
641 &DefaultSystemTimer,
642 nodes,
643 default_distributed_time_constants().datanode_lease,
644 filter,
645 ))
646 }
647
648 async fn active_flownodes(
649 &self,
650 filter: Option<for<'a> fn(&'a NodeWorkloads) -> bool>,
651 ) -> MetaResult<Vec<NodeInfo>> {
652 let nodes = self
653 .list_nodes(Some(ClusterRole::Flownode))
654 .await
655 .map_err(BoxedError::new)
656 .context(ExternalSnafu)?;
657 Ok(util::alive_flownodes(
658 &DefaultSystemTimer,
659 nodes,
660 default_distributed_time_constants().flownode_lease,
661 filter,
662 ))
663 }
664}
665
666fn decode_stats(kv: KeyValue) -> MetaResult<DatanodeStatValue> {
667 DatanodeStatValue::try_from(kv.value)
668 .map_err(BoxedError::new)
669 .context(ExternalSnafu)
670}
671
672impl MetaClient {
673 pub async fn start<U, A>(&mut self, urls: A) -> Result<()>
674 where
675 U: AsRef<str>,
676 A: AsRef<[U]> + Clone,
677 {
678 info!("MetaClient channel config: {:?}", self.channel_config());
679
680 let urls = urls.as_ref().iter().map(|u| u.as_ref()).collect::<Vec<_>>();
681 let leader_provider = self.leader_provider_factory.create(&urls);
682
683 self.start_with(leader_provider, urls).await
684 }
685
686 pub(crate) async fn start_with<U, A>(
688 &mut self,
689 leader_provider: LeaderProviderRef,
690 peers: A,
691 ) -> Result<()>
692 where
693 U: AsRef<str>,
694 A: AsRef<[U]> + Clone,
695 {
696 if let Some(client) = &self.region_follower {
697 info!("Starting region follower client ...");
698 client.start_with(leader_provider.clone()).await?;
699 }
700
701 if let Some(client) = &self.heartbeat {
702 info!("Starting heartbeat client ...");
703 client.start_with(leader_provider.clone()).await?;
704 }
705
706 if let Some(client) = &self.config {
707 info!("Starting config client ...");
708 client.start_with(leader_provider.clone()).await?;
709 }
710
711 if let Some(client) = &mut self.store {
712 info!("Starting store client ...");
713 client.start(peers.clone()).await?;
714 }
715
716 if let Some(client) = &self.procedure {
717 info!("Starting procedure client ...");
718 client.start_with(leader_provider.clone()).await?;
719 }
720
721 if let Some(client) = &mut self.cluster {
722 info!("Starting cluster client ...");
723 client.start_with(leader_provider).await?;
724 }
725 Ok(())
726 }
727
728 pub async fn ask_leader(&self) -> Result<String> {
731 self.heartbeat_client()?.ask_leader().await
732 }
733
734 pub async fn pull_config<T, U>(&self, deserializer: T) -> Result<U>
735 where
736 T: PluginOptionsDeserializer<U>,
737 U: DeserializeOwned,
738 {
739 let res = self.config_client()?.pull_config().await?;
740 let v = deserializer
741 .deserialize(&res.payload)
742 .context(ConvertMetaConfigSnafu)?;
743 Ok(v)
744 }
745
746 pub async fn heartbeat(&self) -> Result<(HeartbeatSender, HeartbeatStream, HeartbeatConfig)> {
755 self.heartbeat_client()?.heartbeat().await
756 }
757
758 pub async fn range(&self, req: RangeRequest) -> Result<RangeResponse> {
760 self.store_client()?
761 .range(req.into())
762 .await?
763 .try_into()
764 .context(ConvertMetaResponseSnafu)
765 }
766
767 pub async fn put(&self, req: PutRequest) -> Result<PutResponse> {
769 self.store_client()?
770 .put(req.into())
771 .await?
772 .try_into()
773 .context(ConvertMetaResponseSnafu)
774 }
775
776 pub async fn batch_get(&self, req: BatchGetRequest) -> Result<BatchGetResponse> {
778 self.store_client()?
779 .batch_get(req.into())
780 .await?
781 .try_into()
782 .context(ConvertMetaResponseSnafu)
783 }
784
785 pub async fn batch_put(&self, req: BatchPutRequest) -> Result<BatchPutResponse> {
787 self.store_client()?
788 .batch_put(req.into())
789 .await?
790 .try_into()
791 .context(ConvertMetaResponseSnafu)
792 }
793
794 pub async fn batch_delete(&self, req: BatchDeleteRequest) -> Result<BatchDeleteResponse> {
796 self.store_client()?
797 .batch_delete(req.into())
798 .await?
799 .try_into()
800 .context(ConvertMetaResponseSnafu)
801 }
802
803 pub async fn compare_and_put(
806 &self,
807 req: CompareAndPutRequest,
808 ) -> Result<CompareAndPutResponse> {
809 self.store_client()?
810 .compare_and_put(req.into())
811 .await?
812 .try_into()
813 .context(ConvertMetaResponseSnafu)
814 }
815
816 pub async fn delete_range(&self, req: DeleteRangeRequest) -> Result<DeleteRangeResponse> {
818 self.store_client()?
819 .delete_range(req.into())
820 .await?
821 .try_into()
822 .context(ConvertMetaResponseSnafu)
823 }
824
825 pub async fn query_procedure_state(&self, pid: &str) -> Result<ProcedureStateResponse> {
827 self.procedure_client()?.query_procedure_state(pid).await
828 }
829
830 pub async fn migrate_region(
832 &self,
833 context: &ExecutorContext,
834 request: MigrateRegionRequest,
835 ) -> Result<MigrateRegionResponse> {
836 self.procedure_client()?
837 .migrate_region(
838 context,
839 request.region_id,
840 request.from_peer,
841 request.to_peer,
842 request.timeout,
843 )
844 .await
845 }
846
847 pub async fn reconcile(&self, request: ReconcileRequest) -> Result<ReconcileResponse> {
849 self.procedure_client()?.reconcile(request).await
850 }
851
852 pub async fn gc_regions(
854 &self,
855 context: &ExecutorContext,
856 request: GcRegionsRequest,
857 ) -> Result<GcResponse> {
858 self.procedure_client()?.gc_regions(context, request).await
859 }
860
861 pub async fn gc_table(
863 &self,
864 context: &ExecutorContext,
865 request: GcTableRequest,
866 ) -> Result<GcResponse> {
867 self.procedure_client()?.gc_table(context, request).await
868 }
869
870 pub async fn submit_ddl_task(
872 &self,
873 context: ExecutorContext,
874 request: SubmitDdlTaskRequest,
875 ) -> Result<SubmitDdlTaskResponse> {
876 let event_context = procedure_event_context(&context);
877 let actor = procedure_actor(&context);
878 let mut query_context = context.query_context.context(MissingQueryContextSnafu)?;
879 query_context
880 .extensions
881 .remove(CREATE_DATABASE_CREATOR_EXTENSION_KEY);
882 if let DdlTask::CreateDatabase(CreateDatabaseTask {
883 creator: Some(creator),
884 ..
885 }) = &request.task
886 {
887 query_context.extensions.insert(
888 CREATE_DATABASE_CREATOR_EXTENSION_KEY.to_string(),
889 serde_json::to_string(creator).context(ConvertMetaConfigSnafu)?,
890 );
891 }
892
893 let mut request: api::v1::meta::DdlTaskRequest =
894 request.try_into().context(ConvertMetaRequestSnafu)?;
895 request.query_context = Some(api::v1::QueryContext::from(query_context));
896 request.event_context = event_context;
897 request.actor = actor;
898
899 self.procedure_client()?
900 .submit_ddl_task(request)
901 .await?
902 .try_into()
903 .context(ConvertMetaResponseSnafu)
904 }
905
906 pub fn heartbeat_client(&self) -> Result<HeartbeatClient> {
907 self.heartbeat.clone().context(NotStartedSnafu {
908 name: "heartbeat_client",
909 })
910 }
911
912 pub fn config_client(&self) -> Result<ConfigClient> {
913 self.config.clone().context(NotStartedSnafu {
914 name: "config_client",
915 })
916 }
917
918 pub fn store_client(&self) -> Result<StoreClient> {
919 self.store.clone().context(NotStartedSnafu {
920 name: "store_client",
921 })
922 }
923
924 pub fn procedure_client(&self) -> Result<ProcedureClient> {
925 self.procedure.clone().context(NotStartedSnafu {
926 name: "procedure_client",
927 })
928 }
929
930 pub fn cluster_client(&self) -> Result<ClusterClient> {
931 self.cluster.clone().context(NotStartedSnafu {
932 name: "cluster_client",
933 })
934 }
935
936 pub fn channel_config(&self) -> &ChannelConfig {
937 self.channel_manager.config()
938 }
939
940 pub fn id(&self) -> Id {
941 self.id
942 }
943}
944
945#[cfg(test)]
946mod tests {
947 use std::sync::atomic::{AtomicUsize, Ordering};
948 use std::sync::{Arc, Mutex};
949
950 use api::v1::meta::{HeartbeatRequest, Peer};
951 use common_base::readable_size::ReadableSize;
952 use common_meta::kv_backend::{KvBackend, KvBackendRef, ResettableKvBackendRef, TxnService};
953 use rand::Rng;
954
955 use super::*;
956 use crate::error;
957 use crate::mocks::{self, MockMetaContext};
958
959 const TEST_KEY_PREFIX: &str = "__unit_test__meta__";
960
961 struct TestClient {
962 ns: String,
963 client: MetaClient,
964 meta_ctx: MockMetaContext,
965 }
966
967 impl TestClient {
968 async fn new(ns: impl Into<String>) -> Self {
969 let (client, meta_ctx) = mocks::mock_client_with_memstore().await;
971 Self {
972 ns: ns.into(),
973 client,
974 meta_ctx,
975 }
976 }
977
978 async fn new_with_grpc_message_sizes(
979 ns: impl Into<String>,
980 server_max_recv_message_size: ReadableSize,
981 server_max_send_message_size: ReadableSize,
982 client_max_recv_message_size: ReadableSize,
983 client_max_send_message_size: ReadableSize,
984 ) -> Self {
985 let (client, meta_ctx) = mocks::mock_client_with_memstore_and_grpc_message_sizes(
986 server_max_recv_message_size,
987 server_max_send_message_size,
988 client_max_recv_message_size,
989 client_max_send_message_size,
990 )
991 .await;
992 Self {
993 ns: ns.into(),
994 client,
995 meta_ctx,
996 }
997 }
998
999 fn key(&self, name: &str) -> Vec<u8> {
1000 format!("{}-{}-{}", TEST_KEY_PREFIX, self.ns, name).into_bytes()
1001 }
1002
1003 async fn gen_data(&self) {
1004 for i in 0..10 {
1005 let req = PutRequest::new()
1006 .with_key(self.key(&format!("key-{i}")))
1007 .with_value(format!("{}-{}", "value", i).into_bytes())
1008 .with_prev_kv();
1009 let res = self.client.put(req).await;
1010 let _ = res.unwrap();
1011 }
1012 }
1013
1014 async fn clear_data(&self) {
1015 let req =
1016 DeleteRangeRequest::new().with_prefix(format!("{}-{}", TEST_KEY_PREFIX, self.ns));
1017 let res = self.client.delete_range(req).await;
1018 let _ = res.unwrap();
1019 }
1020
1021 #[allow(dead_code)]
1022 fn kv_backend(&self) -> KvBackendRef {
1023 self.meta_ctx.kv_backend.clone()
1024 }
1025
1026 fn in_memory(&self) -> Option<ResettableKvBackendRef> {
1027 self.meta_ctx.in_memory.clone()
1028 }
1029 }
1030
1031 async fn new_client(ns: impl Into<String>) -> TestClient {
1032 let client = TestClient::new(ns).await;
1033 client.clear_data().await;
1034 client
1035 }
1036
1037 #[tokio::test]
1038 async fn test_meta_client_builder() {
1039 let urls = &["127.0.0.1:3001", "127.0.0.1:3002"];
1040
1041 let mut meta_client = MetaClientBuilder::new(0, Role::Datanode)
1042 .enable_heartbeat()
1043 .build();
1044 let _ = meta_client.heartbeat_client().unwrap();
1045 assert!(meta_client.store_client().is_err());
1046 meta_client.start(urls).await.unwrap();
1047
1048 let mut meta_client = MetaClientBuilder::new(0, Role::Datanode).build();
1049 assert!(meta_client.heartbeat_client().is_err());
1050 assert!(meta_client.store_client().is_err());
1051 meta_client.start(urls).await.unwrap();
1052
1053 let mut meta_client = MetaClientBuilder::new(0, Role::Datanode)
1054 .enable_store()
1055 .build();
1056 assert!(meta_client.heartbeat_client().is_err());
1057 let _ = meta_client.store_client().unwrap();
1058 meta_client.start(urls).await.unwrap();
1059
1060 let mut meta_client = MetaClientBuilder::new(2, Role::Datanode)
1061 .enable_heartbeat()
1062 .enable_store()
1063 .build();
1064 assert_eq!(2, meta_client.id());
1065 assert_eq!(2, meta_client.id());
1066 let _ = meta_client.heartbeat_client().unwrap();
1067 let _ = meta_client.store_client().unwrap();
1068 meta_client.start(urls).await.unwrap();
1069 }
1070
1071 #[tokio::test]
1072 async fn test_not_start_heartbeat_client() {
1073 let urls = &["127.0.0.1:3001", "127.0.0.1:3002"];
1074 let mut meta_client = MetaClientBuilder::new(0, Role::Datanode)
1075 .enable_store()
1076 .build();
1077 meta_client.start(urls).await.unwrap();
1078 let res = meta_client.ask_leader().await;
1079 assert!(matches!(res.err(), Some(error::Error::NotStarted { .. })));
1080 }
1081
1082 #[tokio::test]
1083 async fn test_not_start_store_client() {
1084 let urls = &["127.0.0.1:3001", "127.0.0.1:3002"];
1085 let mut meta_client = MetaClientBuilder::new(0, Role::Datanode)
1086 .enable_heartbeat()
1087 .build();
1088
1089 meta_client.start(urls).await.unwrap();
1090 let res = meta_client.put(PutRequest::default()).await;
1091 assert!(matches!(res.err(), Some(error::Error::NotStarted { .. })));
1092 }
1093
1094 #[tokio::test]
1095 async fn test_store_writes_are_read_only_by_default() {
1096 let meta_client = MetaClientBuilder::new(0, Role::Datanode)
1097 .enable_store()
1098 .build();
1099
1100 let res = meta_client.put(PutRequest::default()).await;
1101 assert!(matches!(
1102 res.err(),
1103 Some(error::Error::ReadOnlyKvBackend { .. })
1104 ));
1105 }
1106
1107 #[tokio::test]
1108 async fn test_ask_leader() {
1109 let tc = new_client("test_ask_leader").await;
1110 tc.client.ask_leader().await.unwrap();
1111 }
1112
1113 #[tokio::test]
1114 async fn test_heartbeat() {
1115 let tc = new_client("test_heartbeat").await;
1116 let (sender, mut receiver, _config) = tc.client.heartbeat().await.unwrap();
1117 let request_sent = Arc::new(AtomicUsize::new(0));
1120 let request_sent_clone = request_sent.clone();
1121 let _handle = tokio::spawn(async move {
1122 for _ in 0..5 {
1123 let req = HeartbeatRequest {
1124 peer: Some(Peer {
1125 id: 1,
1126 addr: "meta_client_peer".to_string(),
1127 }),
1128 ..Default::default()
1129 };
1130 sender.send(req).await.unwrap();
1131 request_sent_clone.fetch_add(1, Ordering::Relaxed);
1132 }
1133 });
1134
1135 let heartbeat_count = Arc::new(AtomicUsize::new(0));
1136 let heartbeat_count_clone = heartbeat_count.clone();
1137 let handle = tokio::spawn(async move {
1138 while let Some(_resp) = receiver.message().await.unwrap() {
1139 heartbeat_count_clone.fetch_add(1, Ordering::Relaxed);
1140 }
1141 });
1142
1143 handle.await.unwrap();
1144 assert_eq!(
1146 request_sent.load(Ordering::Relaxed) + 1,
1147 heartbeat_count.load(Ordering::Relaxed)
1148 );
1149 }
1150
1151 #[tokio::test]
1152 async fn test_range_get() {
1153 let tc = new_client("test_range_get").await;
1154 tc.gen_data().await;
1155
1156 let key = tc.key("key-0");
1157 let req = RangeRequest::new().with_key(key.as_slice());
1158 let res = tc.client.range(req).await;
1159 let mut kvs = res.unwrap().take_kvs();
1160 assert_eq!(1, kvs.len());
1161 let mut kv = kvs.pop().unwrap();
1162 assert_eq!(key, kv.take_key());
1163 assert_eq!(b"value-0".to_vec(), kv.take_value());
1164 }
1165
1166 #[tokio::test]
1167 async fn test_range_get_prefix() {
1168 let tc = new_client("test_range_get_prefix").await;
1169 tc.gen_data().await;
1170
1171 let req = RangeRequest::new().with_prefix(tc.key("key-"));
1172 let res = tc.client.range(req).await;
1173 let kvs = res.unwrap().take_kvs();
1174 assert_eq!(10, kvs.len());
1175 for (i, mut kv) in kvs.into_iter().enumerate() {
1176 assert_eq!(tc.key(&format!("key-{i}")), kv.take_key());
1177 assert_eq!(format!("{}-{}", "value", i).into_bytes(), kv.take_value());
1178 }
1179 }
1180
1181 #[tokio::test]
1182 async fn test_range() {
1183 let tc = new_client("test_range").await;
1184 tc.gen_data().await;
1185
1186 let req = RangeRequest::new().with_range(tc.key("key-5"), tc.key("key-8"));
1187 let res = tc.client.range(req).await;
1188 let kvs = res.unwrap().take_kvs();
1189 assert_eq!(3, kvs.len());
1190 for (i, mut kv) in kvs.into_iter().enumerate() {
1191 assert_eq!(tc.key(&format!("key-{}", i + 5)), kv.take_key());
1192 assert_eq!(
1193 format!("{}-{}", "value", i + 5).into_bytes(),
1194 kv.take_value()
1195 );
1196 }
1197 }
1198
1199 #[tokio::test]
1200 async fn test_range_keys_only() {
1201 let tc = new_client("test_range_keys_only").await;
1202 tc.gen_data().await;
1203
1204 let req = RangeRequest::new()
1205 .with_range(tc.key("key-5"), tc.key("key-8"))
1206 .with_keys_only();
1207 let res = tc.client.range(req).await;
1208 let kvs = res.unwrap().take_kvs();
1209 assert_eq!(3, kvs.len());
1210 for (i, mut kv) in kvs.into_iter().enumerate() {
1211 assert_eq!(tc.key(&format!("key-{}", i + 5)), kv.take_key());
1212 assert!(kv.take_value().is_empty());
1213 }
1214 }
1215
1216 #[tokio::test]
1217 async fn test_put() {
1218 let tc = new_client("test_put").await;
1219
1220 let req = PutRequest::new()
1221 .with_key(tc.key("key"))
1222 .with_value(b"value".to_vec());
1223 let res = tc.client.put(req).await;
1224 assert!(res.unwrap().prev_kv.is_none());
1225 }
1226
1227 #[tokio::test]
1228 async fn test_put_with_prev_kv() {
1229 let tc = new_client("test_put_with_prev_kv").await;
1230
1231 let key = tc.key("key");
1232 let req = PutRequest::new()
1233 .with_key(key.as_slice())
1234 .with_value(b"value".to_vec())
1235 .with_prev_kv();
1236 let res = tc.client.put(req).await;
1237 assert!(res.unwrap().prev_kv.is_none());
1238
1239 let req = PutRequest::new()
1240 .with_key(key.as_slice())
1241 .with_value(b"value1".to_vec())
1242 .with_prev_kv();
1243 let res = tc.client.put(req).await;
1244 let mut kv = res.unwrap().prev_kv.unwrap();
1245 assert_eq!(key, kv.take_key());
1246 assert_eq!(b"value".to_vec(), kv.take_value());
1247 }
1248
1249 #[tokio::test]
1250 async fn test_batch_put() {
1251 let tc = new_client("test_batch_put").await;
1252
1253 let mut req = BatchPutRequest::new();
1254 for i in 0..275 {
1255 req = req.add_kv(
1256 tc.key(&format!("key-{}", i)),
1257 format!("value-{}", i).into_bytes(),
1258 );
1259 }
1260
1261 let res = tc.client.batch_put(req).await;
1262 assert_eq!(0, res.unwrap().take_prev_kvs().len());
1263
1264 let req = RangeRequest::new().with_prefix(tc.key("key-"));
1265 let res = tc.client.range(req).await;
1266 let kvs = res.unwrap().take_kvs();
1267 assert_eq!(275, kvs.len());
1268 }
1269
1270 #[tokio::test]
1271 async fn test_batch_get() {
1272 let tc = new_client("test_batch_get").await;
1273 tc.gen_data().await;
1274
1275 let mut req = BatchGetRequest::default();
1276 for i in 0..256 {
1277 req = req.add_key(tc.key(&format!("key-{}", i)));
1278 }
1279 let res = tc.client.batch_get(req).await.unwrap();
1280 assert_eq!(10, res.kvs.len());
1281
1282 let req = BatchGetRequest::default()
1283 .add_key(tc.key("key-1"))
1284 .add_key(tc.key("key-999"));
1285 let res = tc.client.batch_get(req).await.unwrap();
1286 assert_eq!(1, res.kvs.len());
1287 }
1288
1289 #[tokio::test]
1290 async fn test_batch_put_with_prev_kv() {
1291 let tc = new_client("test_batch_put_with_prev_kv").await;
1292
1293 let key = tc.key("key");
1294 let key2 = tc.key("key2");
1295 let req = BatchPutRequest::new().add_kv(key.as_slice(), b"value".to_vec());
1296 let res = tc.client.batch_put(req).await;
1297 assert_eq!(0, res.unwrap().take_prev_kvs().len());
1298
1299 let req = BatchPutRequest::new()
1300 .add_kv(key.as_slice(), b"value-".to_vec())
1301 .add_kv(key2.as_slice(), b"value2-".to_vec())
1302 .with_prev_kv();
1303 let res = tc.client.batch_put(req).await;
1304 let mut kvs = res.unwrap().take_prev_kvs();
1305 assert_eq!(1, kvs.len());
1306 let mut kv = kvs.pop().unwrap();
1307 assert_eq!(key, kv.take_key());
1308 assert_eq!(b"value".to_vec(), kv.take_value());
1309 }
1310
1311 #[tokio::test]
1312 async fn test_compare_and_put() {
1313 let tc = new_client("test_compare_and_put").await;
1314
1315 let key = tc.key("key");
1316 let req = CompareAndPutRequest::new()
1317 .with_key(key.as_slice())
1318 .with_expect(b"expect".to_vec())
1319 .with_value(b"value".to_vec());
1320 let res = tc.client.compare_and_put(req).await;
1321 assert!(!res.unwrap().is_success());
1322
1323 let req = CompareAndPutRequest::new()
1325 .with_key(key.as_slice())
1326 .with_value(b"value".to_vec());
1327 let res = tc.client.compare_and_put(req).await;
1328 let mut res = res.unwrap();
1329 assert!(res.is_success());
1330 assert!(res.take_prev_kv().is_none());
1331
1332 let req = CompareAndPutRequest::new()
1334 .with_key(key.as_slice())
1335 .with_expect(b"not_eq".to_vec())
1336 .with_value(b"value2".to_vec());
1337 let res = tc.client.compare_and_put(req).await;
1338 let mut res = res.unwrap();
1339 assert!(!res.is_success());
1340 assert_eq!(b"value".to_vec(), res.take_prev_kv().unwrap().take_value());
1341
1342 let req = CompareAndPutRequest::new()
1344 .with_key(key.as_slice())
1345 .with_expect(b"value".to_vec())
1346 .with_value(b"value2".to_vec());
1347 let res = tc.client.compare_and_put(req).await;
1348 let mut res = res.unwrap();
1349 assert!(res.is_success());
1350
1351 assert!(res.take_prev_kv().is_none());
1353 }
1354
1355 #[tokio::test]
1356 async fn test_delete_with_key() {
1357 let tc = new_client("test_delete_with_key").await;
1358 tc.gen_data().await;
1359
1360 let req = DeleteRangeRequest::new()
1361 .with_key(tc.key("key-0"))
1362 .with_prev_kv();
1363 let res = tc.client.delete_range(req).await;
1364 let mut res = res.unwrap();
1365 assert_eq!(1, res.deleted());
1366 let mut kvs = res.take_prev_kvs();
1367 assert_eq!(1, kvs.len());
1368 let mut kv = kvs.pop().unwrap();
1369 assert_eq!(b"value-0".to_vec(), kv.take_value());
1370 }
1371
1372 #[tokio::test]
1373 async fn test_delete_with_prefix() {
1374 let tc = new_client("test_delete_with_prefix").await;
1375 tc.gen_data().await;
1376
1377 let req = DeleteRangeRequest::new()
1378 .with_prefix(tc.key("key-"))
1379 .with_prev_kv();
1380 let res = tc.client.delete_range(req).await;
1381 let mut res = res.unwrap();
1382 assert_eq!(10, res.deleted());
1383 let kvs = res.take_prev_kvs();
1384 assert_eq!(10, kvs.len());
1385 for (i, mut kv) in kvs.into_iter().enumerate() {
1386 assert_eq!(format!("{}-{}", "value", i).into_bytes(), kv.take_value());
1387 }
1388 }
1389
1390 #[tokio::test]
1391 async fn test_delete_with_range() {
1392 let tc = new_client("test_delete_with_range").await;
1393 tc.gen_data().await;
1394
1395 let req = DeleteRangeRequest::new()
1396 .with_range(tc.key("key-2"), tc.key("key-7"))
1397 .with_prev_kv();
1398 let res = tc.client.delete_range(req).await;
1399 let mut res = res.unwrap();
1400 assert_eq!(5, res.deleted());
1401 let kvs = res.take_prev_kvs();
1402 assert_eq!(5, kvs.len());
1403 for (i, mut kv) in kvs.into_iter().enumerate() {
1404 assert_eq!(
1405 format!("{}-{}", "value", i + 2).into_bytes(),
1406 kv.take_value()
1407 );
1408 }
1409 }
1410
1411 fn mock_decoder(kv: KeyValue) -> MetaResult<Vec<u8>> {
1412 Ok(kv.value)
1413 }
1414
1415 struct RecordingKvBackend {
1416 inner: KvBackendRef,
1417 limits: Arc<Mutex<Vec<i64>>>,
1418 }
1419
1420 #[async_trait::async_trait]
1421 impl TxnService for RecordingKvBackend {
1422 type Error = meta_error::Error;
1423 }
1424
1425 #[async_trait::async_trait]
1426 impl KvBackend for RecordingKvBackend {
1427 fn name(&self) -> &str {
1428 "RecordingKvBackend"
1429 }
1430
1431 fn as_any(&self) -> &dyn std::any::Any {
1432 self
1433 }
1434
1435 async fn range(&self, req: RangeRequest) -> MetaResult<RangeResponse> {
1436 self.limits.lock().unwrap().push(req.limit);
1437 self.inner.range(req).await
1438 }
1439
1440 async fn put(&self, req: PutRequest) -> MetaResult<PutResponse> {
1441 self.inner.put(req).await
1442 }
1443
1444 async fn batch_put(&self, req: BatchPutRequest) -> MetaResult<BatchPutResponse> {
1445 self.inner.batch_put(req).await
1446 }
1447
1448 async fn batch_get(&self, req: BatchGetRequest) -> MetaResult<BatchGetResponse> {
1449 self.inner.batch_get(req).await
1450 }
1451
1452 async fn delete_range(&self, req: DeleteRangeRequest) -> MetaResult<DeleteRangeResponse> {
1453 self.inner.delete_range(req).await
1454 }
1455
1456 async fn batch_delete(&self, req: BatchDeleteRequest) -> MetaResult<BatchDeleteResponse> {
1457 self.inner.batch_delete(req).await
1458 }
1459 }
1460
1461 async fn adaptive_range_with_message_sizes(
1462 server_max_recv_message_size: ReadableSize,
1463 server_max_send_message_size: ReadableSize,
1464 client_max_recv_message_size: ReadableSize,
1465 client_max_send_message_size: ReadableSize,
1466 ) -> (Vec<Vec<u8>>, Vec<Vec<u8>>, Vec<i64>) {
1467 let tx = TestClient::new_with_grpc_message_sizes(
1468 "test_cluster_client",
1469 server_max_recv_message_size,
1470 server_max_send_message_size,
1471 client_max_recv_message_size,
1472 client_max_send_message_size,
1473 )
1474 .await;
1475 let in_memory = tx.in_memory().unwrap();
1476 let cluster_client = tx.client.cluster_client().unwrap();
1477 let mut rng = rand::rng();
1478
1479 let mut expected = Vec::new();
1480 for i in 0..4 {
1481 let data: Vec<u8> = (0..256 * 1024).map(|_| rng.random::<u8>()).collect();
1482 in_memory
1483 .put(
1484 PutRequest::new()
1485 .with_key(format!("__prefix/{i}").as_bytes())
1486 .with_value(data.clone()),
1487 )
1488 .await
1489 .unwrap();
1490 expected.push(data);
1491 }
1492
1493 let req = RangeRequest::new().with_prefix(b"__prefix/");
1494 let limits = Arc::new(Mutex::new(Vec::new()));
1495 let recording_backend = RecordingKvBackend {
1496 inner: Arc::new(cluster_client),
1497 limits: limits.clone(),
1498 };
1499 let stream =
1500 PaginationStream::new(Arc::new(recording_backend), req, 4, mock_decoder).into_stream();
1501
1502 let res = stream.try_collect::<Vec<_>>().await.unwrap();
1503 let limits = limits.lock().unwrap().clone();
1504 (expected, res, limits)
1505 }
1506
1507 #[tokio::test]
1508 async fn test_cluster_client_adaptive_range() {
1509 let (expected, res, limits) = adaptive_range_with_message_sizes(
1510 ReadableSize::mb(2),
1511 ReadableSize::mb(16),
1512 ReadableSize::mb(1),
1513 ReadableSize::mb(2),
1514 )
1515 .await;
1516
1517 assert_eq!(expected, res);
1518 assert_eq!(vec![4, 2, 2], limits);
1519 }
1520
1521 #[tokio::test]
1522 async fn test_cluster_client_adaptive_range_server_limit() {
1523 let (expected, res, limits) = adaptive_range_with_message_sizes(
1524 ReadableSize::mb(2),
1525 ReadableSize::mb(1),
1526 ReadableSize::mb(16),
1527 ReadableSize::mb(2),
1528 )
1529 .await;
1530
1531 assert_eq!(expected, res);
1532 assert_eq!(vec![4, 2, 2], limits);
1533 }
1534}