1use std::collections::{BTreeSet, HashMap};
16use std::env;
17use std::net::TcpListener;
18use std::ops::RangeInclusive;
19use std::sync::Arc;
20use std::sync::atomic::{AtomicUsize, Ordering};
21use std::task::{Context, Poll};
22use std::time::Duration;
23
24use api::v1::health_check_server::HealthCheckServer;
25use api::v1::region::region_server::RegionServer;
26use arrow_flight::flight_service_server::FlightServiceServer;
27use cache::{
28 build_datanode_layered_cache_registry, build_fundamental_cache_registry,
29 with_default_composite_cache_registry,
30};
31use catalog::information_extension::DistributedInformationExtension;
32use catalog::kvbackend::{
33 CachedKvBackendBuilder, KvBackendCatalogManagerBuilder, new_read_only_meta_kv_backend,
34};
35use catalog::process_manager::ProcessManager;
36use client::Client;
37use client::client_manager::NodeClients;
38use cmd::frontend::create_heartbeat_task;
39use common_base::Plugins;
40use common_datasource::object_store::LocalFileAccess;
41use common_event_recorder::EventRecorderOptions;
42use common_grpc::channel_manager::{ChannelConfig, ChannelManager};
43use common_meta::DatanodeId;
44use common_meta::cache::{CacheRegistryBuilder, LayeredCacheRegistryBuilder};
45use common_meta::kv_backend::KvBackendRef;
46use common_meta::kv_backend::chroot::ChrootKvBackend;
47use common_meta::kv_backend::etcd::EtcdStore;
48use common_meta::kv_backend::memory::MemoryKvBackend;
49use common_meta::peer::Peer;
50use common_runtime::Builder as RuntimeBuilder;
51use common_runtime::runtime::BuilderBuild;
52use common_test_util::temp_dir::create_temp_dir;
53use common_time::util::DefaultSystemTimer;
54use common_wal::config::{DatanodeWalConfig, MetasrvWalConfig};
55use datanode::config::DatanodeOptions;
56use datanode::datanode::{Datanode, DatanodeBuilder, ProcedureConfig};
57use frontend::frontend::{Frontend, FrontendOptions};
58use frontend::instance::Instance as FeInstance;
59use frontend::instance::builder::FrontendBuilder;
60use frontend::server::Services;
61use futures::TryStreamExt;
62use hyper_util::rt::TokioIo;
63use meta_client::client::MetaClientBuilder;
64use meta_srv::cluster::MetaPeerClientRef;
65use meta_srv::discovery;
66use meta_srv::gc::GcSchedulerOptions;
67use meta_srv::metasrv::{Metasrv, MetasrvOptions, SelectorRef};
68use meta_srv::mocks::MockInfo;
69use mito2::gc::GcConfig;
70use mito2::region::MitoRegionRef;
71use object_store::config::ObjectStoreConfig;
72use rand::Rng;
73use servers::grpc::flight::FlightCraftWrapper;
74use servers::grpc::region_server::RegionServerRequestHandler;
75use servers::grpc::{GrpcOptions, HealthCheckHandler};
76use servers::server::ServerHandlers;
77use store_api::storage::RegionId;
78use tempfile::TempDir;
79use tokio::io::{AsyncRead, AsyncWrite};
80use tonic::codec::CompressionEncoding;
81use tonic::transport::Server;
82use tonic::transport::server::Connected;
83use tower::{Layer, Service, service_fn};
84use uuid::Uuid;
85
86use crate::test_util::{
87 self, FileDirGuard, StorageType, TestGuard, create_datanode_opts,
88 create_tmp_dir_and_datanode_opts,
89};
90
91#[derive(Debug, Default)]
97pub struct DatanodeRpcStats {
98 do_get_requests: AtomicUsize,
99}
100
101impl DatanodeRpcStats {
102 pub fn requests(&self) -> usize {
104 self.do_get_requests.load(Ordering::Relaxed)
105 }
106}
107
108pub struct GreptimeDbCluster {
109 pub guards: Vec<TestGuard>,
110 pub datanode_options: Vec<DatanodeOptions>,
111
112 pub datanode_instances: HashMap<DatanodeId, Datanode>,
113 pub datanode_rpc_stats: HashMap<DatanodeId, Arc<DatanodeRpcStats>>,
116 pub kv_backend: KvBackendRef,
117 pub metasrv: Arc<Metasrv>,
118 pub frontend: Arc<Frontend>,
119}
120
121impl GreptimeDbCluster {
122 pub fn fe_instance(&self) -> &Arc<FeInstance> {
123 &self.frontend.instance
124 }
125
126 pub fn datanode_rpc_stats(&self, datanode_id: DatanodeId) -> Option<&Arc<DatanodeRpcStats>> {
130 self.datanode_rpc_stats.get(&datanode_id)
131 }
132
133 pub async fn list_sst_files_from_all_datanodes(&self) -> BTreeSet<String> {
135 let mut sst_files = BTreeSet::new();
136
137 for datanode in self.datanode_instances.values() {
138 let region_server = datanode.region_server();
139 let mito = region_server.mito_engine().unwrap();
140 let all_files = mito
141 .all_ssts_from_storage()
142 .try_collect::<Vec<_>>()
143 .await
144 .unwrap()
145 .into_iter()
146 .map(|e| e.file_path)
147 .collect::<Vec<_>>();
148 sst_files.extend(all_files);
149 }
150
151 sst_files
152 }
153
154 pub async fn list_sst_files_from_manifests(&self) -> BTreeSet<String> {
156 let mut sst_files = BTreeSet::new();
157
158 for datanode in self.datanode_instances.values() {
159 let region_server = datanode.region_server();
160 let mito = region_server.mito_engine().unwrap();
161 let all_files = mito
162 .all_ssts_from_manifest()
163 .await
164 .into_iter()
165 .flat_map(|e| {
166 if let Some(index_file_path) = e.index_file_path {
167 vec![e.file_path, index_file_path]
168 } else {
169 vec![e.file_path]
170 }
171 })
172 .collect::<BTreeSet<_>>();
173
174 sst_files.extend(all_files);
175 }
176
177 sst_files
178 }
179
180 pub async fn list_all_regions(&self) -> HashMap<RegionId, MitoRegionRef> {
181 let mut regions = HashMap::new();
182
183 for datanode in self.datanode_instances.values() {
184 let region_server = datanode.region_server();
185 let mito = region_server.mito_engine().unwrap();
186 for region in mito.regions() {
187 regions.insert(region.region_id(), region);
188 }
189 }
190
191 regions
192 }
193}
194
195pub struct GreptimeDbClusterBuilder {
196 cluster_name: String,
197 kv_backend: KvBackendRef,
198 store_config: Option<ObjectStoreConfig>,
199 store_providers: Option<Vec<StorageType>>,
200 datanodes: Option<u32>,
201 datanode_wal_config: DatanodeWalConfig,
202 metasrv_wal_config: MetasrvWalConfig,
203 datanode_gc_config: GcConfig,
204 metasrv_gc_config: GcSchedulerOptions,
205 frontend_auto_create_table: bool,
206 shared_home_dir: Option<Arc<TempDir>>,
207 meta_selector: Option<SelectorRef>,
208 plugins: Plugins,
209 local_file_access: LocalFileAccess,
210 event_recorder_options: EventRecorderOptions,
211 real_datanode_grpc_addr: bool,
212}
213
214impl GreptimeDbClusterBuilder {
215 pub async fn new(cluster_name: &str) -> Self {
216 let endpoints = env::var("GT_ETCD_ENDPOINTS").unwrap_or_default();
217
218 let kv_backend: KvBackendRef = if endpoints.is_empty() {
219 Arc::new(MemoryKvBackend::new())
220 } else {
221 let endpoints = endpoints
222 .split(',')
223 .map(|s| s.to_string())
224 .collect::<Vec<String>>();
225 let backend = EtcdStore::with_endpoints(endpoints, 128)
226 .await
227 .expect("malformed endpoints");
228 let chroot = format!("{}{}", cluster_name, Uuid::new_v4());
230 Arc::new(ChrootKvBackend::new(chroot.into(), backend))
231 };
232
233 Self {
234 cluster_name: cluster_name.to_string(),
235 kv_backend,
236 store_config: None,
237 store_providers: None,
238 datanodes: None,
239 datanode_wal_config: DatanodeWalConfig::default(),
240 metasrv_wal_config: MetasrvWalConfig::default(),
241 datanode_gc_config: GcConfig::default(),
242 metasrv_gc_config: GcSchedulerOptions::default(),
243 frontend_auto_create_table: true,
244 shared_home_dir: None,
245 meta_selector: None,
246 plugins: Plugins::default(),
247 local_file_access: LocalFileAccess::default(),
248 event_recorder_options: EventRecorderOptions::default(),
249 real_datanode_grpc_addr: false,
250 }
251 }
252
253 #[must_use]
254 pub fn with_store_config(mut self, store_config: ObjectStoreConfig) -> Self {
255 self.store_config = Some(store_config);
256 self
257 }
258
259 #[must_use]
260 pub fn with_store_providers(mut self, store_providers: Vec<StorageType>) -> Self {
261 self.store_providers = Some(store_providers);
262 self
263 }
264
265 #[must_use]
266 pub fn with_datanodes(mut self, datanodes: u32) -> Self {
267 self.datanodes = Some(datanodes);
268 self
269 }
270
271 #[must_use]
272 pub fn with_datanode_wal_config(mut self, datanode_wal_config: DatanodeWalConfig) -> Self {
273 self.datanode_wal_config = datanode_wal_config;
274 self
275 }
276
277 #[must_use]
278 pub fn with_metasrv_wal_config(mut self, metasrv_wal_config: MetasrvWalConfig) -> Self {
279 self.metasrv_wal_config = metasrv_wal_config;
280 self
281 }
282
283 #[must_use]
284 pub fn with_datanode_gc_config(mut self, datanode_gc_config: GcConfig) -> Self {
285 self.datanode_gc_config = datanode_gc_config;
286 self
287 }
288
289 pub fn with_metasrv_gc_config(mut self, metasrv_gc_config: GcSchedulerOptions) -> Self {
290 self.metasrv_gc_config = metasrv_gc_config;
291 self
292 }
293
294 #[must_use]
295 pub fn with_event_recorder_options(
296 mut self,
297 event_recorder_options: EventRecorderOptions,
298 ) -> Self {
299 self.event_recorder_options = event_recorder_options;
300 self
301 }
302
303 #[must_use]
305 pub fn with_frontend_auto_create_table(mut self, auto_create_table: bool) -> Self {
306 self.frontend_auto_create_table = auto_create_table;
307 self
308 }
309
310 #[must_use]
311 pub fn with_shared_home_dir(mut self, shared_home_dir: Arc<TempDir>) -> Self {
312 self.shared_home_dir = Some(shared_home_dir);
313 self
314 }
315
316 #[must_use]
317 pub fn with_meta_selector(mut self, selector: SelectorRef) -> Self {
318 self.meta_selector = Some(selector);
319 self
320 }
321
322 #[must_use]
324 pub fn with_plugins(mut self, plugins: Plugins) -> Self {
325 self.plugins = plugins;
326 self
327 }
328
329 pub fn with_local_file_access(mut self, access: LocalFileAccess) -> Self {
331 self.local_file_access = access;
332 self
333 }
334
335 #[must_use]
345 pub fn with_real_datanode_grpc_addr(mut self, real_datanode_grpc_addr: bool) -> Self {
346 self.real_datanode_grpc_addr = real_datanode_grpc_addr;
347 self
348 }
349
350 pub async fn build_with(
351 &self,
352 datanode_options: Vec<DatanodeOptions>,
353 start_frontend_servers: bool,
354 guards: Vec<TestGuard>,
355 ) -> GreptimeDbCluster {
356 let datanodes = datanode_options.len();
357
358 let channel_config = ChannelConfig::new().timeout(Some(Duration::from_secs(20)));
359 let datanode_clients = Arc::new(NodeClients::new(channel_config));
360
361 let opt = MetasrvOptions {
362 procedure: ProcedureConfig {
363 max_retry_times: 5,
366 retry_delay: Duration::from_secs(1),
367 max_metadata_value_size: None,
368 max_running_procedures: 128,
369 },
370 wal: self.metasrv_wal_config.clone(),
371 grpc: GrpcOptions {
372 server_addr: "127.0.0.1:3002".to_string(),
373 ..Default::default()
374 },
375 gc: self.metasrv_gc_config.clone(),
376 event_recorder: self.event_recorder_options.clone(),
377 ..Default::default()
378 };
379
380 test_util::prepare_another_catalog_and_schema_with_kv_backend(self.kv_backend.clone())
381 .await;
382
383 let metasrv = meta_srv::mocks::mock_with_plugins(
384 opt,
385 self.kv_backend.clone(),
386 self.meta_selector.clone(),
387 Some(datanode_clients.clone()),
388 None,
389 self.plugins.clone(),
390 )
391 .await;
392
393 let datanode_instances = self
394 .build_datanodes_with_options(&metasrv, &datanode_options)
395 .await;
396
397 let datanode_rpc_stats = if self.real_datanode_grpc_addr {
398 datanode_options
399 .iter()
400 .map(|opts| (opts.node_id.unwrap(), Arc::new(DatanodeRpcStats::default())))
401 .collect::<HashMap<_, _>>()
402 } else {
403 HashMap::new()
404 };
405
406 build_datanode_clients(
407 datanode_clients.clone(),
408 &datanode_instances,
409 &datanode_options,
410 &datanode_rpc_stats,
411 )
412 .await;
413
414 self.wait_datanodes_alive(metasrv.metasrv.meta_peer_client(), datanodes)
415 .await;
416
417 let mut frontend = self
418 .build_frontend(
419 metasrv.clone(),
420 datanode_clients.clone(),
421 start_frontend_servers,
422 )
423 .await;
424
425 frontend.start().await.unwrap();
426
427 GreptimeDbCluster {
428 datanode_options,
429 guards,
430 datanode_instances,
431 datanode_rpc_stats,
432 kv_backend: self.kv_backend.clone(),
433 metasrv: metasrv.metasrv,
434 frontend: Arc::new(frontend),
435 }
436 }
437
438 pub async fn build(&self, start_frontend_servers: bool) -> GreptimeDbCluster {
439 let datanodes = self.datanodes.unwrap_or(4);
440 let (datanode_options, guards) = self.build_datanode_options_and_guards(datanodes).await;
441 self.build_with(datanode_options, start_frontend_servers, guards)
442 .await
443 }
444
445 async fn build_datanode_options_and_guards(
446 &self,
447 datanodes: u32,
448 ) -> (Vec<DatanodeOptions>, Vec<TestGuard>) {
449 let mut options = Vec::with_capacity(datanodes as usize);
450 let mut guards = Vec::with_capacity(datanodes as usize);
451
452 for i in 0..datanodes {
453 let datanode_id = i as u64 + 1;
454 let mut opts = if let Some(store_config) = &self.store_config {
455 let home_dir = if let Some(home_dir) = &self.shared_home_dir {
456 home_dir.path().to_str().unwrap().to_string()
457 } else {
458 let home_tmp_dir = create_temp_dir(&format!("gt_home_{}", self.cluster_name));
459 let home_dir = home_tmp_dir.path().to_str().unwrap().to_string();
460 guards.push(TestGuard {
461 home_guard: FileDirGuard::new(home_tmp_dir),
462 storage_guards: Vec::new(),
463 });
464
465 home_dir
466 };
467
468 create_datanode_opts(
469 store_config.clone(),
470 vec![],
471 home_dir,
472 self.datanode_wal_config.clone(),
473 self.datanode_gc_config.clone(),
474 )
475 } else {
476 let (opts, guard) = create_tmp_dir_and_datanode_opts(
477 StorageType::File,
478 self.store_providers.clone().unwrap_or_default(),
479 &format!("{}-dn-{}", self.cluster_name, datanode_id),
480 self.datanode_wal_config.clone(),
481 self.datanode_gc_config.clone(),
482 );
483 guards.push(guard);
484
485 opts
486 };
487 opts.node_id = Some(datanode_id);
488 if self.real_datanode_grpc_addr {
489 let addr = self.choose_datanode_grpc_addr();
492 opts.grpc.bind_addr = addr.clone();
493 opts.grpc.server_addr = addr;
494 }
495 options.push(opts);
496 }
497 (options, guards)
498 }
499
500 fn choose_datanode_grpc_addr(&self) -> String {
505 let localhost = "127.0.0.1";
506 let port = self.choose_random_unused_port(24000..=34000, 20, localhost);
507 format!("{}:{}", localhost, port)
508 }
509
510 async fn build_datanodes_with_options(
511 &self,
512 metasrv: &MockInfo,
513 options: &[DatanodeOptions],
514 ) -> HashMap<DatanodeId, Datanode> {
515 let mut instances = HashMap::with_capacity(options.len());
516
517 for opts in options {
518 let datanode = self.create_datanode(opts.clone(), metasrv.clone()).await;
519 let datanode_id = opts.node_id.unwrap();
520 instances.insert(datanode_id, datanode);
521 }
522
523 instances
524 }
525
526 async fn wait_datanodes_alive(
527 &self,
528 meta_peer_client: &MetaPeerClientRef,
529 expected_datanodes: usize,
530 ) {
531 for _ in 0..100 {
532 let alive_datanodes = discovery::utils::alive_datanode_infos(
533 &DefaultSystemTimer,
534 meta_peer_client.as_ref(),
535 Duration::from_secs(u64::MAX),
536 None,
537 )
538 .await
539 .unwrap()
540 .len();
541 if alive_datanodes == expected_datanodes {
542 return;
543 }
544 tokio::time::sleep(Duration::from_micros(100)).await
545 }
546 panic!("Some Datanodes are not alive in 10 seconds!")
547 }
548
549 async fn create_datanode(&self, opts: DatanodeOptions, metasrv: MockInfo) -> Datanode {
550 let mut meta_client = MetaClientBuilder::datanode_default_options(opts.node_id.unwrap())
551 .channel_manager(metasrv.channel_manager)
552 .build();
553 meta_client.start(&[&metasrv.server_addr]).await.unwrap();
554 let meta_client = Arc::new(meta_client);
555
556 let meta_backend = new_read_only_meta_kv_backend(meta_client.clone());
557
558 let layered_cache_registry =
559 Arc::new(build_datanode_layered_cache_registry(meta_backend.clone()));
560
561 let mut builder = DatanodeBuilder::new(opts.clone(), Plugins::default(), meta_backend);
562 builder
563 .with_cache_registry(layered_cache_registry.clone())
564 .with_meta_client(meta_client);
565 let mut datanode = builder.build().await.unwrap();
566
567 datanode.start_heartbeat().await.unwrap();
568
569 datanode
570 }
571
572 async fn build_frontend(
573 &self,
574 metasrv: MockInfo,
575 datanode_clients: Arc<NodeClients>,
576 start_frontend_servers: bool,
577 ) -> Frontend {
578 let mut meta_client = MetaClientBuilder::frontend_default_options()
579 .channel_manager(metasrv.channel_manager)
580 .enable_access_cluster_info()
581 .build();
582 meta_client.start(&[&metasrv.server_addr]).await.unwrap();
583 let meta_client = Arc::new(meta_client);
584
585 let readonly_meta_backend = new_read_only_meta_kv_backend(meta_client.clone());
586 let cached_meta_backend =
587 Arc::new(CachedKvBackendBuilder::new(readonly_meta_backend.clone()).build());
588
589 let layered_cache_builder = LayeredCacheRegistryBuilder::default().add_cache_registry(
590 CacheRegistryBuilder::default()
591 .add_cache(cached_meta_backend.clone())
592 .build(),
593 );
594 let fundamental_cache_registry =
595 build_fundamental_cache_registry(readonly_meta_backend.clone());
596 let cache_registry = Arc::new(
597 with_default_composite_cache_registry(
598 layered_cache_builder.add_cache_registry(fundamental_cache_registry),
599 )
600 .unwrap()
601 .build(),
602 );
603
604 let information_extension = Arc::new(DistributedInformationExtension::new(
605 meta_client.clone(),
606 datanode_clients.clone(),
607 ));
608 let catalog_manager = KvBackendCatalogManagerBuilder::new(
609 information_extension,
610 cached_meta_backend.clone(),
611 cache_registry.clone(),
612 )
613 .build();
614
615 let fe_opts = self.build_frontend_options();
616
617 let instance = FrontendBuilder::new(
618 fe_opts.clone(),
619 cached_meta_backend.clone(),
620 cache_registry.clone(),
621 catalog_manager,
622 datanode_clients,
623 meta_client.clone(),
624 Arc::new(ProcessManager::new(fe_opts.grpc.server_addr.clone(), None)),
625 )
626 .with_local_file_access(self.local_file_access.clone())
627 .with_local_cache_invalidator(cache_registry)
628 .try_build()
629 .await
630 .unwrap();
631
632 let heartbeat_task = create_heartbeat_task(&fe_opts, meta_client, &instance);
633
634 let instance = Arc::new(instance);
635
636 let servers = if start_frontend_servers {
638 Services::new(fe_opts, instance.clone(), Plugins::default())
639 .build()
640 .unwrap()
641 } else {
642 ServerHandlers::default()
643 };
644
645 Frontend {
646 instance,
647 servers,
648 heartbeat_task: Some(heartbeat_task),
649 }
650 }
651
652 fn build_frontend_options(&self) -> FrontendOptions {
653 let mut fe_opts = FrontendOptions {
654 auto_create_table: self.frontend_auto_create_table,
655 event_recorder: self.event_recorder_options.clone(),
656 ..Default::default()
657 };
658
659 let port_range = 14000..=24000;
661 let max_attempts = 10;
662 let localhost = "127.0.0.1";
663 let construct_addr = |port: u16| format!("{}:{}", localhost, port);
664
665 fe_opts.http.addr = construct_addr(self.choose_random_unused_port(
666 port_range.clone(),
667 max_attempts,
668 localhost,
669 ));
670
671 let grpc_port = self.choose_random_unused_port(port_range.clone(), max_attempts, localhost);
672 fe_opts.grpc.bind_addr = construct_addr(grpc_port);
673 fe_opts.grpc.server_addr = construct_addr(grpc_port);
674
675 fe_opts.mysql.addr = construct_addr(self.choose_random_unused_port(
676 port_range.clone(),
677 max_attempts,
678 localhost,
679 ));
680 fe_opts.postgres.addr =
681 construct_addr(self.choose_random_unused_port(port_range, max_attempts, localhost));
682
683 fe_opts
684 }
685
686 fn choose_random_unused_port(
688 &self,
689 port_range: RangeInclusive<u16>,
690 max_attempts: u16,
691 addr: &str,
692 ) -> u16 {
693 let mut rng = rand::rng();
694
695 let mut attempts = 0;
696 while attempts < max_attempts {
697 let port = rng.random_range(port_range.clone());
698 if TcpListener::bind(format!("{}:{}", addr, port)).is_ok() {
699 return port;
700 }
701 attempts += 1;
702 }
703
704 panic!("No unused port found");
705 }
706}
707
708async fn build_datanode_clients(
709 clients: Arc<NodeClients>,
710 instances: &HashMap<DatanodeId, Datanode>,
711 options: &[DatanodeOptions],
712 rpc_stats: &HashMap<DatanodeId, Arc<DatanodeRpcStats>>,
713) {
714 for opts in options {
715 let datanode_id = opts.node_id.unwrap();
716 let instance = &instances[&datanode_id];
717 let (addr, client) = create_datanode_client(
718 instance,
719 &opts.grpc.server_addr,
720 rpc_stats.get(&datanode_id).cloned(),
721 )
722 .await;
723 clients
724 .insert_client(Peer::new(datanode_id, addr), client)
725 .await;
726 }
727}
728
729fn serve_datanode_region_server<I, IO>(
732 datanode: &Datanode,
733 incoming: I,
734 rpc_stats: Option<Arc<DatanodeRpcStats>>,
735) where
736 I: futures::Stream<Item = Result<IO, std::io::Error>> + Send + 'static,
737 IO: AsyncRead + AsyncWrite + Connected + Unpin + Send + 'static,
738{
739 let runtime = RuntimeBuilder::default()
740 .worker_threads(2)
741 .thread_name("grpc-handlers")
742 .build()
743 .unwrap();
744
745 let flight_handler = FlightCraftWrapper(datanode.region_server());
746 let region_server_handler =
747 RegionServerRequestHandler::new(Arc::new(datanode.region_server()), runtime);
748
749 tokio::spawn(async move {
750 Server::builder()
751 .layer(CountRequestsLayer { rpc_stats })
752 .add_service(
753 FlightServiceServer::new(flight_handler)
754 .accept_compressed(CompressionEncoding::Gzip)
755 .accept_compressed(CompressionEncoding::Zstd)
756 .send_compressed(CompressionEncoding::Gzip)
757 .send_compressed(CompressionEncoding::Zstd),
758 )
759 .add_service(
760 RegionServer::new(region_server_handler)
761 .accept_compressed(CompressionEncoding::Gzip)
762 .accept_compressed(CompressionEncoding::Zstd)
763 .send_compressed(CompressionEncoding::Gzip)
764 .send_compressed(CompressionEncoding::Zstd),
765 )
766 .add_service(HealthCheckServer::new(HealthCheckHandler))
767 .serve_with_incoming(incoming)
768 .await
769 });
770}
771
772async fn create_datanode_client(
783 datanode: &Datanode,
784 addr: &str,
785 rpc_stats: Option<Arc<DatanodeRpcStats>>,
786) -> (String, Client) {
787 let (client, server) = tokio::io::duplex(1024);
788 serve_datanode_region_server(
789 datanode,
790 futures::stream::iter(vec![Ok::<_, std::io::Error>(server)]),
791 None,
792 );
793
794 if addr != test_util::PEER_PLACEHOLDER_ADDR {
795 let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
796 let incoming = tokio_stream::wrappers::TcpListenerStream::new(listener);
797 serve_datanode_region_server(datanode, incoming, rpc_stats);
798 }
799
800 let mut client = Some(client);
801 let channel_manager = ChannelManager::new();
802 channel_manager
803 .reset_with_connector(
804 addr,
805 service_fn(move |_| {
806 let client = client.take();
807
808 async move {
809 client
810 .map(TokioIo::new)
811 .ok_or_else(|| std::io::Error::other("Client already taken"))
812 }
813 }),
814 )
815 .unwrap();
816
817 (
818 addr.to_string(),
819 Client::with_query_and_control_managers(channel_manager.clone(), channel_manager, [addr]),
822 )
823}
824
825#[derive(Clone)]
827struct CountRequests<S> {
828 inner: S,
829 rpc_stats: Option<Arc<DatanodeRpcStats>>,
830}
831
832impl<S, ReqBody> Service<http::Request<ReqBody>> for CountRequests<S>
833where
834 S: Service<http::Request<ReqBody>>,
835{
836 type Response = S::Response;
837 type Error = S::Error;
838 type Future = S::Future;
839
840 fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
841 self.inner.poll_ready(cx)
842 }
843
844 fn call(&mut self, request: http::Request<ReqBody>) -> Self::Future {
845 if request.uri().path() == "/arrow.flight.protocol.FlightService/DoGet"
846 && let Some(rpc_stats) = &self.rpc_stats
847 {
848 rpc_stats.do_get_requests.fetch_add(1, Ordering::Relaxed);
849 }
850
851 self.inner.call(request)
852 }
853}
854
855#[derive(Clone)]
856struct CountRequestsLayer {
857 rpc_stats: Option<Arc<DatanodeRpcStats>>,
858}
859
860impl<S> Layer<S> for CountRequestsLayer {
861 type Service = CountRequests<S>;
862
863 fn layer(&self, inner: S) -> Self::Service {
864 CountRequests {
865 inner,
866 rpc_stats: self.rpc_stats.clone(),
867 }
868 }
869}
870
871#[cfg(test)]
873#[allow(deprecated)]
874mod tests {
875 use std::sync::atomic::{AtomicBool, Ordering};
876
877 use api::v1::flow::FlowRequest;
878 use api::v1::region::{
879 ListMetadataRequest, RegionRequest, RegionRequestHeader, region_request,
880 };
881 use catalog::memory::new_memory_catalog_manager;
882 use client::Client;
883 use common_error::ext::ErrorExt;
884 use common_error::status_code::StatusCode;
885 use common_meta::ddl_manager::{DdlManager, DdlManagerConfigurator, DdlManagerConfiguratorRef};
886 use common_meta::key::TableMetadataManager;
887 use common_meta::key::flow::FlowMetadataManager;
888 use common_meta::kv_backend::memory::MemoryKvBackend;
889 use common_meta::node_manager::{DatanodeManager, FlownodeManager};
890 use common_meta::peer::Peer;
891 use flow::{FlownodeBuilder, FlownodeOptions, FlownodeServiceBuilder, FrontendClient};
892 use meta_srv::metasrv::builder::DdlManagerConfigureContext;
893
894 use super::*;
895
896 const HEALTH_REFRESH_INTERVAL: Duration = Duration::from_millis(10);
897 const HEALTH_REFRESH_TIMEOUT: Duration = Duration::from_secs(5);
898
899 async fn wait_for_active_route(client: &Client, active_addr: &str) {
900 client.find_channel().unwrap();
901 tokio::time::timeout(HEALTH_REFRESH_TIMEOUT, async {
902 let mut interval = tokio::time::interval(HEALTH_REFRESH_INTERVAL);
903 loop {
904 interval.tick().await;
905 let (active, inactive) = client.peer_addresses_by_state();
906 if active.len() == 1 && active[0] == active_addr && inactive.len() == 1 {
907 return;
908 }
909 }
910 })
911 .await
912 .expect("background health routing did not select the active peer");
913 }
914
915 async fn create_region_requester_health_client(datanode: &Datanode) -> (Peer, Peer, Client) {
916 const ACTIVE_ADDR: &str = "127.0.0.1:3001";
917 const INACTIVE_ADDR: &str = "127.0.0.1:3002";
918
919 let (active_client, server) = tokio::io::duplex(1024);
920 let runtime = RuntimeBuilder::default()
921 .worker_threads(2)
922 .thread_name("grpc-handlers")
923 .build()
924 .unwrap();
925 let region_server_handler =
926 RegionServerRequestHandler::new(Arc::new(datanode.region_server()), runtime);
927
928 tokio::spawn(async move {
929 Server::builder()
930 .add_service(RegionServer::new(region_server_handler))
931 .add_service(HealthCheckServer::new(HealthCheckHandler))
932 .serve_with_incoming(futures::stream::iter(vec![Ok::<_, std::io::Error>(server)]))
933 .await
934 });
935
936 let channel_manager = ChannelManager::new();
937 let mut active_client = Some(active_client);
938 channel_manager
939 .reset_with_connector(
940 ACTIVE_ADDR,
941 service_fn(move |_| {
942 let client = active_client.take();
943
944 async move {
945 client
946 .map(TokioIo::new)
947 .ok_or_else(|| std::io::Error::other("Active client already taken"))
948 }
949 }),
950 )
951 .unwrap();
952 channel_manager
953 .reset_with_connector(
954 INACTIVE_ADDR,
955 service_fn(|_| async {
956 Err::<TokioIo<tokio::io::DuplexStream>, _>(std::io::Error::other(
957 "Inactive synthetic peer",
958 ))
959 }),
960 )
961 .unwrap();
962
963 let client = Client::with_manager_and_urls_and_options(
964 channel_manager,
965 [INACTIVE_ADDR, ACTIVE_ADDR],
966 client::ClientOptions {
967 health_check_interval: HEALTH_REFRESH_INTERVAL,
968 ..Default::default()
969 },
970 );
971 (
972 Peer::new(1, ACTIVE_ADDR),
973 Peer::new(2, INACTIVE_ADDR),
974 client,
975 )
976 }
977
978 async fn create_flow_requester_health_client(
979 flownode: &flow::FlownodeInstance,
980 ) -> (Peer, Peer, Client) {
981 const ACTIVE_ADDR: &str = "127.0.0.1:3003";
982 const INACTIVE_ADDR: &str = "127.0.0.1:3004";
983
984 let (active_client, server) = tokio::io::duplex(1024);
985 let flow_service = flownode.flownode_server().create_flow_service();
986
987 tokio::spawn(async move {
988 Server::builder()
989 .add_service(flow_service)
990 .add_service(HealthCheckServer::new(HealthCheckHandler))
991 .serve_with_incoming(futures::stream::iter(vec![Ok::<_, std::io::Error>(server)]))
992 .await
993 });
994
995 let channel_manager = ChannelManager::new();
996 let mut active_client = Some(active_client);
997 channel_manager
998 .reset_with_connector(
999 ACTIVE_ADDR,
1000 service_fn(move |_| {
1001 let client = active_client.take();
1002
1003 async move {
1004 client
1005 .map(TokioIo::new)
1006 .ok_or_else(|| std::io::Error::other("Active client already taken"))
1007 }
1008 }),
1009 )
1010 .unwrap();
1011 channel_manager
1012 .reset_with_connector(
1013 INACTIVE_ADDR,
1014 service_fn(|_| async {
1015 Err::<TokioIo<tokio::io::DuplexStream>, _>(std::io::Error::other(
1016 "Inactive synthetic peer",
1017 ))
1018 }),
1019 )
1020 .unwrap();
1021
1022 let client = Client::with_manager_and_urls_and_options(
1023 channel_manager,
1024 [INACTIVE_ADDR, ACTIVE_ADDR],
1025 client::ClientOptions {
1026 health_check_interval: HEALTH_REFRESH_INTERVAL,
1027 ..Default::default()
1028 },
1029 );
1030 (
1031 Peer::new(1, ACTIVE_ADDR),
1032 Peer::new(2, INACTIVE_ADDR),
1033 client,
1034 )
1035 }
1036
1037 async fn start_flownode(addr: String) -> flow::FlownodeInstance {
1038 let kv_backend = Arc::new(MemoryKvBackend::new());
1039 let table_meta = Arc::new(TableMetadataManager::new(kv_backend.clone()));
1040 table_meta.init().await.unwrap();
1041 let flow_meta = Arc::new(FlowMetadataManager::new(kv_backend));
1042 let catalog_manager = new_memory_catalog_manager().unwrap();
1043 let (frontend_client, _handler) =
1044 FrontendClient::from_empty_grpc_handler(Default::default());
1045 let mut opts = FlownodeOptions::default();
1046 opts.grpc.bind_addr = addr.clone();
1047 opts.grpc.server_addr = addr;
1048
1049 let mut flownode = FlownodeBuilder::new(
1050 opts.clone(),
1051 Plugins::default(),
1052 table_meta,
1053 catalog_manager,
1054 flow_meta,
1055 Arc::new(frontend_client),
1056 )
1057 .build()
1058 .await
1059 .unwrap();
1060 let services = FlownodeServiceBuilder::new(&opts)
1061 .with_default_grpc_server(flownode.flownode_server())
1062 .build()
1063 .unwrap();
1064 flownode.setup_services(services);
1065 flownode.start().await.unwrap();
1066 flownode
1067 }
1068
1069 struct TestDdlManagerConfigurator(Arc<AtomicBool>);
1070
1071 #[async_trait::async_trait]
1072 impl DdlManagerConfigurator<DdlManagerConfigureContext> for TestDdlManagerConfigurator {
1073 async fn configure(
1074 &self,
1075 ddl_manager: DdlManager,
1076 _ctx: DdlManagerConfigureContext,
1077 ) -> std::result::Result<DdlManager, common_error::ext::BoxedError> {
1078 self.0.store(true, Ordering::SeqCst);
1079 Ok(ddl_manager)
1080 }
1081 }
1082
1083 #[tokio::test(flavor = "multi_thread")]
1084 async fn test_build_cluster_with_plugins() {
1085 let configured = Arc::new(AtomicBool::new(false));
1086 let plugins = Plugins::default();
1087 plugins.insert::<DdlManagerConfiguratorRef<DdlManagerConfigureContext>>(Arc::new(
1088 TestDdlManagerConfigurator(configured.clone()),
1089 ));
1090
1091 let _cluster = GreptimeDbClusterBuilder::new("test_cluster_with_plugins")
1092 .await
1093 .with_datanodes(1)
1094 .with_plugins(plugins)
1095 .build(false)
1096 .await;
1097
1098 assert!(configured.load(Ordering::SeqCst));
1099 }
1100
1101 #[tokio::test(flavor = "multi_thread")]
1102 async fn test_region_requester_health_check_and_list_metadata() {
1103 let cluster = GreptimeDbClusterBuilder::new("region_requester_health_check")
1105 .await
1106 .with_datanodes(1)
1107 .build(false)
1108 .await;
1109 let (active_peer, inactive_peer, client) =
1110 create_region_requester_health_client(cluster.datanode_instances.get(&1).unwrap())
1111 .await;
1112 let clients = NodeClients::default();
1113 clients
1114 .insert_client(active_peer.clone(), client.clone())
1115 .await;
1116 clients
1117 .insert_client(inactive_peer.clone(), client.clone())
1118 .await;
1119
1120 wait_for_active_route(&client, &active_peer.addr).await;
1122 let requester = clients.datanode(&active_peer).await;
1123 let response = requester
1124 .handle(RegionRequest {
1125 header: Some(RegionRequestHeader::default()),
1126 body: Some(region_request::Body::ListMetadata(ListMetadataRequest {
1127 region_ids: vec![],
1128 })),
1129 })
1130 .await
1131 .unwrap();
1132
1133 assert_eq!(
1135 (vec![active_peer.addr], vec![inactive_peer.addr]),
1136 client.peer_addresses_by_state()
1137 );
1138 assert_eq!(b"[]", response.metadata.as_slice());
1139 }
1140
1141 #[tokio::test(flavor = "multi_thread")]
1142 async fn test_flow_requester_health_check_and_handle_request() {
1143 let mut flownode = start_flownode("127.0.0.1:0".to_string()).await;
1145 let (active_peer, inactive_peer, client) =
1146 create_flow_requester_health_client(&flownode).await;
1147 let clients = NodeClients::default();
1148 clients
1149 .insert_client(active_peer.clone(), client.clone())
1150 .await;
1151 clients
1152 .insert_client(inactive_peer.clone(), client.clone())
1153 .await;
1154
1155 wait_for_active_route(&client, &active_peer.addr).await;
1157 let response = clients
1158 .flownode(&active_peer)
1159 .await
1160 .handle(FlowRequest::default())
1161 .await;
1162
1163 assert_eq!(
1165 (vec![active_peer.addr.clone()], vec![inactive_peer.addr]),
1166 client.peer_addresses_by_state()
1167 );
1168 assert_eq!(
1169 StatusCode::InvalidArguments,
1170 response.unwrap_err().status_code()
1171 );
1172
1173 for value in ["", "unknown", "follower"] {
1174 let mut query_context =
1175 api::v1::QueryContext::from(session::context::QueryContext::arc().as_ref());
1176 query_context.extensions.insert(
1177 session::hints::READ_PREFERENCE_EXTENSION_KEY.to_string(),
1178 value.to_string(),
1179 );
1180 let error = clients
1181 .flownode(&active_peer)
1182 .await
1183 .handle(FlowRequest {
1184 header: Some(api::v1::flow::FlowRequestHeader {
1185 tracing_context: Default::default(),
1186 query_context: Some(query_context),
1187 }),
1188 body: None,
1189 })
1190 .await
1191 .unwrap_err();
1192 assert_eq!(StatusCode::InvalidArguments, error.status_code());
1193 let message = error.output_msg();
1194 assert!(message.contains("read_preference"), "{message}");
1195 if !value.is_empty() {
1196 assert!(message.contains(value), "{message}");
1197 }
1198 }
1199
1200 flownode.shutdown().await.unwrap();
1201 }
1202}