Skip to main content

meta_srv/
metasrv.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15pub mod builder;
16
17use std::fmt::{self, Display};
18use std::sync::atomic::{AtomicBool, Ordering};
19use std::sync::{Arc, Mutex, RwLock};
20use std::time::Duration;
21
22use api::v1::meta::{HeartbeatConfig, Role};
23use clap::ValueEnum;
24use common_base::Plugins;
25use common_base::readable_size::ReadableSize;
26use common_config::{Configurable, DEFAULT_DATA_HOME};
27use common_event_recorder::EventRecorderOptions;
28use common_greptimedb_telemetry::GreptimeDBTelemetryTask;
29use common_meta::affinity::{AffinityFallback, AffinityRef, AffinityResolverRef};
30use common_meta::cache_invalidator::CacheInvalidatorRef;
31use common_meta::ddl::allocator::resource_id::ResourceIdAllocatorRef;
32use common_meta::ddl_manager::DdlManagerRef;
33use common_meta::distributed_time_constants::{
34    self, BASE_HEARTBEAT_INTERVAL, default_distributed_time_constants, frontend_heartbeat_interval,
35};
36use common_meta::election::LeaderChangeMessage;
37pub use common_meta::election::{ElectionRef, MetasrvNodeInfo};
38use common_meta::key::TableMetadataManagerRef;
39use common_meta::key::runtime_switch::RuntimeSwitchManagerRef;
40use common_meta::kv_backend::{KvBackendRef, ResettableKvBackend, ResettableKvBackendRef};
41use common_meta::leadership_notifier::{
42    LeadershipChangeNotifier, LeadershipChangeNotifierCustomizerRef,
43};
44use common_meta::node_expiry_listener::NodeExpiryListener;
45use common_meta::peer::{Peer, PeerDiscoveryRef};
46use common_meta::reconciliation::manager::ReconciliationManagerRef;
47use common_meta::region_keeper::MemoryRegionKeeperRef;
48use common_meta::region_registry::LeaderRegionRegistryRef;
49use common_meta::stats::topic::TopicStatsRegistryRef;
50use common_meta::wal_provider::WalProviderRef;
51use common_options::datanode::DatanodeClientOptions;
52use common_options::memory::MemoryOptions;
53use common_procedure::ProcedureManagerRef;
54use common_procedure::options::ProcedureConfig;
55use common_stat::ResourceStatRef;
56use common_telemetry::logging::{LoggingOptions, TracingOptions};
57use common_telemetry::{error, info, warn};
58use common_time::util::DefaultSystemTimer;
59use common_wal::config::MetasrvWalConfig;
60use serde::{Deserialize, Serialize};
61use servers::grpc::GrpcOptions;
62use servers::http::HttpOptions;
63use servers::tls::TlsOption;
64use snafu::{OptionExt, ResultExt};
65use store_api::storage::RegionId;
66use tokio::sync::broadcast::error::RecvError;
67
68use crate::cluster::MetaPeerClientRef;
69use crate::discovery;
70use crate::discovery::node_info::NodeInfoAccessor;
71use crate::error::{
72    self, InitMetadataSnafu, KvBackendSnafu, Result, StartProcedureManagerSnafu,
73    StartTelemetryTaskSnafu, StopProcedureManagerSnafu,
74};
75use crate::failure_detector::PhiAccrualFailureDetectorOptions;
76use crate::gc::{GcSchedulerOptions, GcTickerRef};
77use crate::handler::{HeartbeatHandlerGroupBuilder, HeartbeatHandlerGroupRef};
78use crate::node_scheduling::NodeSchedulingManagerRef;
79use crate::procedure::ProcedureManagerListenerAdapter;
80use crate::procedure::drain_datanode::manager::DrainDatanodeManagerRef;
81use crate::procedure::region_migration::manager::RegionMigrationManagerRef;
82use crate::procedure::repartition::gc_requirement::RepartitionGcRequirementManagerRef;
83use crate::procedure::wal_prune::manager::WalPruneTickerRef;
84use crate::pubsub::{PublisherRef, SubscriptionManagerRef};
85use crate::region::flush_trigger::RegionFlushTickerRef;
86use crate::region::supervisor::RegionSupervisorTickerRef;
87use crate::selector::{RegionStatAwareSelector, Selector, SelectorType};
88use crate::service::mailbox::MailboxRef;
89use crate::service::store::cached_kv::LeaderCachedKvBackend;
90use crate::state::{StateRef, become_follower, become_leader};
91use crate::utils::database::DatabaseOperatorRef;
92
93pub const TABLE_ID_SEQ: &str = "table_id";
94pub const FLOW_ID_SEQ: &str = "flow_id";
95pub const METASRV_DATA_DIR: &str = "metasrv";
96
97// The datastores that implements metadata kvbackend.
98#[derive(Clone, Debug, PartialEq, Serialize, Default, Deserialize, ValueEnum)]
99#[serde(rename_all = "snake_case")]
100pub enum BackendImpl {
101    // Etcd as metadata storage.
102    #[default]
103    EtcdStore,
104    // In memory metadata storage - mostly used for testing.
105    MemoryStore,
106    #[cfg(feature = "pg_kvbackend")]
107    // Postgres as metadata storage.
108    PostgresStore,
109    #[cfg(feature = "mysql_kvbackend")]
110    // MySql as metadata storage.
111    MysqlStore,
112}
113
114/// Configuration options for the stats persistence.
115#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
116pub struct StatsPersistenceOptions {
117    /// TTL for the stats table that will be used to store the stats.
118    #[serde(with = "humantime_serde")]
119    pub ttl: Duration,
120    /// The interval to persist the stats.
121    #[serde(with = "humantime_serde")]
122    pub interval: Duration,
123}
124
125impl Default for StatsPersistenceOptions {
126    fn default() -> Self {
127        Self {
128            ttl: Duration::ZERO,
129            interval: Duration::from_secs(10 * 60),
130        }
131    }
132}
133
134/// Heartbeat configuration for a single node type.
135#[derive(Clone, PartialEq, Serialize, Deserialize, Debug)]
136#[serde(default)]
137pub struct HeartbeatOptions {
138    /// Heartbeat interval.
139    #[serde(with = "humantime_serde")]
140    pub interval: Duration,
141    /// Retry interval when heartbeat connection fails.
142    #[serde(with = "humantime_serde")]
143    pub retry_interval: Duration,
144}
145
146impl Default for HeartbeatOptions {
147    fn default() -> Self {
148        Self {
149            interval: BASE_HEARTBEAT_INTERVAL,
150            retry_interval: BASE_HEARTBEAT_INTERVAL,
151        }
152    }
153}
154
155impl HeartbeatOptions {
156    pub fn datanode_from(base_interval: Duration) -> Self {
157        Self {
158            interval: base_interval,
159            retry_interval: base_interval,
160        }
161    }
162
163    pub fn frontend_from(base_interval: Duration) -> Self {
164        Self {
165            interval: frontend_heartbeat_interval(base_interval),
166            retry_interval: base_interval,
167        }
168    }
169
170    pub fn flownode_from(base_interval: Duration) -> Self {
171        Self {
172            interval: base_interval,
173            retry_interval: base_interval,
174        }
175    }
176}
177
178impl From<HeartbeatOptions> for HeartbeatConfig {
179    fn from(opts: HeartbeatOptions) -> Self {
180        Self {
181            heartbeat_interval_ms: opts.interval.as_millis() as u64,
182            retry_interval_ms: opts.retry_interval.as_millis() as u64,
183            gc_enabled: false,
184        }
185    }
186}
187
188#[derive(Clone, PartialEq, Serialize, Deserialize, Debug)]
189#[serde(default)]
190pub struct BackendClientOptions {
191    #[serde(with = "humantime_serde")]
192    pub keep_alive_timeout: Duration,
193    #[serde(with = "humantime_serde")]
194    pub keep_alive_interval: Duration,
195    #[serde(with = "humantime_serde")]
196    pub connect_timeout: Duration,
197}
198
199impl Default for BackendClientOptions {
200    fn default() -> Self {
201        Self {
202            keep_alive_interval: Duration::from_secs(10),
203            keep_alive_timeout: Duration::from_secs(3),
204            connect_timeout: Duration::from_secs(3),
205        }
206    }
207}
208
209#[derive(Clone, PartialEq, Serialize, Deserialize)]
210#[serde(default)]
211pub struct MetasrvOptions {
212    /// The address the server listens on.
213    #[deprecated(note = "Use grpc.bind_addr instead")]
214    pub bind_addr: String,
215    /// The address the server advertises to the clients.
216    #[deprecated(note = "Use grpc.server_addr instead")]
217    pub server_addr: String,
218    /// The address of the store, e.g., etcd.
219    pub store_addrs: Vec<String>,
220    /// TLS configuration for kv store backend (PostgreSQL/MySQL)
221    /// Only applicable when using PostgreSQL or MySQL as the metadata store
222    #[serde(default)]
223    pub backend_tls: Option<TlsOption>,
224    /// The backend client options.
225    /// Currently, only applicable when using etcd as the metadata store.
226    #[serde(default)]
227    pub backend_client: BackendClientOptions,
228    /// The type of selector.
229    pub selector: SelectorType,
230    /// Whether to enable region failover.
231    pub enable_region_failover: bool,
232    /// The base heartbeat interval.
233    ///
234    /// This value is used to calculate the distributed time constants for components.
235    /// e.g., the region lease time is `heartbeat_interval * 3 + Duration::from_secs(1)`.
236    #[serde(with = "humantime_serde")]
237    pub heartbeat_interval: Duration,
238    /// The delay before starting region failure detection.
239    /// This delay helps prevent Metasrv from triggering unnecessary region failovers before all Datanodes are fully started.
240    /// Especially useful when the cluster is not deployed with GreptimeDB Operator and maintenance mode is not enabled.
241    #[serde(with = "humantime_serde")]
242    pub region_failure_detector_initialization_delay: Duration,
243    /// Whether to allow region failover on local WAL.
244    ///
245    /// If it's true, the region failover will be allowed even if the local WAL is used.
246    /// Note that this option is not recommended to be set to true, because it may lead to data loss during failover.
247    pub allow_region_failover_on_local_wal: bool,
248    pub grpc: GrpcOptions,
249    /// The HTTP server options.
250    pub http: HttpOptions,
251    /// The logging options.
252    pub logging: LoggingOptions,
253    /// The procedure options.
254    pub procedure: ProcedureConfig,
255    /// The failure detector options.
256    pub failure_detector: PhiAccrualFailureDetectorOptions,
257    /// The datanode options.
258    pub datanode: DatanodeClientOptions,
259    /// Whether to enable telemetry.
260    pub enable_telemetry: bool,
261    /// The data home directory.
262    pub data_home: String,
263    /// The WAL options.
264    pub wal: MetasrvWalConfig,
265    /// The store key prefix. If it is not empty, all keys in the store will be prefixed with it.
266    /// This is useful when multiple metasrv clusters share the same store.
267    pub store_key_prefix: String,
268    /// The max operations per txn
269    ///
270    /// This value is usually limited by which store is used for the `KvBackend`.
271    /// For example, if using etcd, this value should ensure that it is less than
272    /// or equal to the `--max-txn-ops` option value of etcd.
273    ///
274    /// TODO(jeremy): Currently, this option only affects the etcd store, but it may
275    /// also affect other stores in the future. In other words, each store needs to
276    /// limit the number of operations in a txn because an infinitely large txn could
277    /// potentially block other operations.
278    pub max_txn_ops: usize,
279    /// The factor that determines how often statistics should be flushed,
280    /// based on the number of received heartbeats. When the number of heartbeats
281    /// reaches this factor, a flush operation is triggered.
282    pub flush_stats_factor: usize,
283    /// The tracing options.
284    pub tracing: TracingOptions,
285    /// The memory options.
286    pub memory: MemoryOptions,
287    /// The datastore for kv metadata.
288    pub backend: BackendImpl,
289    #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))]
290    /// Table name of rds kv backend.
291    pub meta_table_name: String,
292    #[cfg(feature = "pg_kvbackend")]
293    /// Lock id for meta kv election. Only effect when using pg_kvbackend.
294    pub meta_election_lock_id: u64,
295    #[cfg(feature = "pg_kvbackend")]
296    /// Optional PostgreSQL schema for metadata table (defaults to current search_path if empty).
297    pub meta_schema_name: Option<String>,
298    #[cfg(feature = "pg_kvbackend")]
299    /// Automatically create PostgreSQL schema if it doesn't exist (default: true).
300    pub auto_create_schema: bool,
301    #[serde(with = "humantime_serde")]
302    pub node_max_idle_time: Duration,
303    /// The event recorder options.
304    pub event_recorder: EventRecorderOptions,
305    /// The stats persistence options.
306    pub stats_persistence: StatsPersistenceOptions,
307    /// The GC scheduler options.
308    pub gc: GcSchedulerOptions,
309}
310
311impl fmt::Debug for MetasrvOptions {
312    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
313        let mut debug_struct = f.debug_struct("MetasrvOptions");
314        debug_struct
315            .field("store_addrs", &self.sanitize_store_addrs())
316            .field("backend_tls", &self.backend_tls)
317            .field("selector", &self.selector)
318            .field("enable_region_failover", &self.enable_region_failover)
319            .field(
320                "allow_region_failover_on_local_wal",
321                &self.allow_region_failover_on_local_wal,
322            )
323            .field("grpc", &self.grpc)
324            .field("http", &self.http)
325            .field("logging", &self.logging)
326            .field("procedure", &self.procedure)
327            .field("failure_detector", &self.failure_detector)
328            .field("datanode", &self.datanode)
329            .field("enable_telemetry", &self.enable_telemetry)
330            .field("data_home", &self.data_home)
331            .field("wal", &self.wal)
332            .field("store_key_prefix", &self.store_key_prefix)
333            .field("max_txn_ops", &self.max_txn_ops)
334            .field("flush_stats_factor", &self.flush_stats_factor)
335            .field("tracing", &self.tracing)
336            .field("backend", &self.backend)
337            .field("event_recorder", &self.event_recorder)
338            .field("stats_persistence", &self.stats_persistence)
339            .field("heartbeat_interval", &self.heartbeat_interval)
340            .field("backend_client", &self.backend_client);
341
342        #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))]
343        debug_struct.field("meta_table_name", &self.meta_table_name);
344
345        #[cfg(feature = "pg_kvbackend")]
346        debug_struct.field("meta_election_lock_id", &self.meta_election_lock_id);
347        #[cfg(feature = "pg_kvbackend")]
348        debug_struct.field("meta_schema_name", &self.meta_schema_name);
349
350        debug_struct
351            .field("node_max_idle_time", &self.node_max_idle_time)
352            .finish()
353    }
354}
355
356const DEFAULT_METASRV_ADDR_PORT: &str = "3002";
357
358impl Default for MetasrvOptions {
359    fn default() -> Self {
360        Self {
361            #[allow(deprecated)]
362            bind_addr: String::new(),
363            #[allow(deprecated)]
364            server_addr: String::new(),
365            store_addrs: vec!["127.0.0.1:2379".to_string()],
366            backend_tls: Some(TlsOption::prefer()),
367            selector: SelectorType::default(),
368            enable_region_failover: false,
369            heartbeat_interval: distributed_time_constants::BASE_HEARTBEAT_INTERVAL,
370            region_failure_detector_initialization_delay: Duration::from_secs(10 * 60),
371            allow_region_failover_on_local_wal: false,
372            grpc: GrpcOptions {
373                bind_addr: format!("127.0.0.1:{}", DEFAULT_METASRV_ADDR_PORT),
374                ..Default::default()
375            },
376            http: HttpOptions::default(),
377            logging: LoggingOptions::default(),
378            procedure: ProcedureConfig {
379                max_retry_times: 12,
380                retry_delay: Duration::from_millis(500),
381                // The etcd the maximum size of any request is 1.5 MiB
382                // 1500KiB = 1536KiB (1.5MiB) - 36KiB (reserved size of key)
383                max_metadata_value_size: Some(ReadableSize::kb(1500)),
384                max_running_procedures: 128,
385            },
386            failure_detector: PhiAccrualFailureDetectorOptions::default(),
387            datanode: DatanodeClientOptions::default(),
388            enable_telemetry: true,
389            data_home: DEFAULT_DATA_HOME.to_string(),
390            wal: MetasrvWalConfig::default(),
391            store_key_prefix: String::new(),
392            max_txn_ops: 128,
393            flush_stats_factor: 3,
394            tracing: TracingOptions::default(),
395            memory: MemoryOptions::default(),
396            backend: BackendImpl::EtcdStore,
397            #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))]
398            meta_table_name: common_meta::kv_backend::DEFAULT_META_TABLE_NAME.to_string(),
399            #[cfg(feature = "pg_kvbackend")]
400            meta_election_lock_id: common_meta::kv_backend::DEFAULT_META_ELECTION_LOCK_ID,
401            #[cfg(feature = "pg_kvbackend")]
402            meta_schema_name: None,
403            #[cfg(feature = "pg_kvbackend")]
404            auto_create_schema: true,
405            node_max_idle_time: Duration::from_secs(24 * 60 * 60),
406            event_recorder: EventRecorderOptions::default(),
407            stats_persistence: StatsPersistenceOptions::default(),
408            gc: GcSchedulerOptions::default(),
409            backend_client: BackendClientOptions::default(),
410        }
411    }
412}
413
414impl Configurable for MetasrvOptions {
415    fn env_list_keys() -> Option<&'static [&'static str]> {
416        Some(&[
417            "wal.broker_endpoints",
418            "store_addrs",
419            "event_recorder.event_types",
420        ])
421    }
422}
423
424impl MetasrvOptions {
425    fn sanitize_store_addrs(&self) -> Vec<String> {
426        self.store_addrs
427            .iter()
428            .map(|addr| common_meta::kv_backend::util::sanitize_connection_string(addr))
429            .collect()
430    }
431}
432
433pub struct MetasrvInfo {
434    pub server_addr: String,
435}
436#[derive(Clone)]
437pub struct Context {
438    pub server_addr: String,
439    pub in_memory: ResettableKvBackendRef,
440    pub kv_backend: KvBackendRef,
441    pub leader_cached_kv_backend: ResettableKvBackendRef,
442    pub meta_peer_client: MetaPeerClientRef,
443    pub mailbox: MailboxRef,
444    pub election: Option<ElectionRef>,
445    pub is_infancy: bool,
446    pub table_metadata_manager: TableMetadataManagerRef,
447    pub cache_invalidator: CacheInvalidatorRef,
448    pub leader_region_registry: LeaderRegionRegistryRef,
449    pub topic_stats_registry: TopicStatsRegistryRef,
450    pub heartbeat_interval: Duration,
451    pub gc_enabled: bool,
452    pub is_handshake: bool,
453}
454
455impl Context {
456    pub fn reset_in_memory(&self) {
457        self.in_memory.reset();
458        self.leader_region_registry.reset();
459    }
460
461    pub fn with_handshake(mut self, is_handshake: bool) -> Self {
462        self.is_handshake = is_handshake;
463        self
464    }
465
466    pub fn heartbeat_options_for(&self, role: Role) -> HeartbeatOptions {
467        match role {
468            Role::Datanode => HeartbeatOptions::datanode_from(self.heartbeat_interval),
469            Role::Frontend => HeartbeatOptions::frontend_from(self.heartbeat_interval),
470            Role::Flownode => HeartbeatOptions::flownode_from(self.heartbeat_interval),
471        }
472    }
473}
474
475#[derive(Clone, Copy)]
476pub enum SelectTarget {
477    Datanode,
478    Flownode,
479}
480
481impl Display for SelectTarget {
482    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
483        match self {
484            SelectTarget::Datanode => write!(f, "datanode"),
485            SelectTarget::Flownode => write!(f, "flownode"),
486        }
487    }
488}
489
490#[derive(Clone)]
491pub struct SelectorContext {
492    pub peer_discovery: PeerDiscoveryRef,
493    /// Evaluator shared by datanode and flownode selection.
494    pub affinity: AffinityRef,
495    /// Whether selection may retry without affinity when candidates are insufficient.
496    pub affinity_fallback: AffinityFallback,
497}
498
499pub type SelectorRef = Arc<dyn Selector<Context = SelectorContext, Output = Vec<Peer>>>;
500
501/// Context passed to a selector factory during metasrv bootstrap.
502///
503/// The factory runs after bootstrap has constructed the selector configured by
504/// [`MetasrvOptions::selector`], so plugins can either decorate `base_selector` or
505/// build a completely different selector using bootstrap-only dependencies like
506/// [`MetaPeerClientRef`].
507pub struct SelectorFactoryContext {
508    pub metasrv_options: MetasrvOptions,
509    pub meta_peer_client: MetaPeerClientRef,
510    pub in_memory: ResettableKvBackendRef,
511    pub election: Option<ElectionRef>,
512    pub base_selector: SelectorRef,
513}
514
515/// Builds the final datanode selector metasrv should use.
516pub trait SelectorFactory: Send + Sync {
517    fn build(&self, ctx: SelectorFactoryContext) -> SelectorRef;
518
519    /// Builds the resolver shared by allocation and failover callers.
520    ///
521    /// The accessor includes last-known records of inactive source nodes; discovery
522    /// is the shared scheduling-aware view of active nodes.
523    fn build_affinity_resolver(
524        &self,
525        _node_info_accessor: Arc<dyn NodeInfoAccessor>,
526        _peer_discovery: PeerDiscoveryRef,
527    ) -> Option<AffinityResolverRef> {
528        None
529    }
530}
531
532/// Shared selector factory plugin registered through [`common_base::Plugins`].
533pub type SelectorFactoryRef = Arc<dyn SelectorFactory>;
534pub type RegionStatAwareSelectorRef =
535    Arc<dyn RegionStatAwareSelector<Context = SelectorContext, Output = Vec<(RegionId, Peer)>>>;
536
537pub struct MetaStateHandler {
538    subscribe_manager: Option<SubscriptionManagerRef>,
539    greptimedb_telemetry_task: Arc<GreptimeDBTelemetryTask>,
540    leader_cached_kv_backend: Arc<LeaderCachedKvBackend>,
541    leadership_change_notifier: LeadershipChangeNotifier,
542    state: StateRef,
543}
544
545impl MetaStateHandler {
546    pub async fn on_leader_start(&self) {
547        self.state.write().unwrap().next_state(become_leader(false));
548
549        if let Err(e) = self.leader_cached_kv_backend.load().await {
550            error!(e; "Failed to load kv into leader cache kv store");
551        } else {
552            self.state.write().unwrap().next_state(become_leader(true));
553        }
554
555        self.leadership_change_notifier
556            .notify_on_leader_start()
557            .await;
558
559        self.greptimedb_telemetry_task.should_report(true);
560    }
561
562    pub async fn on_leader_stop(&self) {
563        self.state.write().unwrap().next_state(become_follower());
564
565        self.leadership_change_notifier
566            .notify_on_leader_stop()
567            .await;
568
569        // Suspends reporting.
570        self.greptimedb_telemetry_task.should_report(false);
571
572        if let Some(sub_manager) = self.subscribe_manager.clone() {
573            info!("Leader changed, un_subscribe all");
574            if let Err(e) = sub_manager.unsubscribe_all() {
575                error!(e; "Failed to un_subscribe all");
576            }
577        }
578    }
579}
580
581pub struct Metasrv {
582    state: StateRef,
583    started: Arc<AtomicBool>,
584    start_time_ms: u64,
585    options: MetasrvOptions,
586    // It is only valid at the leader node and is used to temporarily
587    // store some data that will not be persisted.
588    in_memory: ResettableKvBackendRef,
589    kv_backend: KvBackendRef,
590    leader_cached_kv_backend: Arc<LeaderCachedKvBackend>,
591    meta_peer_client: MetaPeerClientRef,
592    // The selector is used to select a target datanode.
593    selector: SelectorRef,
594    selector_ctx: SelectorContext,
595    // The flow selector is used to select a target flownode.
596    flow_selector: SelectorRef,
597    handler_group: RwLock<Option<HeartbeatHandlerGroupRef>>,
598    handler_group_builder: Mutex<Option<HeartbeatHandlerGroupBuilder>>,
599    election: Option<ElectionRef>,
600    procedure_manager: ProcedureManagerRef,
601    mailbox: MailboxRef,
602    ddl_manager: DdlManagerRef,
603    wal_provider: WalProviderRef,
604    table_metadata_manager: TableMetadataManagerRef,
605    runtime_switch_manager: RuntimeSwitchManagerRef,
606    repartition_gc_requirement_manager: RepartitionGcRequirementManagerRef,
607    memory_region_keeper: MemoryRegionKeeperRef,
608    greptimedb_telemetry_task: Arc<GreptimeDBTelemetryTask>,
609    region_migration_manager: RegionMigrationManagerRef,
610    drain_datanode_manager: DrainDatanodeManagerRef,
611    region_supervisor_ticker: Option<RegionSupervisorTickerRef>,
612    cache_invalidator: CacheInvalidatorRef,
613    leader_region_registry: LeaderRegionRegistryRef,
614    topic_stats_registry: TopicStatsRegistryRef,
615    wal_prune_ticker: Option<WalPruneTickerRef>,
616    region_flush_ticker: Option<RegionFlushTickerRef>,
617    table_id_allocator: ResourceIdAllocatorRef,
618    reconciliation_manager: ReconciliationManagerRef,
619    resource_stat: ResourceStatRef,
620    gc_ticker: Option<GcTickerRef>,
621    database_operator: DatabaseOperatorRef,
622    node_scheduling_manager: NodeSchedulingManagerRef,
623
624    plugins: Plugins,
625}
626
627impl Metasrv {
628    pub(crate) async fn ensure_repartition_gc_enabled(&self) -> Result<()> {
629        self.repartition_gc_requirement_manager
630            .ensure_gc_enabled(self.options.gc.enable, &self.procedure_manager)
631            .await
632    }
633
634    pub async fn try_start(&self) -> Result<()> {
635        self.ensure_repartition_gc_enabled().await?;
636        self.try_start_after_gc_check().await
637    }
638
639    pub(crate) async fn try_start_after_gc_check(&self) -> Result<()> {
640        if self
641            .started
642            .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
643            .is_err()
644        {
645            warn!("Metasrv already started");
646            return Ok(());
647        }
648
649        let handler_group_builder =
650            self.handler_group_builder
651                .lock()
652                .unwrap()
653                .take()
654                .context(error::UnexpectedSnafu {
655                    violated: "expected heartbeat handler group builder",
656                })?;
657        *self.handler_group.write().unwrap() = Some(Arc::new(handler_group_builder.build()?));
658
659        // Creates default schema if not exists
660        self.table_metadata_manager
661            .init()
662            .await
663            .context(InitMetadataSnafu)?;
664
665        if let Some(election) = self.election() {
666            let procedure_manager = self.procedure_manager.clone();
667            let in_memory = self.in_memory.clone();
668            let leader_cached_kv_backend = self.leader_cached_kv_backend.clone();
669            let subscribe_manager = self.subscription_manager();
670            let mut rx = election.subscribe_leader_change();
671            let greptimedb_telemetry_task = self.greptimedb_telemetry_task.clone();
672            greptimedb_telemetry_task
673                .start()
674                .context(StartTelemetryTaskSnafu)?;
675
676            // Builds leadership change notifier.
677            let mut leadership_change_notifier = LeadershipChangeNotifier::default();
678            leadership_change_notifier.add_listener(self.wal_provider.clone());
679            leadership_change_notifier
680                .add_listener(Arc::new(ProcedureManagerListenerAdapter(procedure_manager)));
681            leadership_change_notifier.add_listener(Arc::new(NodeExpiryListener::new(
682                self.options.node_max_idle_time,
683                self.in_memory.clone(),
684            )));
685            if let Some(region_supervisor_ticker) = &self.region_supervisor_ticker {
686                leadership_change_notifier.add_listener(region_supervisor_ticker.clone() as _);
687            }
688            if let Some(wal_prune_ticker) = &self.wal_prune_ticker {
689                leadership_change_notifier.add_listener(wal_prune_ticker.clone() as _);
690            }
691            if let Some(region_flush_trigger) = &self.region_flush_ticker {
692                leadership_change_notifier.add_listener(region_flush_trigger.clone() as _);
693            }
694            if let Some(gc_ticker) = &self.gc_ticker {
695                leadership_change_notifier.add_listener(gc_ticker.clone() as _);
696            }
697            if let Some(customizer) = self.plugins.get::<LeadershipChangeNotifierCustomizerRef>() {
698                customizer.customize(&mut leadership_change_notifier);
699            }
700
701            let state_handler = MetaStateHandler {
702                greptimedb_telemetry_task,
703                subscribe_manager,
704                state: self.state.clone(),
705                leader_cached_kv_backend: leader_cached_kv_backend.clone(),
706                leadership_change_notifier,
707            };
708            let _handle = common_runtime::spawn_global(async move {
709                loop {
710                    match rx.recv().await {
711                        Ok(msg) => {
712                            in_memory.reset();
713                            leader_cached_kv_backend.reset();
714                            info!("Leader's cache has bean cleared on leader change: {msg}");
715                            match msg {
716                                LeaderChangeMessage::Elected(_) => {
717                                    state_handler.on_leader_start().await;
718                                }
719                                LeaderChangeMessage::StepDown(leader) => {
720                                    error!("Leader :{:?} step down", leader);
721
722                                    state_handler.on_leader_stop().await;
723                                }
724                            }
725                        }
726                        Err(RecvError::Closed) => {
727                            error!("Not expected, is leader election loop still running?");
728                            break;
729                        }
730                        Err(RecvError::Lagged(_)) => {
731                            break;
732                        }
733                    }
734                }
735
736                state_handler.on_leader_stop().await;
737            });
738
739            // Register candidate and keep lease in background.
740            {
741                let election = election.clone();
742                let started = self.started.clone();
743                let node_info = self.node_info();
744                let _handle = common_runtime::spawn_global(async move {
745                    while started.load(Ordering::Acquire) {
746                        let res = election.register_candidate(&node_info).await;
747                        if let Err(e) = res {
748                            warn!(e; "Metasrv register candidate error");
749                        }
750                    }
751                });
752            }
753
754            // Campaign
755            {
756                let election = election.clone();
757                let started = self.started.clone();
758                let _handle = common_runtime::spawn_global(async move {
759                    while started.load(Ordering::Acquire) {
760                        let res = election.campaign().await;
761                        if let Err(e) = res {
762                            warn!(e; "Metasrv election error");
763                        }
764                        election.reset_campaign().await;
765                        info!("Metasrv re-initiate election");
766                    }
767                    info!("Metasrv stopped");
768                });
769            }
770        } else {
771            warn!(
772                "Ensure only one instance of Metasrv is running, as there is no election service."
773            );
774
775            if let Err(e) = self.wal_provider.start().await {
776                error!(e; "Failed to start wal provider");
777            }
778            // Always load kv into cached kv store.
779            self.leader_cached_kv_backend
780                .load()
781                .await
782                .context(KvBackendSnafu)?;
783            self.procedure_manager
784                .start()
785                .await
786                .context(StartProcedureManagerSnafu)?;
787        }
788
789        info!("Metasrv started");
790
791        Ok(())
792    }
793
794    pub async fn shutdown(&self) -> Result<()> {
795        if self
796            .started
797            .compare_exchange(true, false, Ordering::AcqRel, Ordering::Acquire)
798            .is_err()
799        {
800            warn!("Metasrv already stopped");
801            return Ok(());
802        }
803
804        self.procedure_manager
805            .stop()
806            .await
807            .context(StopProcedureManagerSnafu)?;
808
809        info!("Metasrv stopped");
810
811        Ok(())
812    }
813
814    pub fn start_time_ms(&self) -> u64 {
815        self.start_time_ms
816    }
817
818    pub fn resource_stat(&self) -> &ResourceStatRef {
819        &self.resource_stat
820    }
821
822    pub fn node_info(&self) -> MetasrvNodeInfo {
823        let build_info = common_version::build_info();
824        MetasrvNodeInfo {
825            addr: self.options().grpc.server_addr.clone(),
826            version: build_info.version.to_string(),
827            git_commit: build_info.commit_short.to_string(),
828            start_time_ms: self.start_time_ms(),
829            total_cpu_millicores: self.resource_stat.get_total_cpu_millicores(),
830            total_memory_bytes: self.resource_stat.get_total_memory_bytes(),
831            cpu_usage_millicores: self.resource_stat.get_cpu_usage_millicores(),
832            memory_usage_bytes: self.resource_stat.get_memory_usage_bytes(),
833            hostname: hostname::get()
834                .unwrap_or_default()
835                .to_string_lossy()
836                .to_string(),
837        }
838    }
839
840    /// Looks up a datanode peer by peer_id, returning it only when it's alive.
841    /// A datanode is considered alive when it's still within the lease period.
842    pub(crate) async fn lookup_datanode_peer(&self, peer_id: u64) -> Result<Option<Peer>> {
843        discovery::utils::alive_datanode(
844            &DefaultSystemTimer,
845            self.meta_peer_client.as_ref(),
846            peer_id,
847            default_distributed_time_constants().datanode_lease,
848        )
849        .await
850    }
851
852    pub fn options(&self) -> &MetasrvOptions {
853        &self.options
854    }
855
856    pub fn in_memory(&self) -> &ResettableKvBackendRef {
857        &self.in_memory
858    }
859
860    pub fn kv_backend(&self) -> &KvBackendRef {
861        &self.kv_backend
862    }
863
864    /// Returns the undecorated peer client.
865    ///
866    /// Its `active_datanodes` does not know about node scheduling states. Use
867    /// [`Metasrv::selector_ctx`] for any consumer that places regions or picks datanodes.
868    pub fn meta_peer_client(&self) -> &MetaPeerClientRef {
869        &self.meta_peer_client
870    }
871
872    pub fn selector(&self) -> &SelectorRef {
873        &self.selector
874    }
875
876    /// Returns the selector context, whose `peer_discovery` stamps node scheduling states.
877    pub fn selector_ctx(&self) -> &SelectorContext {
878        &self.selector_ctx
879    }
880
881    pub fn flow_selector(&self) -> &SelectorRef {
882        &self.flow_selector
883    }
884
885    pub fn handler_group(&self) -> Option<HeartbeatHandlerGroupRef> {
886        self.handler_group.read().unwrap().clone()
887    }
888
889    pub fn election(&self) -> Option<&ElectionRef> {
890        self.election.as_ref()
891    }
892
893    pub fn mailbox(&self) -> &MailboxRef {
894        &self.mailbox
895    }
896
897    pub fn ddl_manager(&self) -> &DdlManagerRef {
898        &self.ddl_manager
899    }
900
901    pub fn procedure_manager(&self) -> &ProcedureManagerRef {
902        &self.procedure_manager
903    }
904
905    pub fn table_metadata_manager(&self) -> &TableMetadataManagerRef {
906        &self.table_metadata_manager
907    }
908
909    pub fn runtime_switch_manager(&self) -> &RuntimeSwitchManagerRef {
910        &self.runtime_switch_manager
911    }
912
913    pub fn memory_region_keeper(&self) -> &MemoryRegionKeeperRef {
914        &self.memory_region_keeper
915    }
916
917    pub fn region_migration_manager(&self) -> &RegionMigrationManagerRef {
918        &self.region_migration_manager
919    }
920
921    /// Returns the [`DrainDatanodeManagerRef`].
922    pub fn drain_datanode_manager(&self) -> &DrainDatanodeManagerRef {
923        &self.drain_datanode_manager
924    }
925
926    pub fn publish(&self) -> Option<PublisherRef> {
927        self.plugins.get::<PublisherRef>()
928    }
929
930    pub fn subscription_manager(&self) -> Option<SubscriptionManagerRef> {
931        self.plugins.get::<SubscriptionManagerRef>()
932    }
933
934    pub fn table_id_allocator(&self) -> &ResourceIdAllocatorRef {
935        &self.table_id_allocator
936    }
937
938    pub fn reconciliation_manager(&self) -> &ReconciliationManagerRef {
939        &self.reconciliation_manager
940    }
941
942    pub fn database_operator(&self) -> &DatabaseOperatorRef {
943        &self.database_operator
944    }
945
946    pub fn node_scheduling_manager(&self) -> &NodeSchedulingManagerRef {
947        &self.node_scheduling_manager
948    }
949
950    pub fn plugins(&self) -> &Plugins {
951        &self.plugins
952    }
953
954    pub fn started(&self) -> Arc<AtomicBool> {
955        self.started.clone()
956    }
957
958    pub fn gc_ticker(&self) -> Option<GcTickerRef> {
959        self.gc_ticker.as_ref().cloned()
960    }
961
962    #[inline]
963    pub fn new_ctx(&self) -> Context {
964        let server_addr = self.options().grpc.server_addr.clone();
965        let in_memory = self.in_memory.clone();
966        let kv_backend = self.kv_backend.clone();
967        let leader_cached_kv_backend = self.leader_cached_kv_backend.clone();
968        let meta_peer_client = self.meta_peer_client.clone();
969        let mailbox = self.mailbox.clone();
970        let election = self.election.clone();
971        let table_metadata_manager = self.table_metadata_manager.clone();
972        let cache_invalidator = self.cache_invalidator.clone();
973        let leader_region_registry = self.leader_region_registry.clone();
974        let topic_stats_registry = self.topic_stats_registry.clone();
975
976        Context {
977            server_addr,
978            in_memory,
979            kv_backend,
980            leader_cached_kv_backend,
981            meta_peer_client,
982            mailbox,
983            election,
984            is_infancy: false,
985            table_metadata_manager,
986            cache_invalidator,
987            leader_region_registry,
988            topic_stats_registry,
989            heartbeat_interval: self.options().heartbeat_interval,
990            gc_enabled: self.options().gc.enable,
991            is_handshake: false,
992        }
993    }
994}
995
996#[cfg(test)]
997mod tests {
998    use common_event_recorder::EventTypeFilter;
999
1000    use super::*;
1001    use crate::metasrv::MetasrvNodeInfo;
1002
1003    #[test]
1004    fn test_deserialize_metasrv_node_info() {
1005        let str = r#"{"addr":"127.0.0.1:4002","version":"0.1.0","git_commit":"1234567890","start_time_ms":1715145600}"#;
1006        let node_info: MetasrvNodeInfo = serde_json::from_str(str).unwrap();
1007        assert_eq!(node_info.addr, "127.0.0.1:4002");
1008        assert_eq!(node_info.version, "0.1.0");
1009        assert_eq!(node_info.git_commit, "1234567890");
1010        assert_eq!(node_info.start_time_ms, 1715145600);
1011    }
1012
1013    #[test]
1014    fn test_metasrv_event_recorder_options_preserve_event_type_filter_semantics() {
1015        let all = MetasrvOptions::default().event_recorder;
1016        let none: EventRecorderOptions = toml::from_str("ttl = '90d'\nevent_types = []").unwrap();
1017        let selected: EventRecorderOptions =
1018            toml::from_str("ttl = '90d'\nevent_types = ['create_database']").unwrap();
1019
1020        assert!(all.event_types.allows("future_event"));
1021        assert_eq!(
1022            none.event_types.as_ref(),
1023            &EventTypeFilter::Only(Default::default())
1024        );
1025        assert!(selected.event_types.allows("create_database"));
1026        assert!(!selected.event_types.allows("drop_database"));
1027    }
1028}