1use std::path::Path;
16use std::sync::atomic::AtomicBool;
17use std::sync::{Arc, Mutex, RwLock};
18use std::time::Duration;
19
20use client::client_manager::NodeClients;
21use client::inserter::InsertOptions;
22use common_base::Plugins;
23use common_catalog::consts::{MIN_USER_FLOW_ID, MIN_USER_TABLE_ID};
24use common_event_recorder::{DEFAULT_COMPACTION_TIME_WINDOW, EventRecorderImpl, EventRecorderRef};
25use common_meta::affinity::{AffinityFallback, AffinityRef, NoopAffinity};
26use common_meta::ddl::flow_meta::FlowMetadataAllocator;
27use common_meta::ddl::table_meta::{TableMetadataAllocator, TableMetadataAllocatorRef};
28use common_meta::ddl::{
29 DdlContext, NoopRegionFailureDetectorControl, RegionFailureDetectorControllerRef,
30};
31use common_meta::ddl_manager::{
32 DdlManager, DdlManagerConfiguratorRef, RepartitionProcedureFactoryRef,
33};
34use common_meta::distributed_time_constants::default_distributed_time_constants;
35use common_meta::key::TableMetadataManager;
36use common_meta::key::flow::FlowMetadataManager;
37use common_meta::key::flow::flow_state::FlowStateManager;
38use common_meta::key::runtime_switch::{RuntimeSwitchManager, RuntimeSwitchManagerRef};
39use common_meta::kv_backend::memory::MemoryKvBackend;
40use common_meta::kv_backend::{KvBackendRef, ResettableKvBackendRef};
41use common_meta::node_manager::NodeManagerRef;
42use common_meta::peer::PeerDiscoveryRef;
43use common_meta::reconciliation::manager::ReconciliationManager;
44use common_meta::region_keeper::MemoryRegionKeeper;
45use common_meta::region_registry::LeaderRegionRegistry;
46use common_meta::sequence::SequenceBuilder;
47use common_meta::state_store::KvStateStore;
48use common_meta::stats::topic::TopicStatsRegistry;
49use common_meta::wal_provider::{build_kafka_client, build_wal_provider};
50use common_procedure::ProcedureManagerRef;
51use common_procedure::local::{LocalManager, ManagerConfig};
52use common_stat::ResourceStatImpl;
53use common_telemetry::{info, warn};
54use snafu::{ResultExt, ensure};
55use store_api::storage::MAX_REGION_SEQ;
56
57use crate::bootstrap::build_default_meta_peer_client;
58use crate::cache_invalidator::MetasrvCacheInvalidator;
59use crate::cluster::MetaPeerClientRef;
60use crate::discovery::node_scheduling::SchedulingAwarePeerDiscovery;
61use crate::error::{self, BuildWalProviderSnafu, OtherSnafu, Result};
62use crate::event::EventHandlerImpl;
63use crate::gc::{DefaultGcSchedulerCtx, GcScheduler};
64use crate::greptimedb_telemetry::get_greptimedb_telemetry_task;
65use crate::handler::failure_handler::RegionFailureHandler;
66use crate::handler::flow_state_handler::FlowStateHandler;
67use crate::handler::persist_stats_handler::PersistStatsHandler;
68use crate::handler::region_lease_handler::{CustomizedRegionLeaseRenewerRef, RegionLeaseHandler};
69use crate::handler::{HeartbeatHandlerGroupBuilder, HeartbeatMailbox, Pushers};
70use crate::metasrv::{
71 ElectionRef, FLOW_ID_SEQ, METASRV_DATA_DIR, Metasrv, MetasrvInfo, MetasrvOptions,
72 RegionStatAwareSelectorRef, SelectTarget, SelectorContext, SelectorFactoryRef, SelectorRef,
73 TABLE_ID_SEQ,
74};
75use crate::node_scheduling::NodeSchedulingManager;
76use crate::peer::MetasrvPeerAllocator;
77use crate::procedure::drain_datanode::manager::DrainDatanodeManager;
78use crate::procedure::region_migration::DefaultContextFactory;
79use crate::procedure::region_migration::manager::RegionMigrationManager;
80use crate::procedure::repartition::gc_requirement::RepartitionGcRequirementManager;
81use crate::procedure::repartition::{
82 DefaultRepartitionProcedureFactory, GcDisabledRepartitionProcedureFactory,
83};
84use crate::procedure::wal_prune::Context as WalPruneContext;
85use crate::procedure::wal_prune::manager::{WalPruneManager, WalPruneTicker};
86use crate::region::flush_trigger::RegionFlushTrigger;
87use crate::region::supervisor::{
88 DEFAULT_INITIALIZATION_RETRY_PERIOD, DEFAULT_TICK_INTERVAL, HeartbeatAcceptor,
89 RegionFailureDetectorControl, RegionSupervisor, RegionSupervisorSelector,
90 RegionSupervisorTicker,
91};
92use crate::selector::lease_based::LeaseBasedSelector;
93use crate::selector::round_robin::RoundRobinSelector;
94use crate::service::mailbox::MailboxRef;
95use crate::service::store::cached_kv::LeaderCachedKvBackend;
96use crate::state::State;
97use crate::utils::database::DatabaseOperator;
98use crate::utils::insert_forwarder::InsertForwarder;
99
100const REGION_STATS_TABLE_TWCS_COMPACTION_TIME_WINDOW: Duration = Duration::from_secs(86400);
102
103pub struct MetasrvBuilder {
105 options: Option<MetasrvOptions>,
106 kv_backend: Option<KvBackendRef>,
107 in_memory: Option<ResettableKvBackendRef>,
108 selector: Option<SelectorRef>,
109 handler_group_builder: Option<HeartbeatHandlerGroupBuilder>,
110 election: Option<ElectionRef>,
111 meta_peer_client: Option<MetaPeerClientRef>,
112 node_manager: Option<NodeManagerRef>,
113 plugins: Option<Plugins>,
114 table_metadata_allocator: Option<TableMetadataAllocatorRef>,
115}
116
117impl MetasrvBuilder {
118 pub fn new() -> Self {
119 Self {
120 kv_backend: None,
121 in_memory: None,
122 selector: None,
123 handler_group_builder: None,
124 meta_peer_client: None,
125 election: None,
126 options: None,
127 node_manager: None,
128 plugins: None,
129 table_metadata_allocator: None,
130 }
131 }
132
133 pub fn options(mut self, options: MetasrvOptions) -> Self {
134 self.options = Some(options);
135 self
136 }
137
138 pub fn kv_backend(mut self, kv_backend: KvBackendRef) -> Self {
139 self.kv_backend = Some(kv_backend);
140 self
141 }
142
143 pub fn in_memory(mut self, in_memory: ResettableKvBackendRef) -> Self {
144 self.in_memory = Some(in_memory);
145 self
146 }
147
148 pub fn selector(mut self, selector: SelectorRef) -> Self {
149 self.selector = Some(selector);
150 self
151 }
152
153 pub fn heartbeat_handler(
154 mut self,
155 handler_group_builder: HeartbeatHandlerGroupBuilder,
156 ) -> Self {
157 self.handler_group_builder = Some(handler_group_builder);
158 self
159 }
160
161 pub fn meta_peer_client(mut self, meta_peer_client: MetaPeerClientRef) -> Self {
162 self.meta_peer_client = Some(meta_peer_client);
163 self
164 }
165
166 pub fn election(mut self, election: Option<ElectionRef>) -> Self {
167 self.election = election;
168 self
169 }
170
171 pub fn node_manager(mut self, node_manager: NodeManagerRef) -> Self {
172 self.node_manager = Some(node_manager);
173 self
174 }
175
176 pub fn plugins(mut self, plugins: Plugins) -> Self {
177 self.plugins = Some(plugins);
178 self
179 }
180
181 pub fn table_metadata_allocator(
182 mut self,
183 table_metadata_allocator: TableMetadataAllocatorRef,
184 ) -> Self {
185 self.table_metadata_allocator = Some(table_metadata_allocator);
186 self
187 }
188
189 pub fn options_ref(&self) -> Option<&MetasrvOptions> {
190 self.options.as_ref()
191 }
192
193 pub fn kv_backend_ref(&self) -> Option<&KvBackendRef> {
194 self.kv_backend.as_ref()
195 }
196
197 pub fn in_memory_ref(&self) -> Option<&ResettableKvBackendRef> {
198 self.in_memory.as_ref()
199 }
200
201 pub fn election_ref(&self) -> Option<&ElectionRef> {
202 self.election.as_ref()
203 }
204
205 pub fn meta_peer_client_ref(&self) -> Option<&MetaPeerClientRef> {
206 self.meta_peer_client.as_ref()
207 }
208
209 pub fn node_manager_ref(&self) -> Option<&NodeManagerRef> {
210 self.node_manager.as_ref()
211 }
212
213 pub async fn build(self) -> Result<Metasrv> {
214 let MetasrvBuilder {
215 election,
216 meta_peer_client,
217 options,
218 kv_backend,
219 in_memory,
220 selector,
221 handler_group_builder,
222 node_manager,
223 plugins,
224 table_metadata_allocator,
225 } = self;
226
227 let options = options.unwrap_or_default();
228 options.gc.validate()?;
229
230 let kv_backend = kv_backend.unwrap_or_else(|| Arc::new(MemoryKvBackend::new()));
231 let in_memory = in_memory.unwrap_or_else(|| Arc::new(MemoryKvBackend::new()));
232
233 let state = Arc::new(RwLock::new(match election {
234 None => State::leader(options.grpc.server_addr.clone(), true),
235 Some(_) => State::follower(options.grpc.server_addr.clone()),
236 }));
237
238 let leader_cached_kv_backend = Arc::new(LeaderCachedKvBackend::new(
239 state.clone(),
240 kv_backend.clone(),
241 ));
242
243 let meta_peer_client = meta_peer_client
244 .unwrap_or_else(|| build_default_meta_peer_client(&election, &in_memory));
245
246 let node_scheduling_manager = Arc::new(NodeSchedulingManager::new(kv_backend.clone()));
247
248 let selector_ctx = SelectorContext {
254 affinity_fallback: plugins
255 .as_ref()
256 .and_then(|plugins| plugins.get::<AffinityFallback>())
257 .unwrap_or_default(),
258 affinity: plugins
259 .as_ref()
260 .and_then(|plugins| plugins.get::<AffinityRef>())
261 .unwrap_or_else(|| Arc::new(NoopAffinity)),
262 peer_discovery: Arc::new(SchedulingAwarePeerDiscovery::new(
263 node_scheduling_manager.clone(),
264 meta_peer_client.clone(),
265 )),
266 };
267 let database_operator =
269 Arc::new(DatabaseOperator::new(selector_ctx.peer_discovery.clone()));
270
271 let event_inserter = Box::new(InsertForwarder::new(
272 database_operator.clone(),
273 Some(InsertOptions {
274 ttl: options.event_recorder.ttl,
275 append_mode: true,
276 twcs_compaction_time_window: Some(DEFAULT_COMPACTION_TIME_WINDOW),
277 }),
278 ));
279 let event_recorder = Arc::new(EventRecorderImpl::with_event_type_filter(
281 Box::new(EventHandlerImpl::new(event_inserter)),
282 options.event_recorder.event_types.clone(),
283 options.event_recorder.flush_interval,
284 ));
285
286 let selector = selector.unwrap_or_else(|| Arc::new(LeaseBasedSelector));
287 let pushers = Pushers::default();
288 let mailbox = build_mailbox(&kv_backend, &pushers);
289 let runtime_switch_manager = Arc::new(RuntimeSwitchManager::new(kv_backend.clone()));
290 let repartition_gc_requirement_manager =
291 Arc::new(RepartitionGcRequirementManager::new(kv_backend.clone()));
292 let procedure_manager = build_procedure_manager(
293 &options,
294 &kv_backend,
295 &runtime_switch_manager,
296 event_recorder,
297 );
298
299 let table_metadata_manager = Arc::new(TableMetadataManager::new(
300 leader_cached_kv_backend.clone() as _,
301 ));
302 let flow_metadata_manager = Arc::new(FlowMetadataManager::new(
303 leader_cached_kv_backend.clone() as _,
304 ));
305
306 let wal_provider = build_wal_provider(&options.wal, kv_backend.clone())
307 .await
308 .context(BuildWalProviderSnafu)?;
309 let wal_provider = Arc::new(wal_provider);
310 let is_remote_wal = wal_provider.is_remote_wal();
311 let table_metadata_allocator = table_metadata_allocator.unwrap_or_else(|| {
312 let sequence = Arc::new(
313 SequenceBuilder::new(TABLE_ID_SEQ, kv_backend.clone())
314 .initial(MIN_USER_TABLE_ID as u64)
315 .step(10)
316 .build(),
317 );
318 let peer_allocator = Arc::new(
319 MetasrvPeerAllocator::new(selector_ctx.clone(), selector.clone())
320 .with_max_items(MAX_REGION_SEQ),
321 );
322 Arc::new(TableMetadataAllocator::with_peer_allocator(
323 sequence,
324 wal_provider.clone(),
325 peer_allocator,
326 ))
327 });
328 let table_id_allocator = table_metadata_allocator.table_id_allocator();
329
330 let flow_selector =
331 Arc::new(RoundRobinSelector::new(SelectTarget::Flownode)) as SelectorRef;
332
333 let flow_metadata_allocator = {
334 let flow_selector_ctx = selector_ctx.clone();
336 let peer_allocator = Arc::new(MetasrvPeerAllocator::new(
337 flow_selector_ctx,
338 flow_selector.clone(),
339 ));
340 let seq = Arc::new(
341 SequenceBuilder::new(FLOW_ID_SEQ, kv_backend.clone())
342 .initial(MIN_USER_FLOW_ID as u64)
343 .step(10)
344 .build(),
345 );
346
347 Arc::new(FlowMetadataAllocator::with_peer_allocator(
348 seq,
349 peer_allocator,
350 ))
351 };
352 let flow_state_handler =
353 FlowStateHandler::new(FlowStateManager::new(in_memory.clone().as_kv_backend_ref()));
354
355 let memory_region_keeper = Arc::new(MemoryRegionKeeper::default());
356 let node_manager = node_manager.unwrap_or_else(|| {
357 let datanode_client_channel_config = options.datanode.client.channel_config();
358 Arc::new(NodeClients::new(datanode_client_channel_config))
359 });
360 let cache_invalidator = Arc::new(MetasrvCacheInvalidator::new(
361 mailbox.clone(),
362 MetasrvInfo {
363 server_addr: options.grpc.server_addr.clone(),
364 },
365 ));
366
367 if !is_remote_wal && options.enable_region_failover {
368 ensure!(
369 options.allow_region_failover_on_local_wal,
370 error::UnexpectedSnafu {
371 violated: "Region failover is not supported in the local WAL implementation!
372 If you want to enable region failover for local WAL, please set `allow_region_failover_on_local_wal` to true.",
373 }
374 );
375 if options.allow_region_failover_on_local_wal {
376 warn!(
377 "Region failover is force enabled in the local WAL implementation! This may lead to data loss during failover!"
378 );
379 }
380 }
381
382 let (tx, rx) = RegionSupervisor::channel();
383 let (region_failure_detector_controller, region_supervisor_ticker): (
384 RegionFailureDetectorControllerRef,
385 Option<std::sync::Arc<RegionSupervisorTicker>>,
386 ) = if options.enable_region_failover {
387 (
388 Arc::new(RegionFailureDetectorControl::new(tx.clone())) as _,
389 Some(Arc::new(RegionSupervisorTicker::new(
390 DEFAULT_TICK_INTERVAL,
391 options.region_failure_detector_initialization_delay,
392 DEFAULT_INITIALIZATION_RETRY_PERIOD,
393 tx.clone(),
394 ))),
395 )
396 } else {
397 (Arc::new(NoopRegionFailureDetectorControl) as _, None as _)
398 };
399
400 let region_migration_manager = Arc::new(RegionMigrationManager::new(
402 procedure_manager.clone(),
403 DefaultContextFactory::new(
404 in_memory.clone(),
405 table_metadata_manager.clone(),
406 memory_region_keeper.clone(),
407 region_failure_detector_controller.clone(),
408 mailbox.clone(),
409 options.grpc.server_addr.clone(),
410 cache_invalidator.clone(),
411 ),
412 ));
413 region_migration_manager.try_start()?;
414
415 let drain_datanode_manager = Arc::new(DrainDatanodeManager::new(
416 procedure_manager.clone(),
417 table_metadata_manager.clone(),
418 node_scheduling_manager.clone(),
419 region_migration_manager.clone(),
420 selector_ctx.clone(),
421 ));
422 drain_datanode_manager.try_start()?;
423 let affinity_resolver = plugins
424 .as_ref()
425 .and_then(|plugins| plugins.get::<SelectorFactoryRef>())
426 .and_then(|factory| {
427 factory.build_affinity_resolver(
428 meta_peer_client.clone(),
429 selector_ctx.peer_discovery.clone(),
430 )
431 });
432 let region_supervisor_selector = plugins
433 .as_ref()
434 .and_then(|plugins| plugins.get::<RegionStatAwareSelectorRef>());
435
436 let supervisor_selector = match region_supervisor_selector {
437 Some(selector) => {
438 info!("Using region stat aware selector");
439 RegionSupervisorSelector::RegionStatAwareSelector(selector)
440 }
441 None => RegionSupervisorSelector::NaiveSelector(selector.clone()),
442 };
443
444 let region_failover_handler = if options.enable_region_failover {
445 let region_supervisor = RegionSupervisor::new(
446 rx,
447 options.failure_detector,
448 selector_ctx.clone(),
449 supervisor_selector,
450 region_migration_manager.clone(),
451 runtime_switch_manager.clone(),
452 meta_peer_client.clone(),
453 leader_cached_kv_backend.clone(),
454 )
455 .with_state(state.clone());
456 let region_supervisor = if let Some(resolver) = &affinity_resolver {
457 region_supervisor.with_affinity_resolver(resolver.clone())
458 } else {
459 region_supervisor
460 };
461
462 Some(RegionFailureHandler::new(
463 region_supervisor,
464 HeartbeatAcceptor::new(tx),
465 ))
466 } else {
467 None
468 };
469
470 let leader_region_registry = Arc::new(LeaderRegionRegistry::default());
471 let topic_stats_registry = Arc::new(TopicStatsRegistry::default());
472
473 let ddl_context = DdlContext {
474 peer_alloc_context_provider: None,
475 affinity_fallback: selector_ctx.affinity_fallback,
476 affinity_resolver,
477 node_manager: node_manager.clone(),
478 cache_invalidator: cache_invalidator.clone(),
479 memory_region_keeper: memory_region_keeper.clone(),
480 leader_region_registry: leader_region_registry.clone(),
481 table_metadata_manager: table_metadata_manager.clone(),
482 table_metadata_allocator: table_metadata_allocator.clone(),
483 flow_metadata_manager: flow_metadata_manager.clone(),
484 flow_metadata_allocator: flow_metadata_allocator.clone(),
485 region_failure_detector_controller,
486 soft_drop_enabled: ddl_soft_drop_enabled(&options),
487 soft_drop_retention: ddl_soft_drop_retention(&options),
488 create_database_metadata_committer: None,
489 };
490 let procedure_manager_c = procedure_manager.clone();
491 let repartition_procedure_factory: RepartitionProcedureFactoryRef = if options.gc.enable {
492 Arc::new(DefaultRepartitionProcedureFactory::new(
493 mailbox.clone(),
494 options.grpc.server_addr.clone(),
495 repartition_gc_requirement_manager.clone(),
496 ))
497 } else {
498 Arc::new(GcDisabledRepartitionProcedureFactory::new(
499 mailbox.clone(),
500 options.grpc.server_addr.clone(),
501 repartition_gc_requirement_manager.clone(),
502 ))
503 };
504 let ddl_manager = DdlManager::new(
505 ddl_context,
506 procedure_manager_c,
507 repartition_procedure_factory,
508 );
509
510 let ddl_manager = if let Some(configurator) = plugins
511 .as_ref()
512 .and_then(|p| p.get::<DdlManagerConfiguratorRef<DdlManagerConfigureContext>>())
513 {
514 let ctx = DdlManagerConfigureContext {
515 kv_backend: kv_backend.clone(),
516 peer_discovery: selector_ctx.peer_discovery.clone(),
517 };
518 configurator
519 .configure(ddl_manager, ctx)
520 .await
521 .context(OtherSnafu)?
522 } else {
523 ddl_manager
524 };
525 ddl_manager
526 .register_loaders()
527 .context(error::InitDdlManagerSnafu)?;
528
529 let ddl_manager = Arc::new(ddl_manager);
530
531 let region_flush_ticker = if is_remote_wal {
532 let remote_wal_options = options.wal.remote_wal_options().unwrap();
533 let (region_flush_trigger, region_flush_ticker) = RegionFlushTrigger::new(
534 table_metadata_manager.clone(),
535 leader_region_registry.clone(),
536 topic_stats_registry.clone(),
537 mailbox.clone(),
538 options.grpc.server_addr.clone(),
539 remote_wal_options.flush_trigger_size,
540 remote_wal_options.checkpoint_trigger_size,
541 remote_wal_options.region_flush_trigger_interval,
542 remote_wal_options.periodic_checkpoint_persist_interval,
543 );
544 region_flush_trigger.try_start()?;
545
546 Some(Arc::new(region_flush_ticker))
547 } else {
548 None
549 };
550
551 let wal_prune_ticker = if is_remote_wal && options.wal.enable_active_wal_pruning() {
553 let (tx, rx) = WalPruneManager::channel();
554 let remote_wal_options = options.wal.remote_wal_options().unwrap();
556 let kafka_client = build_kafka_client(&remote_wal_options.connection)
557 .await
558 .context(error::BuildKafkaClientSnafu)?;
559 let wal_prune_context = WalPruneContext {
560 client: Arc::new(kafka_client),
561 table_metadata_manager: table_metadata_manager.clone(),
562 leader_region_registry: leader_region_registry.clone(),
563 };
564 let wal_prune_manager = WalPruneManager::new(
565 remote_wal_options.auto_prune_parallelism,
566 remote_wal_options.auto_prune_logical_delete,
567 rx,
568 procedure_manager.clone(),
569 wal_prune_context,
570 );
571 wal_prune_manager.try_start().await?;
573 let wal_prune_ticker = Arc::new(WalPruneTicker::new(
574 remote_wal_options.auto_prune_interval,
575 tx.clone(),
576 ));
577 Some(wal_prune_ticker)
578 } else {
579 None
580 };
581
582 let gc_ticker = if options.gc.enable {
583 let gc_scheduler_ctx = DefaultGcSchedulerCtx::try_new(
584 table_metadata_manager.clone(),
585 procedure_manager.clone(),
586 runtime_switch_manager.clone(),
587 #[cfg(feature = "enterprise")]
588 ddl_manager.clone(),
589 meta_peer_client.clone(),
590 mailbox.clone(),
591 options.grpc.server_addr.clone(),
592 )?;
593 let (gc_scheduler, gc_ticker) = GcScheduler::new_with_config(
594 gc_scheduler_ctx,
595 runtime_switch_manager.clone(),
596 options.gc.clone(),
597 )?;
598 gc_scheduler.try_start()?;
599
600 Some(Arc::new(gc_ticker))
601 } else {
602 None
603 };
604
605 let customized_region_lease_renewer = plugins
606 .as_ref()
607 .and_then(|plugins| plugins.get::<CustomizedRegionLeaseRenewerRef>());
608
609 let persist_region_stats_handler = if !options.stats_persistence.ttl.is_zero() {
610 let inserter = Box::new(InsertForwarder::new(
611 database_operator.clone(),
612 Some(InsertOptions {
613 ttl: options.stats_persistence.ttl,
614 append_mode: true,
615 twcs_compaction_time_window: Some(
616 REGION_STATS_TABLE_TWCS_COMPACTION_TIME_WINDOW,
617 ),
618 }),
619 ));
620
621 Some(PersistStatsHandler::new(
622 inserter,
623 options.stats_persistence.interval,
624 ))
625 } else {
626 None
627 };
628
629 let handler_group_builder = match handler_group_builder {
630 Some(handler_group_builder) => handler_group_builder,
631 None => {
632 let region_lease_handler = RegionLeaseHandler::new(
633 default_distributed_time_constants().region_lease.as_secs(),
634 table_metadata_manager.clone(),
635 memory_region_keeper.clone(),
636 customized_region_lease_renewer,
637 );
638
639 HeartbeatHandlerGroupBuilder::new(pushers)
640 .with_plugins(plugins.clone())
641 .with_region_failure_handler(region_failover_handler)
642 .with_region_lease_handler(Some(region_lease_handler))
643 .with_flush_stats_factor(Some(options.flush_stats_factor))
644 .with_flow_state_handler(Some(flow_state_handler))
645 .with_persist_stats_handler(persist_region_stats_handler)
646 .add_default_handlers()
647 }
648 };
649
650 let enable_telemetry = options.enable_telemetry;
651 let metasrv_home = Path::new(&options.data_home)
652 .join(METASRV_DATA_DIR)
653 .to_string_lossy()
654 .to_string();
655
656 let reconciliation_manager = Arc::new(ReconciliationManager::new(
657 node_manager.clone(),
658 table_metadata_manager.clone(),
659 cache_invalidator.clone(),
660 procedure_manager.clone(),
661 ));
662 reconciliation_manager
663 .try_start()
664 .context(error::InitReconciliationManagerSnafu)?;
665
666 let mut resource_stat = ResourceStatImpl::default();
667 resource_stat.start_collect_cpu_usage();
668
669 Ok(Metasrv {
670 state,
671 started: Arc::new(AtomicBool::new(false)),
672 start_time_ms: common_time::util::current_time_millis() as u64,
673 options,
674 in_memory,
675 kv_backend,
676 leader_cached_kv_backend,
677 meta_peer_client: meta_peer_client.clone(),
678 selector,
679 selector_ctx,
680 flow_selector,
682 handler_group: RwLock::new(None),
683 handler_group_builder: Mutex::new(Some(handler_group_builder)),
684 election,
685 procedure_manager,
686 mailbox,
687 ddl_manager,
688 wal_provider,
689 table_metadata_manager,
690 runtime_switch_manager,
691 repartition_gc_requirement_manager,
692 greptimedb_telemetry_task: get_greptimedb_telemetry_task(
693 Some(metasrv_home),
694 meta_peer_client,
695 enable_telemetry,
696 )
697 .await,
698 plugins: plugins.unwrap_or_else(Plugins::default),
699 memory_region_keeper,
700 region_migration_manager,
701 drain_datanode_manager,
702 region_supervisor_ticker,
703 cache_invalidator,
704 leader_region_registry,
705 wal_prune_ticker,
706 region_flush_ticker,
707 table_id_allocator,
708 reconciliation_manager,
709 topic_stats_registry,
710 resource_stat: Arc::new(resource_stat),
711 gc_ticker,
712 database_operator,
713 node_scheduling_manager,
714 })
715 }
716}
717
718fn build_mailbox(kv_backend: &KvBackendRef, pushers: &Pushers) -> MailboxRef {
719 let mailbox_sequence = SequenceBuilder::new("heartbeat_mailbox", kv_backend.clone())
720 .initial(1)
721 .step(100)
722 .build();
723
724 HeartbeatMailbox::create(pushers.clone(), mailbox_sequence)
725}
726
727fn build_procedure_manager(
728 options: &MetasrvOptions,
729 kv_backend: &KvBackendRef,
730 runtime_switch_manager: &RuntimeSwitchManagerRef,
731 event_recorder: EventRecorderRef,
732) -> ProcedureManagerRef {
733 let manager_config = ManagerConfig {
734 max_retry_times: options.procedure.max_retry_times,
735 retry_delay: options.procedure.retry_delay,
736 max_running_procedures: options.procedure.max_running_procedures,
737 ..Default::default()
738 };
739 let kv_state_store = Arc::new(
740 KvStateStore::new(kv_backend.clone()).with_max_value_size(
741 options
742 .procedure
743 .max_metadata_value_size
744 .map(|v| v.as_bytes() as usize),
745 ),
746 );
747
748 Arc::new(LocalManager::new(
749 manager_config,
750 kv_state_store.clone(),
751 kv_state_store,
752 Some(runtime_switch_manager.clone()),
753 Some(event_recorder),
754 ))
755}
756
757fn ddl_soft_drop_enabled(options: &MetasrvOptions) -> bool {
762 cfg!(feature = "enterprise") && options.gc.experimental_soft_drop.enable
763}
764
765fn ddl_soft_drop_retention(options: &MetasrvOptions) -> Option<Duration> {
767 Some(options.gc.experimental_soft_drop.retention)
768}
769
770impl Default for MetasrvBuilder {
771 fn default() -> Self {
772 Self::new()
773 }
774}
775
776pub struct DdlManagerConfigureContext {
778 pub kv_backend: KvBackendRef,
779 pub peer_discovery: PeerDiscoveryRef,
780}
781
782#[cfg(test)]
783mod tests {
784 use super::*;
785
786 #[cfg(feature = "enterprise")]
787 #[test]
788 fn test_ddl_soft_drop_gate_preserves_retention_for_recovery() {
789 let mut options = MetasrvOptions::default();
790 options.gc.enable = true;
791 options.gc.experimental_soft_drop.enable = true;
792 options.gc.experimental_soft_drop.retention = Duration::from_secs(123);
793
794 assert!(ddl_soft_drop_enabled(&options));
795 assert_eq!(
796 Some(Duration::from_secs(123)),
797 ddl_soft_drop_retention(&options)
798 );
799 }
800
801 #[cfg(not(feature = "enterprise"))]
802 #[test]
803 fn test_ddl_soft_drop_is_always_disabled_in_non_enterprise_build() {
804 let mut options = MetasrvOptions::default();
805 options.gc.enable = true;
806 options.gc.experimental_soft_drop.enable = true;
807 options.gc.experimental_soft_drop.retention = Duration::from_secs(123);
808
809 assert!(!ddl_soft_drop_enabled(&options));
810 assert_eq!(
812 Some(Duration::from_secs(123)),
813 ddl_soft_drop_retention(&options)
814 );
815 }
816
817 #[test]
818 fn test_ddl_soft_drop_is_disabled_by_default() {
819 assert!(!ddl_soft_drop_enabled(&MetasrvOptions::default()));
820 }
821
822 #[test]
823 fn test_soft_drop_options_are_validated() {
824 let mut options = MetasrvOptions::default();
825 options.gc.enable = true;
826 options.gc.experimental_soft_drop.enable = true;
827 options.gc.experimental_soft_drop.retention = Duration::ZERO;
828
829 assert!(options.gc.validate().is_err());
830 }
831
832 #[tokio::test]
833 async fn test_builder_rejects_soft_drop_when_gc_is_disabled() {
834 let mut options = MetasrvOptions::default();
835 options.gc.experimental_soft_drop.enable = true;
836
837 assert!(
838 MetasrvBuilder::new()
839 .options(options)
840 .build()
841 .await
842 .is_err()
843 );
844 }
845
846 #[tokio::test]
847 async fn test_builder_skips_gc_validation_when_gc_is_disabled() {
848 let mut options = MetasrvOptions::default();
849 options.gc.enable = false;
850 options.gc.max_concurrent_tables = 0;
851
852 let metasrv = MetasrvBuilder::new()
853 .options(options)
854 .build()
855 .await
856 .unwrap();
857 let context = metasrv.ddl_manager().create_context();
858 assert_eq!(context.affinity_fallback, AffinityFallback::Error);
859 assert!(context.affinity_resolver.is_none());
860 assert!(context.peer_alloc_context_provider.is_none());
861 }
862
863 #[tokio::test]
864 async fn test_builder_injects_affinity_components() {
865 use std::sync::atomic::{AtomicUsize, Ordering};
866
867 use common_meta::affinity::{
868 Affinity, AffinityRef, AffinityReference, AffinityRequirements, AffinityResolver,
869 AffinityResolverRef,
870 };
871 use common_meta::cluster::NodeInfo;
872 use common_meta::error::Result as MetaResult;
873
874 use common_meta::ddl_manager::DdlManagerConfigurator;
875
876 use crate::discovery::node_info::NodeInfoAccessor;
877 use crate::metasrv::{SelectorFactory, SelectorFactoryContext};
878
879 struct TestAffinity;
880
881 impl Affinity for TestAffinity {
882 fn matches(&self, _: &AffinityRequirements, _: &NodeInfo) -> bool {
883 true
884 }
885 }
886
887 struct TestResolver;
888
889 #[async_trait::async_trait]
890 impl AffinityResolver for TestResolver {
891 async fn resolve(
892 &self,
893 references: &[AffinityReference],
894 ) -> MetaResult<Vec<Option<AffinityRequirements>>> {
895 Ok(vec![None; references.len()])
896 }
897 }
898
899 struct RecordingFactory {
900 calls: Arc<AtomicUsize>,
901 resolver: AffinityResolverRef,
902 discovery: Arc<std::sync::Mutex<Option<PeerDiscoveryRef>>>,
903 }
904
905 struct RecordingConfigurator {
906 discovery: Arc<std::sync::Mutex<Option<PeerDiscoveryRef>>>,
907 }
908
909 #[async_trait::async_trait]
910 impl DdlManagerConfigurator<DdlManagerConfigureContext> for RecordingConfigurator {
911 async fn configure(
912 &self,
913 ddl_manager: DdlManager,
914 ctx: DdlManagerConfigureContext,
915 ) -> std::result::Result<DdlManager, common_error::ext::BoxedError> {
916 *self.discovery.lock().unwrap() = Some(ctx.peer_discovery);
917 Ok(ddl_manager)
918 }
919 }
920
921 impl SelectorFactory for RecordingFactory {
922 fn build_affinity_resolver(
923 &self,
924 _: Arc<dyn NodeInfoAccessor>,
925 peer_discovery: PeerDiscoveryRef,
926 ) -> Option<AffinityResolverRef> {
927 *self.discovery.lock().unwrap() = Some(peer_discovery);
928 self.calls.fetch_add(1, Ordering::Relaxed);
929 Some(self.resolver.clone())
930 }
931
932 fn build(&self, ctx: SelectorFactoryContext) -> SelectorRef {
933 ctx.base_selector
934 }
935 }
936
937 let factory_discovery = Arc::new(std::sync::Mutex::new(None));
938 let configurator_discovery = Arc::new(std::sync::Mutex::new(None));
939 let calls = Arc::new(AtomicUsize::new(0));
940 let resolver: AffinityResolverRef = Arc::new(TestResolver);
941 let affinity: AffinityRef = Arc::new(TestAffinity);
942 let plugins = Plugins::new();
943 plugins.insert(affinity.clone());
944 plugins.insert(AffinityFallback::Unconstrained);
945 plugins.insert(Arc::new(RecordingFactory {
946 calls: calls.clone(),
947 resolver: resolver.clone(),
948 discovery: factory_discovery.clone(),
949 }) as SelectorFactoryRef);
950 plugins.insert(Arc::new(RecordingConfigurator {
951 discovery: configurator_discovery.clone(),
952 })
953 as DdlManagerConfiguratorRef<DdlManagerConfigureContext>);
954 let metasrv = MetasrvBuilder::new()
955 .options(MetasrvOptions {
956 enable_telemetry: false,
957 ..Default::default()
958 })
959 .plugins(plugins)
960 .build()
961 .await
962 .unwrap();
963
964 assert_eq!(
965 metasrv.selector_ctx().affinity_fallback,
966 AffinityFallback::Unconstrained
967 );
968 assert_eq!(
969 metasrv.ddl_manager().create_context().affinity_fallback,
970 AffinityFallback::Unconstrained
971 );
972 assert_eq!(calls.load(Ordering::Relaxed), 1);
973 for discovery in [factory_discovery, configurator_discovery] {
974 assert!(Arc::ptr_eq(
975 discovery.lock().unwrap().as_ref().unwrap(),
976 &metasrv.selector_ctx().peer_discovery,
977 ));
978 }
979 assert!(Arc::ptr_eq(&metasrv.selector_ctx().affinity, &affinity));
980 assert!(Arc::ptr_eq(
981 metasrv
982 .ddl_manager()
983 .create_context()
984 .affinity_resolver
985 .as_ref()
986 .unwrap(),
987 &resolver
988 ));
989 }
990
991 #[tokio::test]
992 async fn test_builder_wires_node_scheduling_discovery() {
993 use common_meta::peer::Peer;
994
995 use crate::key::NodeSchedulingRole;
996 use crate::test_util::put_datanodes;
997
998 let metasrv = MetasrvBuilder::new()
999 .options(MetasrvOptions {
1000 enable_telemetry: false,
1001 ..Default::default()
1002 })
1003 .build()
1004 .await
1005 .unwrap();
1006
1007 put_datanodes(
1008 metasrv.meta_peer_client(),
1009 vec![Peer::empty(1), Peer::empty(2)],
1010 )
1011 .await;
1012 metasrv
1013 .node_scheduling_manager()
1014 .mark_unschedulable(NodeSchedulingRole::Datanode, 2)
1015 .await
1016 .unwrap();
1017
1018 let datanodes = metasrv
1019 .selector_ctx()
1020 .peer_discovery
1021 .active_datanodes(None)
1022 .await
1023 .unwrap();
1024 assert_eq!(2, datanodes.len());
1025 for datanode in datanodes {
1026 let expected = datanode.peer.id != 2;
1027 assert_eq!(Some(expected), datanode.schedulable);
1028 }
1029 }
1030}