Skip to main content

risingwave_meta/rpc/
metrics.rs

1// Copyright 2022 RisingWave Labs
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
15use std::collections::{HashMap, HashSet};
16use std::sync::atomic::AtomicU64;
17use std::sync::{Arc, LazyLock};
18use std::time::Duration;
19
20use prometheus::core::{AtomicF64, GenericGaugeVec};
21use prometheus::{
22    GaugeVec, Histogram, HistogramVec, IntCounterVec, IntGauge, IntGaugeVec, Registry,
23    exponential_buckets, histogram_opts, register_gauge_vec_with_registry,
24    register_histogram_vec_with_registry, register_histogram_with_registry,
25    register_int_counter_vec_with_registry, register_int_gauge_vec_with_registry,
26    register_int_gauge_with_registry,
27};
28use risingwave_common::catalog::{FragmentTypeFlag, TableId};
29use risingwave_common::metrics::{
30    LabelGuardedHistogramVec, LabelGuardedIntCounterVec, LabelGuardedIntGaugeVec,
31    LabelGuardedUintGaugeVec,
32};
33use risingwave_common::monitor::GLOBAL_METRICS_REGISTRY;
34use risingwave_common::system_param::reader::SystemParamsRead;
35use risingwave_common::util::stream_graph_visitor::{
36    visit_stream_node_source_backfill, visit_stream_node_stream_scan,
37};
38use risingwave_common::{
39    register_guarded_histogram_vec_with_registry, register_guarded_int_counter_vec_with_registry,
40    register_guarded_int_gauge_vec_with_registry, register_guarded_uint_gauge_vec_with_registry,
41};
42use risingwave_connector::source::monitor::EnumeratorMetrics as SourceEnumeratorMetrics;
43use risingwave_meta_model::table::TableType;
44use risingwave_meta_model::{ObjectId, WorkerId};
45use risingwave_object_store::object::object_metrics::{
46    GLOBAL_OBJECT_STORE_METRICS, ObjectStoreMetrics,
47};
48use risingwave_pb::common::WorkerType;
49use risingwave_pb::meta::FragmentDistribution;
50use thiserror_ext::AsReport;
51use tokio::sync::oneshot::Sender;
52use tokio::task::JoinHandle;
53
54use crate::barrier::BarrierManagerRef;
55use crate::controller::catalog::CatalogControllerRef;
56use crate::controller::cluster::ClusterControllerRef;
57use crate::controller::system_param::SystemParamsControllerRef;
58use crate::controller::utils::PartialFragmentStateTables;
59use crate::hummock::HummockManagerRef;
60use crate::manager::MetadataManager;
61use crate::rpc::ElectionClientRef;
62
63struct BackfillFragmentInfo {
64    job_id: u32,
65    fragment_id: u32,
66    backfill_state_table_id: u32,
67    backfill_target_relation_id: u32,
68    backfill_type: &'static str,
69    backfill_epoch: u64,
70}
71
72#[derive(Clone)]
73pub struct MetaMetrics {
74    // ********************************** Meta ************************************
75    /// The number of workers in the cluster.
76    pub worker_num: IntGaugeVec,
77    /// The roles of all meta nodes in the cluster.
78    pub meta_type: IntGaugeVec,
79
80    // ********************************** gRPC ************************************
81    /// gRPC latency of meta services
82    pub grpc_latency: HistogramVec,
83
84    // ********************************** Barrier ************************************
85    /// The duration from barrier injection to commit
86    /// It is the sum of inflight-latency, sync-latency and wait-commit-latency
87    pub barrier_latency: LabelGuardedHistogramVec,
88    /// The duration from barrier complete to commit
89    pub barrier_wait_commit_latency: Histogram,
90    /// Latency between each barrier send
91    pub barrier_send_latency: LabelGuardedHistogramVec,
92    /// The number of all barriers. It is the sum of barriers that are in-flight or completed but
93    /// waiting for other barriers
94    pub all_barrier_nums: LabelGuardedIntGaugeVec,
95    /// The number of in-flight barriers
96    pub in_flight_barrier_nums: LabelGuardedIntGaugeVec,
97    /// The timestamp (UNIX epoch seconds) of the last committed barrier's epoch time.
98    pub last_committed_barrier_time: LabelGuardedIntGaugeVec,
99    /// The barrier interval of each database
100    pub barrier_interval_by_database: GaugeVec,
101
102    // ********************************** Snapshot Backfill ***************************
103    /// The barrier latency in second of `table_id` and snapshto backfill `barrier_type`
104    pub snapshot_backfill_barrier_latency: LabelGuardedHistogramVec, // (table_id, barrier_type)
105    /// The lags between the upstream epoch and the downstream epoch.
106    pub snapshot_backfill_lag: LabelGuardedIntGaugeVec, // (table_id, )
107    /// The number of inflight barriers of `table_id`
108    pub snapshot_backfill_inflight_barrier_num: LabelGuardedIntGaugeVec, // (table_id, _)
109
110    // ********************************** Recovery ************************************
111    pub recovery_failure_cnt: IntCounterVec,
112    pub recovery_latency: HistogramVec,
113
114    // ********************************** Hummock ************************************
115    /// Max committed epoch
116    pub max_committed_epoch: IntGauge,
117    /// Min committed epoch
118    pub min_committed_epoch: IntGauge,
119    /// The number of SSTs in each level
120    pub level_sst_num: IntGaugeVec,
121    /// The number of SSTs to be merged to next level in each level
122    pub level_compact_cnt: IntGaugeVec,
123    /// The number of compact tasks
124    pub compact_frequency: IntCounterVec,
125    /// Size of each level
126    pub level_file_size: IntGaugeVec,
127    /// Hummock version size
128    pub version_size: IntGauge,
129    /// The version Id of current version.
130    pub current_version_id: IntGauge,
131    /// The version id of checkpoint version.
132    pub checkpoint_version_id: IntGauge,
133    /// The smallest version id that is being pinned by worker nodes.
134    pub min_pinned_version_id: IntGauge,
135    /// The smallest version id that is being guarded by meta node safe points.
136    pub min_safepoint_version_id: IntGauge,
137    /// Compaction groups that is in write stop state.
138    pub write_stop_compaction_groups: IntGaugeVec,
139    /// The number of attempts to trigger full GC.
140    pub full_gc_trigger_count: IntGauge,
141    /// The number of candidate object to delete after scanning object store.
142    pub full_gc_candidate_object_count: Histogram,
143    /// The number of object to delete after filtering by meta node.
144    pub full_gc_selected_object_count: Histogram,
145    /// Hummock version stats
146    pub version_stats: IntGaugeVec,
147    /// Hummock version stats
148    pub materialized_view_stats: IntGaugeVec,
149    /// Total number of objects that is no longer referenced by versions.
150    pub stale_object_count: IntGauge,
151    /// Total size of objects that is no longer referenced by versions.
152    pub stale_object_size: IntGauge,
153    /// Total number of objects that is still referenced by non-current versions.
154    pub old_version_object_count: IntGauge,
155    /// Total size of objects that is still referenced by non-current versions.
156    pub old_version_object_size: IntGauge,
157    /// Total number of objects that is referenced by time travel.
158    pub time_travel_object_count: IntGauge,
159    /// Total number of objects that is referenced by current version.
160    pub current_version_object_count: IntGauge,
161    /// Total size of objects that is referenced by current version.
162    pub current_version_object_size: IntGauge,
163    /// Total number of objects that includes dangling objects.
164    pub total_object_count: IntGauge,
165    /// Total size of objects that includes dangling objects.
166    pub total_object_size: IntGauge,
167    /// Number of objects per table change log.
168    pub table_change_log_object_count: IntGaugeVec,
169    /// Size of objects per table change log.
170    pub table_change_log_object_size: IntGaugeVec,
171    /// Min epoch currently retained in table change log.
172    pub table_change_log_min_epoch: IntGaugeVec,
173    /// Latency of serving table change log requests.
174    pub table_change_log_get_latency: Histogram,
175    /// The number of hummock version delta log.
176    pub delta_log_count: IntGauge,
177    /// latency of version checkpoint
178    pub version_checkpoint_latency: Histogram,
179    /// Latency for hummock manager to acquire lock
180    pub hummock_manager_lock_time: HistogramVec,
181    /// Latency for hummock manager to really process a request after acquire the lock
182    pub hummock_manager_real_process_time: HistogramVec,
183    /// The number of compactions from one level to another level that have been skipped
184    pub compact_skip_frequency: IntCounterVec,
185    /// Bytes of lsm tree needed to reach balance
186    pub compact_pending_bytes: IntGaugeVec,
187    /// Per level compression ratio
188    pub compact_level_compression_ratio: GenericGaugeVec<AtomicF64>,
189    /// Per level number of running compaction task
190    pub level_compact_task_cnt: IntGaugeVec,
191    pub time_after_last_observation: Arc<AtomicU64>,
192    pub l0_compact_level_count: HistogramVec,
193    pub compact_task_size: HistogramVec,
194    pub compact_task_file_count: HistogramVec,
195    pub compact_task_batch_count: HistogramVec,
196    pub split_compaction_group_count: IntCounterVec,
197    pub state_table_count: IntGaugeVec,
198    pub branched_sst_count: IntGaugeVec,
199    pub compact_task_trivial_move_sst_count: HistogramVec,
200
201    pub compaction_event_consumed_latency: Histogram,
202    pub compaction_event_loop_iteration_latency: Histogram,
203    pub time_travel_vacuum_metadata_latency: Histogram,
204    pub time_travel_write_metadata_latency: Histogram,
205
206    // ********************************** Object Store ************************************
207    // Object store related metrics (for backup/restore and version checkpoint)
208    pub object_store_metric: Arc<ObjectStoreMetrics>,
209
210    // ********************************** Source ************************************
211    /// supervisor for which source is still up.
212    pub source_is_up: LabelGuardedIntGaugeVec,
213    /// Duration of a source worker `tick` execution (`list_splits` + `on_tick`), in seconds.
214    pub source_worker_tick_duration_seconds: LabelGuardedHistogramVec,
215    /// Number of source enumerator `on_tick` monitor round-trip failures.
216    pub source_enumerator_monitor_error_count: LabelGuardedIntCounterVec,
217    pub source_enumerator_metrics: Arc<SourceEnumeratorMetrics>,
218
219    // ********************************** Fragment ************************************
220    /// A dummy gauge metrics with its label to be the mapping from actor id to fragment id
221    pub actor_info: IntGaugeVec,
222    /// A dummy gauge metrics with its label to be the mapping from table id to actor id
223    pub table_info: IntGaugeVec,
224    /// A dummy gauge metrics with its label to be the mapping from actor id to sink id
225    pub sink_info: IntGaugeVec,
226    /// A dummy gauge metrics with its label to be relation info
227    pub relation_info: IntGaugeVec,
228    /// A dummy gauge metrics with its label to be the mapping from database id to database name
229    pub database_info: IntGaugeVec,
230    /// Backfill progress per fragment
231    pub backfill_fragment_progress: IntGaugeVec,
232    /// Max subscription retention configured for the table's changelog.
233    pub streaming_table_change_log_retention_seconds: IntGaugeVec,
234
235    // ********************************** System Params ************************************
236    /// A dummy gauge metric with labels carrying system parameter info.
237    /// Labels: (name, value)
238    pub system_param_info: IntGaugeVec,
239
240    /// Write throughput of commit epoch for each stable
241    pub table_write_throughput: IntCounterVec,
242
243    /// The number of compaction groups that have been triggered to move
244    pub merge_compaction_group_count: IntCounterVec,
245
246    // ********************************** Auto Schema Change ************************************
247    pub auto_schema_change_failure_cnt: LabelGuardedIntCounterVec,
248    pub auto_schema_change_success_cnt: LabelGuardedIntCounterVec,
249    pub auto_schema_change_latency: LabelGuardedHistogramVec,
250
251    pub time_travel_version_replay_latency: Histogram,
252
253    pub compaction_group_count: IntGauge,
254    pub compaction_group_size: IntGaugeVec,
255    pub compaction_group_file_count: IntGaugeVec,
256    pub compaction_group_throughput: IntGaugeVec,
257
258    // ********************************** Refresh Manager ************************************
259    pub refresh_job_duration: LabelGuardedUintGaugeVec,
260    pub refresh_job_finish_cnt: LabelGuardedIntCounterVec,
261    pub refresh_cron_job_trigger_cnt: LabelGuardedIntCounterVec,
262    pub refresh_cron_job_miss_cnt: LabelGuardedIntCounterVec,
263}
264
265pub static GLOBAL_META_METRICS: LazyLock<MetaMetrics> =
266    LazyLock::new(|| MetaMetrics::new(&GLOBAL_METRICS_REGISTRY));
267
268impl MetaMetrics {
269    fn new(registry: &Registry) -> Self {
270        let opts = histogram_opts!(
271            "meta_grpc_duration_seconds",
272            "gRPC latency of meta services",
273            exponential_buckets(0.0001, 2.0, 20).unwrap() // max 52s
274        );
275        let grpc_latency =
276            register_histogram_vec_with_registry!(opts, &["path"], registry).unwrap();
277
278        let opts = histogram_opts!(
279            "meta_barrier_duration_seconds",
280            "barrier latency",
281            exponential_buckets(0.1, 1.5, 20).unwrap() // max 221s
282        );
283        let barrier_latency =
284            register_guarded_histogram_vec_with_registry!(opts, &["database_id"], registry)
285                .unwrap();
286
287        let opts = histogram_opts!(
288            "meta_barrier_wait_commit_duration_seconds",
289            "barrier_wait_commit_latency",
290            exponential_buckets(0.1, 1.5, 20).unwrap() // max 221s
291        );
292        let barrier_wait_commit_latency =
293            register_histogram_with_registry!(opts, registry).unwrap();
294
295        let opts = histogram_opts!(
296            "meta_barrier_send_duration_seconds",
297            "barrier send latency",
298            exponential_buckets(0.1, 1.5, 19).unwrap() // max 148s
299        );
300        let barrier_send_latency =
301            register_guarded_histogram_vec_with_registry!(opts, &["database_id"], registry)
302                .unwrap();
303        let barrier_interval_by_database = register_gauge_vec_with_registry!(
304            "meta_barrier_interval_by_database",
305            "barrier interval of each database",
306            &["database_id"],
307            registry
308        )
309        .unwrap();
310
311        let all_barrier_nums = register_guarded_int_gauge_vec_with_registry!(
312            "all_barrier_nums",
313            "num of of all_barrier",
314            &["database_id"],
315            registry
316        )
317        .unwrap();
318        let in_flight_barrier_nums = register_guarded_int_gauge_vec_with_registry!(
319            "in_flight_barrier_nums",
320            "num of of in_flight_barrier",
321            &["database_id"],
322            registry
323        )
324        .unwrap();
325        let last_committed_barrier_time = register_guarded_int_gauge_vec_with_registry!(
326            "last_committed_barrier_time",
327            "The timestamp (UNIX epoch seconds) of the last committed barrier's epoch time.",
328            &["database_id"],
329            registry
330        )
331        .unwrap();
332
333        // snapshot backfill metrics
334        let opts = histogram_opts!(
335            "meta_snapshot_backfill_barrier_duration_seconds",
336            "snapshot backfill barrier latency",
337            exponential_buckets(0.1, 1.5, 20).unwrap() // max 221s
338        );
339        let snapshot_backfill_barrier_latency = register_guarded_histogram_vec_with_registry!(
340            opts,
341            &["table_id", "barrier_type"],
342            registry
343        )
344        .unwrap();
345
346        let snapshot_backfill_lag = register_guarded_int_gauge_vec_with_registry!(
347            "meta_snapshot_backfill_upstream_lag",
348            "snapshot backfill upstream_lag",
349            &["table_id"],
350            registry
351        )
352        .unwrap();
353        let snapshot_backfill_inflight_barrier_num = register_guarded_int_gauge_vec_with_registry!(
354            "meta_snapshot_backfill_inflight_barrier_num",
355            "snapshot backfill inflight_barrier_num",
356            &["table_id"],
357            registry
358        )
359        .unwrap();
360
361        let max_committed_epoch = register_int_gauge_with_registry!(
362            "storage_max_committed_epoch",
363            "max committed epoch",
364            registry
365        )
366        .unwrap();
367
368        let min_committed_epoch = register_int_gauge_with_registry!(
369            "storage_min_committed_epoch",
370            "min committed epoch",
371            registry
372        )
373        .unwrap();
374
375        let level_sst_num = register_int_gauge_vec_with_registry!(
376            "storage_level_sst_num",
377            "num of SSTs in each level",
378            &["level_index"],
379            registry
380        )
381        .unwrap();
382
383        let level_compact_cnt = register_int_gauge_vec_with_registry!(
384            "storage_level_compact_cnt",
385            "num of SSTs to be merged to next level in each level",
386            &["level_index"],
387            registry
388        )
389        .unwrap();
390
391        let compact_frequency = register_int_counter_vec_with_registry!(
392            "storage_level_compact_frequency",
393            "The number of compactions from one level to another level that have completed or failed.",
394            &["compactor", "group", "task_type", "result"],
395            registry
396        )
397        .unwrap();
398        let compact_skip_frequency = register_int_counter_vec_with_registry!(
399            "storage_skip_compact_frequency",
400            "The number of compactions from one level to another level that have been skipped.",
401            &["level", "type"],
402            registry
403        )
404        .unwrap();
405
406        let version_size =
407            register_int_gauge_with_registry!("storage_version_size", "version size", registry)
408                .unwrap();
409
410        let current_version_id = register_int_gauge_with_registry!(
411            "storage_current_version_id",
412            "current version id",
413            registry
414        )
415        .unwrap();
416
417        let checkpoint_version_id = register_int_gauge_with_registry!(
418            "storage_checkpoint_version_id",
419            "checkpoint version id",
420            registry
421        )
422        .unwrap();
423
424        let min_pinned_version_id = register_int_gauge_with_registry!(
425            "storage_min_pinned_version_id",
426            "min pinned version id",
427            registry
428        )
429        .unwrap();
430
431        let write_stop_compaction_groups = register_int_gauge_vec_with_registry!(
432            "storage_write_stop_compaction_groups",
433            "compaction groups of write stop state",
434            &["compaction_group_id"],
435            registry
436        )
437        .unwrap();
438
439        let full_gc_trigger_count = register_int_gauge_with_registry!(
440            "storage_full_gc_trigger_count",
441            "the number of attempts to trigger full GC",
442            registry
443        )
444        .unwrap();
445
446        let opts = histogram_opts!(
447            "storage_full_gc_candidate_object_count",
448            "the number of candidate object to delete after scanning object store",
449            exponential_buckets(1.0, 10.0, 6).unwrap()
450        );
451        let full_gc_candidate_object_count =
452            register_histogram_with_registry!(opts, registry).unwrap();
453
454        let opts = histogram_opts!(
455            "storage_full_gc_selected_object_count",
456            "the number of object to delete after filtering by meta node",
457            exponential_buckets(1.0, 10.0, 6).unwrap()
458        );
459        let full_gc_selected_object_count =
460            register_histogram_with_registry!(opts, registry).unwrap();
461
462        let min_safepoint_version_id = register_int_gauge_with_registry!(
463            "storage_min_safepoint_version_id",
464            "min safepoint version id",
465            registry
466        )
467        .unwrap();
468
469        let level_file_size = register_int_gauge_vec_with_registry!(
470            "storage_level_total_file_size",
471            "KBs total file bytes in each level",
472            &["level_index"],
473            registry
474        )
475        .unwrap();
476
477        let version_stats = register_int_gauge_vec_with_registry!(
478            "storage_version_stats",
479            "per table stats in current hummock version",
480            &["table_id", "metric"],
481            registry
482        )
483        .unwrap();
484
485        let materialized_view_stats = register_int_gauge_vec_with_registry!(
486            "storage_materialized_view_stats",
487            "per materialized view stats in current hummock version",
488            &["table_id", "metric"],
489            registry
490        )
491        .unwrap();
492
493        let stale_object_count = register_int_gauge_with_registry!(
494            "storage_stale_object_count",
495            "total number of objects that is no longer referenced by versions.",
496            registry
497        )
498        .unwrap();
499
500        let stale_object_size = register_int_gauge_with_registry!(
501            "storage_stale_object_size",
502            "total size of objects that is no longer referenced by versions.",
503            registry
504        )
505        .unwrap();
506
507        let old_version_object_count = register_int_gauge_with_registry!(
508            "storage_old_version_object_count",
509            "total number of objects that is still referenced by non-current versions",
510            registry
511        )
512        .unwrap();
513
514        let old_version_object_size = register_int_gauge_with_registry!(
515            "storage_old_version_object_size",
516            "total size of objects that is still referenced by non-current versions",
517            registry
518        )
519        .unwrap();
520
521        let current_version_object_count = register_int_gauge_with_registry!(
522            "storage_current_version_object_count",
523            "total number of objects that is referenced by current version",
524            registry
525        )
526        .unwrap();
527
528        let current_version_object_size = register_int_gauge_with_registry!(
529            "storage_current_version_object_size",
530            "total size of objects that is referenced by current version",
531            registry
532        )
533        .unwrap();
534
535        let total_object_count = register_int_gauge_with_registry!(
536            "storage_total_object_count",
537            "Total number of objects that includes dangling objects. Note that the metric is updated right before full GC. So subsequent full GC may reduce the actual value significantly, without updating the metric.",
538            registry
539        ).unwrap();
540
541        let total_object_size = register_int_gauge_with_registry!(
542            "storage_total_object_size",
543            "Total size of objects that includes dangling objects. Note that the metric is updated right before full GC. So subsequent full GC may reduce the actual value significantly, without updating the metric.",
544            registry
545        ).unwrap();
546
547        let table_change_log_object_count = register_int_gauge_vec_with_registry!(
548            "storage_table_change_log_object_count",
549            "per table change log object count",
550            &["table_id"],
551            registry
552        )
553        .unwrap();
554
555        let table_change_log_object_size = register_int_gauge_vec_with_registry!(
556            "storage_table_change_log_object_size",
557            "per table change log object size",
558            &["table_id"],
559            registry
560        )
561        .unwrap();
562
563        let table_change_log_min_epoch = register_int_gauge_vec_with_registry!(
564            "storage_table_change_log_min_epoch",
565            "min epoch currently retained in table change log",
566            &["table_id"],
567            registry
568        )
569        .unwrap();
570
571        let opts = histogram_opts!(
572            "storage_table_change_log_get_latency",
573            "latency of serving table change log requests",
574            exponential_buckets(0.001, 5.0, 7).unwrap()
575        );
576        let table_change_log_get_latency =
577            register_histogram_with_registry!(opts, registry).unwrap();
578
579        let time_travel_object_count = register_int_gauge_with_registry!(
580            "storage_time_travel_object_count",
581            "total number of objects that is referenced by time travel.",
582            registry
583        )
584        .unwrap();
585
586        let delta_log_count = register_int_gauge_with_registry!(
587            "storage_delta_log_count",
588            "total number of hummock version delta log",
589            registry
590        )
591        .unwrap();
592
593        let opts = histogram_opts!(
594            "storage_version_checkpoint_latency",
595            "hummock version checkpoint latency",
596            exponential_buckets(0.1, 1.5, 20).unwrap()
597        );
598        let version_checkpoint_latency = register_histogram_with_registry!(opts, registry).unwrap();
599
600        let opts = histogram_opts!(
601            "hummock_manager_lock_time",
602            "latency for hummock manager to acquire the rwlock",
603            exponential_buckets(0.02, 2.5, 10).unwrap() // max 76s
604        );
605        let hummock_manager_lock_time =
606            register_histogram_vec_with_registry!(opts, &["lock_name", "lock_type"], registry)
607                .unwrap();
608
609        let opts = histogram_opts!(
610            "meta_hummock_manager_real_process_time",
611            "latency for hummock manager to really process the request",
612            exponential_buckets(0.02, 2.5, 10).unwrap() // max 76s
613        );
614        let hummock_manager_real_process_time =
615            register_histogram_vec_with_registry!(opts, &["method", "lock_name"], registry)
616                .unwrap();
617
618        let worker_num = register_int_gauge_vec_with_registry!(
619            "worker_num",
620            "number of nodes in the cluster",
621            &["worker_type"],
622            registry,
623        )
624        .unwrap();
625
626        let meta_type = register_int_gauge_vec_with_registry!(
627            "meta_num",
628            "role of meta nodes in the cluster",
629            &["worker_addr", "role"],
630            registry,
631        )
632        .unwrap();
633
634        let compact_pending_bytes = register_int_gauge_vec_with_registry!(
635            "storage_compact_pending_bytes",
636            "bytes of lsm tree needed to reach balance",
637            &["group"],
638            registry
639        )
640        .unwrap();
641
642        let compact_level_compression_ratio = register_gauge_vec_with_registry!(
643            "storage_compact_level_compression_ratio",
644            "compression ratio of each level of the lsm tree",
645            &["group", "level", "algorithm"],
646            registry
647        )
648        .unwrap();
649
650        let level_compact_task_cnt = register_int_gauge_vec_with_registry!(
651            "storage_level_compact_task_cnt",
652            "num of compact_task organized by group and level",
653            &["task"],
654            registry
655        )
656        .unwrap();
657
658        let time_travel_vacuum_metadata_latency = register_histogram_with_registry!(
659            histogram_opts!(
660                "storage_time_travel_vacuum_metadata_latency",
661                "Latency of vacuuming metadata for time travel",
662                exponential_buckets(0.1, 1.5, 20).unwrap()
663            ),
664            registry
665        )
666        .unwrap();
667        let time_travel_write_metadata_latency = register_histogram_with_registry!(
668            histogram_opts!(
669                "storage_time_travel_write_metadata_latency",
670                "Latency of writing metadata for time travel",
671                exponential_buckets(0.1, 1.5, 20).unwrap()
672            ),
673            registry
674        )
675        .unwrap();
676
677        let object_store_metric = Arc::new(GLOBAL_OBJECT_STORE_METRICS.clone());
678
679        let recovery_failure_cnt = register_int_counter_vec_with_registry!(
680            "recovery_failure_cnt",
681            "Number of failed recovery attempts",
682            &["recovery_type"],
683            registry
684        )
685        .unwrap();
686        let opts = histogram_opts!(
687            "recovery_latency",
688            "Latency of the recovery process",
689            exponential_buckets(0.1, 1.5, 20).unwrap() // max 221s
690        );
691        let recovery_latency =
692            register_histogram_vec_with_registry!(opts, &["recovery_type"], registry).unwrap();
693
694        let auto_schema_change_failure_cnt = register_guarded_int_counter_vec_with_registry!(
695            "auto_schema_change_failure_cnt",
696            "Number of failed auto schema change",
697            &["table_id", "table_name"],
698            registry
699        )
700        .unwrap();
701
702        let auto_schema_change_success_cnt = register_guarded_int_counter_vec_with_registry!(
703            "auto_schema_change_success_cnt",
704            "Number of success auto schema change",
705            &["table_id", "table_name"],
706            registry
707        )
708        .unwrap();
709
710        let opts = histogram_opts!(
711            "auto_schema_change_latency",
712            "Latency of the auto schema change process",
713            exponential_buckets(0.1, 1.5, 20).unwrap() // max 221s
714        );
715        let auto_schema_change_latency = register_guarded_histogram_vec_with_registry!(
716            opts,
717            &["table_id", "table_name"],
718            registry
719        )
720        .unwrap();
721
722        let source_is_up = register_guarded_int_gauge_vec_with_registry!(
723            "source_status_is_up",
724            "source is up or not",
725            &["source_id", "source_name"],
726            registry
727        )
728        .unwrap();
729        let opts = histogram_opts!(
730            "source_worker_tick_duration_seconds",
731            "Duration of a source worker tick (list_splits + on_tick) in seconds",
732            exponential_buckets(0.1, 1.5, 20).unwrap() // max ~221s
733        );
734        let source_worker_tick_duration_seconds = register_guarded_histogram_vec_with_registry!(
735            opts,
736            &["source_id", "source_name"],
737            registry
738        )
739        .unwrap();
740        let source_enumerator_monitor_error_count =
741            register_guarded_int_counter_vec_with_registry!(
742                "source_enumerator_monitor_error_count",
743                "Number of source enumerator on_tick monitor round-trip failures",
744                &["source_id", "source_name"],
745                registry
746            )
747            .unwrap();
748        let source_enumerator_metrics = Arc::new(SourceEnumeratorMetrics::default());
749
750        let actor_info = register_int_gauge_vec_with_registry!(
751            "actor_info",
752            "Mapping from actor id to (fragment id, compute node)",
753            &["actor_id", "fragment_id", "compute_node"],
754            registry
755        )
756        .unwrap();
757
758        let table_info = register_int_gauge_vec_with_registry!(
759            "table_info",
760            "Mapping from table id to (actor id, table name)",
761            &[
762                "materialized_view_id",
763                "table_id",
764                "fragment_id",
765                "table_name",
766                "table_type",
767                "compaction_group_id"
768            ],
769            registry
770        )
771        .unwrap();
772
773        let sink_info = register_int_gauge_vec_with_registry!(
774            "sink_info",
775            "Mapping from actor id to (actor id, sink name)",
776            &["actor_id", "sink_id", "sink_name",],
777            registry
778        )
779        .unwrap();
780
781        let relation_info = register_int_gauge_vec_with_registry!(
782            "relation_info",
783            "Information of the database relation (table/source/sink/materialized view/index/internal)",
784            &["id", "database", "schema", "name", "resource_group", "type"],
785            registry
786        )
787        .unwrap();
788
789        let streaming_table_change_log_retention_seconds = register_int_gauge_vec_with_registry!(
790            "streaming_table_change_log_retention_seconds",
791            "Max subscription retention configured for the table change log in seconds",
792            &["table_id"],
793            registry
794        )
795        .unwrap();
796
797        let database_info = register_int_gauge_vec_with_registry!(
798            "database_info",
799            "Mapping from database id to database name",
800            &["database_id", "database_name"],
801            registry
802        )
803        .unwrap();
804
805        let backfill_fragment_progress = register_int_gauge_vec_with_registry!(
806            "backfill_fragment_progress",
807            "Backfill progress per fragment",
808            &[
809                "job_id",
810                "fragment_id",
811                "backfill_state_table_id",
812                "backfill_target_relation_id",
813                "backfill_target_relation_name",
814                "backfill_target_relation_type",
815                "backfill_type",
816                "backfill_epoch",
817                "upstream_type",
818                "backfill_progress",
819            ],
820            registry
821        )
822        .unwrap();
823
824        let l0_compact_level_count = register_histogram_vec_with_registry!(
825            "storage_l0_compact_level_count",
826            "level_count of l0 compact task",
827            &["group", "type"],
828            registry
829        )
830        .unwrap();
831
832        // System parameter info
833        let system_param_info = register_int_gauge_vec_with_registry!(
834            "system_param_info",
835            "Information of system parameters",
836            &["name", "value"],
837            registry
838        )
839        .unwrap();
840
841        let opts = histogram_opts!(
842            "storage_compact_task_size",
843            "Total size of compact that have been issued to state store",
844            exponential_buckets(1048576.0, 2.0, 16).unwrap()
845        );
846
847        let compact_task_size =
848            register_histogram_vec_with_registry!(opts, &["group", "type"], registry).unwrap();
849
850        let compact_task_file_count = register_histogram_vec_with_registry!(
851            "storage_compact_task_file_count",
852            "file count of compact task",
853            &["group", "type"],
854            registry
855        )
856        .unwrap();
857        let opts = histogram_opts!(
858            "storage_compact_task_batch_count",
859            "count of compact task batch",
860            exponential_buckets(1.0, 2.0, 8).unwrap()
861        );
862        let compact_task_batch_count =
863            register_histogram_vec_with_registry!(opts, &["type"], registry).unwrap();
864
865        let table_write_throughput = register_int_counter_vec_with_registry!(
866            "storage_commit_write_throughput",
867            "The number of compactions from one level to another level that have been skipped.",
868            &["table_id"],
869            registry
870        )
871        .unwrap();
872
873        let split_compaction_group_count = register_int_counter_vec_with_registry!(
874            "storage_split_compaction_group_count",
875            "Count of trigger split compaction group",
876            &["group"],
877            registry
878        )
879        .unwrap();
880
881        let state_table_count = register_int_gauge_vec_with_registry!(
882            "storage_state_table_count",
883            "Count of stable table per compaction group",
884            &["group"],
885            registry
886        )
887        .unwrap();
888
889        let branched_sst_count = register_int_gauge_vec_with_registry!(
890            "storage_branched_sst_count",
891            "Count of branched sst per compaction group",
892            &["group"],
893            registry
894        )
895        .unwrap();
896
897        let opts = histogram_opts!(
898            "storage_compaction_event_consumed_latency",
899            "The latency(ms) of each event being consumed",
900            exponential_buckets(1.0, 1.5, 30).unwrap() // max 191s
901        );
902        let compaction_event_consumed_latency =
903            register_histogram_with_registry!(opts, registry).unwrap();
904
905        let opts = histogram_opts!(
906            "storage_compaction_event_loop_iteration_latency",
907            "The latency(ms) of each iteration of the compaction event loop",
908            exponential_buckets(1.0, 1.5, 30).unwrap() // max 191s
909        );
910        let compaction_event_loop_iteration_latency =
911            register_histogram_with_registry!(opts, registry).unwrap();
912
913        let merge_compaction_group_count = register_int_counter_vec_with_registry!(
914            "storage_merge_compaction_group_count",
915            "Count of trigger merge compaction group",
916            &["group"],
917            registry
918        )
919        .unwrap();
920
921        let opts = histogram_opts!(
922            "storage_time_travel_version_replay_latency",
923            "The latency(ms) of replaying a hummock version for time travel",
924            exponential_buckets(0.01, 10.0, 6).unwrap()
925        );
926        let time_travel_version_replay_latency =
927            register_histogram_with_registry!(opts, registry).unwrap();
928
929        let compaction_group_count = register_int_gauge_with_registry!(
930            "storage_compaction_group_count",
931            "The number of compaction groups",
932            registry,
933        )
934        .unwrap();
935
936        let compaction_group_size = register_int_gauge_vec_with_registry!(
937            "storage_compaction_group_size",
938            "The size of compaction group",
939            &["group"],
940            registry
941        )
942        .unwrap();
943
944        let compaction_group_file_count = register_int_gauge_vec_with_registry!(
945            "storage_compaction_group_file_count",
946            "The file count of compaction group",
947            &["group"],
948            registry
949        )
950        .unwrap();
951
952        let compaction_group_throughput = register_int_gauge_vec_with_registry!(
953            "storage_compaction_group_throughput",
954            "The throughput of compaction group",
955            &["group"],
956            registry
957        )
958        .unwrap();
959
960        let opts = histogram_opts!(
961            "storage_compact_task_trivial_move_sst_count",
962            "sst count of compact trivial-move task",
963            exponential_buckets(1.0, 2.0, 8).unwrap()
964        );
965        let compact_task_trivial_move_sst_count =
966            register_histogram_vec_with_registry!(opts, &["group"], registry).unwrap();
967
968        let refresh_job_duration = register_guarded_uint_gauge_vec_with_registry!(
969            "meta_refresh_job_duration",
970            "The duration of refresh job",
971            &["table_id", "status"],
972            registry
973        )
974        .unwrap();
975        let refresh_job_finish_cnt = register_guarded_int_counter_vec_with_registry!(
976            "meta_refresh_job_finish_cnt",
977            "The number of finished refresh jobs",
978            &["table_id", "status"],
979            registry
980        )
981        .unwrap();
982        let refresh_cron_job_trigger_cnt = register_guarded_int_counter_vec_with_registry!(
983            "meta_refresh_cron_job_trigger_cnt",
984            "The number of cron refresh jobs triggered",
985            &["table_id"],
986            registry
987        )
988        .unwrap();
989        let refresh_cron_job_miss_cnt = register_guarded_int_counter_vec_with_registry!(
990            "meta_refresh_cron_job_miss_cnt",
991            "The number of cron refresh jobs missed",
992            &["table_id"],
993            registry
994        )
995        .unwrap();
996
997        Self {
998            grpc_latency,
999            barrier_latency,
1000            barrier_wait_commit_latency,
1001            barrier_send_latency,
1002            all_barrier_nums,
1003            in_flight_barrier_nums,
1004            last_committed_barrier_time,
1005            barrier_interval_by_database,
1006            snapshot_backfill_barrier_latency,
1007            snapshot_backfill_lag,
1008            snapshot_backfill_inflight_barrier_num,
1009            recovery_failure_cnt,
1010            recovery_latency,
1011
1012            max_committed_epoch,
1013            min_committed_epoch,
1014            level_sst_num,
1015            level_compact_cnt,
1016            compact_frequency,
1017            compact_skip_frequency,
1018            level_file_size,
1019            version_size,
1020            version_stats,
1021            materialized_view_stats,
1022            stale_object_count,
1023            stale_object_size,
1024            old_version_object_count,
1025            old_version_object_size,
1026            time_travel_object_count,
1027            current_version_object_count,
1028            current_version_object_size,
1029            total_object_count,
1030            total_object_size,
1031            table_change_log_object_count,
1032            table_change_log_object_size,
1033            table_change_log_min_epoch,
1034            table_change_log_get_latency,
1035            delta_log_count,
1036            version_checkpoint_latency,
1037            current_version_id,
1038            checkpoint_version_id,
1039            min_pinned_version_id,
1040            min_safepoint_version_id,
1041            write_stop_compaction_groups,
1042            full_gc_trigger_count,
1043            full_gc_candidate_object_count,
1044            full_gc_selected_object_count,
1045            hummock_manager_lock_time,
1046            hummock_manager_real_process_time,
1047            time_after_last_observation: Arc::new(AtomicU64::new(0)),
1048            worker_num,
1049            meta_type,
1050            compact_pending_bytes,
1051            compact_level_compression_ratio,
1052            level_compact_task_cnt,
1053            object_store_metric,
1054            source_is_up,
1055            source_worker_tick_duration_seconds,
1056            source_enumerator_monitor_error_count,
1057            source_enumerator_metrics,
1058            actor_info,
1059            table_info,
1060            sink_info,
1061            relation_info,
1062            database_info,
1063            backfill_fragment_progress,
1064            streaming_table_change_log_retention_seconds,
1065            system_param_info,
1066            l0_compact_level_count,
1067            compact_task_size,
1068            compact_task_file_count,
1069            compact_task_batch_count,
1070            compact_task_trivial_move_sst_count,
1071            table_write_throughput,
1072            split_compaction_group_count,
1073            state_table_count,
1074            branched_sst_count,
1075            compaction_event_consumed_latency,
1076            compaction_event_loop_iteration_latency,
1077            auto_schema_change_failure_cnt,
1078            auto_schema_change_success_cnt,
1079            auto_schema_change_latency,
1080            merge_compaction_group_count,
1081            time_travel_version_replay_latency,
1082            compaction_group_count,
1083            compaction_group_size,
1084            compaction_group_file_count,
1085            compaction_group_throughput,
1086            refresh_job_duration,
1087            refresh_job_finish_cnt,
1088            refresh_cron_job_trigger_cnt,
1089            refresh_cron_job_miss_cnt,
1090            time_travel_vacuum_metadata_latency,
1091            time_travel_write_metadata_latency,
1092        }
1093    }
1094
1095    #[cfg(test)]
1096    pub fn for_test(registry: &Registry) -> Self {
1097        Self::new(registry)
1098    }
1099}
1100impl Default for MetaMetrics {
1101    fn default() -> Self {
1102        GLOBAL_META_METRICS.clone()
1103    }
1104}
1105
1106/// Refresh `system_param_info` metrics by reading current system parameters.
1107pub async fn refresh_system_param_info_metrics(
1108    system_params_controller: &SystemParamsControllerRef,
1109    meta_metrics: Arc<MetaMetrics>,
1110) {
1111    let params_info = system_params_controller.get_params().await.get_all();
1112
1113    meta_metrics.system_param_info.reset();
1114    for info in params_info {
1115        meta_metrics
1116            .system_param_info
1117            .with_label_values(&[info.name, &info.value])
1118            .set(1);
1119    }
1120}
1121
1122pub fn start_worker_info_monitor(
1123    metadata_manager: MetadataManager,
1124    election_client: ElectionClientRef,
1125    interval: Duration,
1126    meta_metrics: Arc<MetaMetrics>,
1127) -> (JoinHandle<()>, Sender<()>) {
1128    let (shutdown_tx, mut shutdown_rx) = tokio::sync::oneshot::channel();
1129    let join_handle = tokio::spawn(async move {
1130        let mut monitor_interval = tokio::time::interval(interval);
1131        monitor_interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
1132        loop {
1133            tokio::select! {
1134                // Wait for interval
1135                _ = monitor_interval.tick() => {},
1136                // Shutdown monitor
1137                _ = &mut shutdown_rx => {
1138                    tracing::info!("Worker number monitor is stopped");
1139                    return;
1140                }
1141            }
1142
1143            let node_map = match metadata_manager.count_worker_node().await {
1144                Ok(node_map) => node_map,
1145                Err(err) => {
1146                    tracing::warn!(error = %err.as_report(), "fail to count worker node");
1147                    continue;
1148                }
1149            };
1150
1151            // Reset metrics to clean the stale labels e.g. invalid lease ids
1152            meta_metrics.worker_num.reset();
1153            meta_metrics.meta_type.reset();
1154
1155            for (worker_type, worker_num) in node_map {
1156                meta_metrics
1157                    .worker_num
1158                    .with_label_values(&[(worker_type.as_str_name())])
1159                    .set(worker_num as i64);
1160            }
1161            if let Ok(meta_members) = election_client.get_members().await {
1162                meta_metrics
1163                    .worker_num
1164                    .with_label_values(&[WorkerType::Meta.as_str_name()])
1165                    .set(meta_members.len() as i64);
1166                meta_members.into_iter().for_each(|m| {
1167                    let role = if m.is_leader { "leader" } else { "follower" };
1168                    meta_metrics
1169                        .meta_type
1170                        .with_label_values(&[m.id.as_str(), role])
1171                        .set(1);
1172                });
1173            }
1174        }
1175    });
1176
1177    (join_handle, shutdown_tx)
1178}
1179
1180pub async fn refresh_fragment_info_metrics(
1181    catalog_controller: &CatalogControllerRef,
1182    cluster_controller: &ClusterControllerRef,
1183    hummock_manager: &HummockManagerRef,
1184    meta_metrics: Arc<MetaMetrics>,
1185) {
1186    let worker_nodes = match cluster_controller
1187        .list_workers(Some(WorkerType::ComputeNode.into()), None)
1188        .await
1189    {
1190        Ok(worker_nodes) => worker_nodes,
1191        Err(err) => {
1192            tracing::warn!(error=%err.as_report(), "fail to list worker node");
1193            return;
1194        }
1195    };
1196    let actor_locations = match catalog_controller.list_actor_locations() {
1197        Ok(actor_locations) => actor_locations,
1198        Err(err) => {
1199            tracing::warn!(error=%err.as_report(), "fail to get actor locations");
1200            return;
1201        }
1202    };
1203    let sink_actor_mapping = match catalog_controller.list_sink_actor_mapping().await {
1204        Ok(sink_actor_mapping) => sink_actor_mapping,
1205        Err(err) => {
1206            tracing::warn!(error=%err.as_report(), "fail to get sink actor mapping");
1207            return;
1208        }
1209    };
1210    let fragment_state_tables = match catalog_controller.list_fragment_state_tables().await {
1211        Ok(fragment_state_tables) => fragment_state_tables,
1212        Err(err) => {
1213            tracing::warn!(error=%err.as_report(), "fail to get fragment state tables");
1214            return;
1215        }
1216    };
1217    let table_name_and_type_mapping = match catalog_controller.get_table_name_type_mapping().await {
1218        Ok(mapping) => mapping,
1219        Err(err) => {
1220            tracing::warn!(error=%err.as_report(), "fail to get table name mapping");
1221            return;
1222        }
1223    };
1224
1225    let worker_addr_mapping: HashMap<WorkerId, String> = worker_nodes
1226        .into_iter()
1227        .map(|worker_node| {
1228            let addr = match worker_node.host {
1229                Some(host) => format!("{}:{}", host.host, host.port),
1230                None => "".to_owned(),
1231            };
1232            (worker_node.id, addr)
1233        })
1234        .collect();
1235    let table_compaction_group_id_mapping = hummock_manager
1236        .get_table_compaction_group_id_mapping()
1237        .await;
1238
1239    // Start fresh with a reset to clear all outdated labels. This is safe since we always
1240    // report full info on each interval.
1241    meta_metrics.actor_info.reset();
1242    meta_metrics.table_info.reset();
1243    meta_metrics.sink_info.reset();
1244    for actor_location in actor_locations {
1245        let actor_id_str = actor_location.actor_id.to_string();
1246        let fragment_id_str = actor_location.fragment_id.to_string();
1247        // Report a dummy gauge metrics with (fragment id, actor id, node
1248        // address) as its label
1249        if let Some(address) = worker_addr_mapping.get(&actor_location.worker_id) {
1250            meta_metrics
1251                .actor_info
1252                .with_label_values(&[&actor_id_str, &fragment_id_str, address])
1253                .set(1);
1254        }
1255    }
1256    for (sink_id, (sink_name, actor_ids)) in sink_actor_mapping {
1257        let sink_id_str = sink_id.to_string();
1258        for actor_id in actor_ids {
1259            let actor_id_str = actor_id.to_string();
1260            meta_metrics
1261                .sink_info
1262                .with_label_values(&[&actor_id_str, &sink_id_str, &sink_name])
1263                .set(1);
1264        }
1265    }
1266    for PartialFragmentStateTables {
1267        fragment_id,
1268        job_id,
1269        state_table_ids,
1270    } in fragment_state_tables
1271    {
1272        let fragment_id_str = fragment_id.to_string();
1273        let job_id_str = job_id.to_string();
1274        for table_id in state_table_ids.into_inner() {
1275            let table_id_str = table_id.to_string();
1276            let (table_name, table_type) = table_name_and_type_mapping
1277                .get(&table_id)
1278                .cloned()
1279                .unwrap_or_else(|| ("unknown".to_owned(), "unknown".to_owned()));
1280            let compaction_group_id = table_compaction_group_id_mapping
1281                .get(&table_id)
1282                .map(|cg_id| cg_id.to_string())
1283                .unwrap_or_else(|| "unknown".to_owned());
1284            meta_metrics
1285                .table_info
1286                .with_label_values(&[
1287                    &job_id_str,
1288                    &table_id_str,
1289                    &fragment_id_str,
1290                    &table_name,
1291                    &table_type,
1292                    &compaction_group_id,
1293                ])
1294                .set(1);
1295        }
1296    }
1297}
1298
1299pub async fn refresh_relation_info_metrics(
1300    catalog_controller: &CatalogControllerRef,
1301    meta_metrics: Arc<MetaMetrics>,
1302) {
1303    let table_objects = match catalog_controller.list_table_objects().await {
1304        Ok(table_objects) => table_objects,
1305        Err(err) => {
1306            tracing::warn!(error=%err.as_report(), "fail to get table objects");
1307            return;
1308        }
1309    };
1310
1311    let source_objects = match catalog_controller.list_source_objects().await {
1312        Ok(source_objects) => source_objects,
1313        Err(err) => {
1314            tracing::warn!(error=%err.as_report(), "fail to get source objects");
1315            return;
1316        }
1317    };
1318
1319    let sink_objects = match catalog_controller.list_sink_objects().await {
1320        Ok(sink_objects) => sink_objects,
1321        Err(err) => {
1322            tracing::warn!(error=%err.as_report(), "fail to get sink objects");
1323            return;
1324        }
1325    };
1326    let subscriptions = match catalog_controller.list_subscriptions().await {
1327        Ok(subscriptions) => subscriptions,
1328        Err(err) => {
1329            tracing::warn!(error=%err.as_report(), "fail to get subscription objects");
1330            return;
1331        }
1332    };
1333
1334    meta_metrics.relation_info.reset();
1335    meta_metrics
1336        .streaming_table_change_log_retention_seconds
1337        .reset();
1338
1339    for (id, db, schema, name, resource_group, table_type) in table_objects {
1340        let relation_type = match table_type {
1341            TableType::Table => "table",
1342            TableType::MaterializedView => "materialized_view",
1343            TableType::Index | TableType::VectorIndex => "index",
1344            TableType::Internal => "internal",
1345        };
1346        meta_metrics
1347            .relation_info
1348            .with_label_values(&[
1349                &id.to_string(),
1350                &db,
1351                &schema,
1352                &name,
1353                &resource_group,
1354                &relation_type.to_owned(),
1355            ])
1356            .set(1);
1357    }
1358
1359    for (id, db, schema, name, resource_group) in source_objects {
1360        meta_metrics
1361            .relation_info
1362            .with_label_values(&[
1363                &id.to_string(),
1364                &db,
1365                &schema,
1366                &name,
1367                &resource_group,
1368                &"source".to_owned(),
1369            ])
1370            .set(1);
1371    }
1372
1373    for (id, db, schema, name, resource_group) in sink_objects {
1374        meta_metrics
1375            .relation_info
1376            .with_label_values(&[
1377                &id.to_string(),
1378                &db,
1379                &schema,
1380                &name,
1381                &resource_group,
1382                &"sink".to_owned(),
1383            ])
1384            .set(1);
1385    }
1386
1387    let mut max_retention_by_table = HashMap::new();
1388    for subscription in subscriptions {
1389        max_retention_by_table
1390            .entry(subscription.dependent_table_id)
1391            .and_modify(|retention: &mut u64| {
1392                *retention = (*retention).max(subscription.retention_seconds);
1393            })
1394            .or_insert(subscription.retention_seconds);
1395    }
1396    for (table_id, retention_seconds) in max_retention_by_table {
1397        meta_metrics
1398            .streaming_table_change_log_retention_seconds
1399            .with_label_values(&[&table_id.to_string()])
1400            .set(retention_seconds as _);
1401    }
1402}
1403
1404pub async fn refresh_database_info_metrics(
1405    catalog_controller: &CatalogControllerRef,
1406    meta_metrics: Arc<MetaMetrics>,
1407) {
1408    let databases = match catalog_controller.list_databases().await {
1409        Ok(databases) => databases,
1410        Err(err) => {
1411            tracing::warn!(error=%err.as_report(), "fail to get databases");
1412            return;
1413        }
1414    };
1415
1416    meta_metrics.database_info.reset();
1417
1418    for db in databases {
1419        meta_metrics
1420            .database_info
1421            .with_label_values(&[&db.id.to_string(), &db.name])
1422            .set(1);
1423    }
1424}
1425
1426fn extract_backfill_fragment_info(
1427    distribution: &FragmentDistribution,
1428) -> Option<BackfillFragmentInfo> {
1429    let backfill_type =
1430        if distribution.fragment_type_mask & FragmentTypeFlag::SourceScan as u32 != 0 {
1431            "SOURCE"
1432        } else if distribution.fragment_type_mask
1433            & (FragmentTypeFlag::SnapshotBackfillStreamScan as u32
1434                | FragmentTypeFlag::CrossDbSnapshotBackfillStreamScan as u32)
1435            != 0
1436        {
1437            "SNAPSHOT_BACKFILL"
1438        } else if distribution.fragment_type_mask & FragmentTypeFlag::StreamScan as u32 != 0 {
1439            "ARRANGEMENT_OR_NO_SHUFFLE"
1440        } else {
1441            return None;
1442        };
1443
1444    let stream_node = distribution.node.as_ref()?;
1445    let mut info = None;
1446    match backfill_type {
1447        "SOURCE" => {
1448            visit_stream_node_source_backfill(stream_node, |node| {
1449                info = Some(BackfillFragmentInfo {
1450                    job_id: distribution.table_id.as_raw_id(),
1451                    fragment_id: distribution.fragment_id.as_raw_id(),
1452                    backfill_state_table_id: node
1453                        .state_table
1454                        .as_ref()
1455                        .map(|table| table.id.as_raw_id())
1456                        .unwrap_or_default(),
1457                    backfill_target_relation_id: node.upstream_source_id.as_raw_id(),
1458                    backfill_type,
1459                    backfill_epoch: 0,
1460                });
1461            });
1462        }
1463        "SNAPSHOT_BACKFILL" | "ARRANGEMENT_OR_NO_SHUFFLE" => {
1464            visit_stream_node_stream_scan(stream_node, |node| {
1465                info = Some(BackfillFragmentInfo {
1466                    job_id: distribution.table_id.as_raw_id(),
1467                    fragment_id: distribution.fragment_id.as_raw_id(),
1468                    backfill_state_table_id: node
1469                        .state_table
1470                        .as_ref()
1471                        .map(|table| table.id.as_raw_id())
1472                        .unwrap_or_default(),
1473                    backfill_target_relation_id: node.table_id.as_raw_id(),
1474                    backfill_type,
1475                    backfill_epoch: node.snapshot_backfill_epoch.unwrap_or_default(),
1476                });
1477            });
1478        }
1479        _ => {}
1480    }
1481
1482    info
1483}
1484
1485pub async fn refresh_backfill_progress_metrics(
1486    catalog_controller: &CatalogControllerRef,
1487    hummock_manager: &HummockManagerRef,
1488    barrier_manager: &BarrierManagerRef,
1489    meta_metrics: Arc<MetaMetrics>,
1490) {
1491    let fragment_descs = match catalog_controller.list_fragment_descs_with_node(true).await {
1492        Ok(fragment_descs) => fragment_descs,
1493        Err(err) => {
1494            tracing::warn!(error=%err.as_report(), "fail to list creating fragment descs");
1495            return;
1496        }
1497    };
1498
1499    let backfill_infos: HashMap<(u32, u32), BackfillFragmentInfo> = fragment_descs
1500        .iter()
1501        .filter_map(|(distribution, _)| extract_backfill_fragment_info(distribution))
1502        .map(|info| ((info.job_id, info.fragment_id), info))
1503        .collect();
1504
1505    let fragment_progresses = match barrier_manager.get_fragment_backfill_progress().await {
1506        Ok(progress) => progress,
1507        Err(err) => {
1508            tracing::warn!(error=%err.as_report(), "fail to get fragment backfill progress");
1509            return;
1510        }
1511    };
1512
1513    let progress_by_fragment: HashMap<(u32, u32), _> = fragment_progresses
1514        .into_iter()
1515        .map(|progress| {
1516            (
1517                (
1518                    progress.job_id.as_raw_id(),
1519                    progress.fragment_id.as_raw_id(),
1520                ),
1521                progress,
1522            )
1523        })
1524        .collect();
1525
1526    let version_stats = hummock_manager.get_version_stats().await;
1527
1528    let relation_ids: HashSet<_> = backfill_infos
1529        .values()
1530        .map(|info| ObjectId::new(info.backfill_target_relation_id))
1531        .collect();
1532    let relation_objects = match catalog_controller
1533        .list_relation_objects_by_ids(&relation_ids)
1534        .await
1535    {
1536        Ok(relation_objects) => relation_objects,
1537        Err(err) => {
1538            tracing::warn!(error=%err.as_report(), "fail to get relation objects");
1539            return;
1540        }
1541    };
1542
1543    let mut relation_info = HashMap::new();
1544    for (id, db, schema, name, rel_type) in relation_objects {
1545        relation_info.insert(id.as_raw_id(), (db, schema, name, rel_type));
1546    }
1547
1548    meta_metrics.backfill_fragment_progress.reset();
1549
1550    for info in backfill_infos.values() {
1551        let progress = progress_by_fragment.get(&(info.job_id, info.fragment_id));
1552        let (db, schema, name, rel_type) = relation_info
1553            .get(&info.backfill_target_relation_id)
1554            .cloned()
1555            .unwrap_or_else(|| {
1556                (
1557                    "unknown".to_owned(),
1558                    "unknown".to_owned(),
1559                    "unknown".to_owned(),
1560                    "unknown".to_owned(),
1561                )
1562            });
1563
1564        let job_id_str = info.job_id.to_string();
1565        let fragment_id_str = info.fragment_id.to_string();
1566        let backfill_state_table_id_str = info.backfill_state_table_id.to_string();
1567        let backfill_target_relation_id_str = info.backfill_target_relation_id.to_string();
1568        let backfill_target_relation_name_str = format!("{db}.{schema}.{name}");
1569        let backfill_target_relation_type_str = rel_type;
1570        let backfill_type_str = info.backfill_type.to_owned();
1571        let backfill_epoch_str = info.backfill_epoch.to_string();
1572        let total_key_count = version_stats
1573            .table_stats
1574            .get(&TableId::new(info.backfill_target_relation_id))
1575            .map(|stats| stats.total_key_count as u64);
1576
1577        let progress_label = match (info.backfill_type, progress) {
1578            ("SOURCE", Some(progress)) => format!("{} consumed rows", progress.consumed_rows),
1579            ("SOURCE", None) => "0 consumed rows".to_owned(),
1580            (_, Some(progress)) if progress.done => {
1581                let total = total_key_count.unwrap_or(0);
1582                format!("100.0000% ({}/{})", total, total)
1583            }
1584            (_, Some(progress)) => {
1585                let total = total_key_count.unwrap_or(0);
1586                if total == 0 {
1587                    "100.0000% (0/0)".to_owned()
1588                } else {
1589                    let raw = (progress.consumed_rows as f64) / (total as f64) * 100.0;
1590                    format!(
1591                        "{:.4}% ({}/{})",
1592                        raw.min(100.0),
1593                        progress.consumed_rows,
1594                        total
1595                    )
1596                }
1597            }
1598            (_, None) => "0.0000% (0/0)".to_owned(),
1599        };
1600        let upstream_type_str = progress
1601            .map(|progress| progress.upstream_type.to_string())
1602            .unwrap_or_else(|| "Unknown".to_owned());
1603
1604        meta_metrics
1605            .backfill_fragment_progress
1606            .with_label_values(&[
1607                &job_id_str,
1608                &fragment_id_str,
1609                &backfill_state_table_id_str,
1610                &backfill_target_relation_id_str,
1611                &backfill_target_relation_name_str,
1612                &backfill_target_relation_type_str,
1613                &backfill_type_str,
1614                &backfill_epoch_str,
1615                &upstream_type_str,
1616                &progress_label,
1617            ])
1618            .set(1);
1619    }
1620}
1621
1622pub fn start_info_monitor(
1623    metadata_manager: MetadataManager,
1624    hummock_manager: HummockManagerRef,
1625    barrier_manager: BarrierManagerRef,
1626    system_params_controller: SystemParamsControllerRef,
1627    meta_metrics: Arc<MetaMetrics>,
1628) -> (JoinHandle<()>, Sender<()>) {
1629    const COLLECT_INTERVAL_SECONDS: u64 = 60;
1630
1631    let (shutdown_tx, mut shutdown_rx) = tokio::sync::oneshot::channel();
1632    let join_handle = tokio::spawn(async move {
1633        let mut monitor_interval =
1634            tokio::time::interval(Duration::from_secs(COLLECT_INTERVAL_SECONDS));
1635        monitor_interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
1636        loop {
1637            tokio::select! {
1638                // Wait for interval
1639                _ = monitor_interval.tick() => {},
1640                // Shutdown monitor
1641                _ = &mut shutdown_rx => {
1642                    tracing::info!("Meta info monitor is stopped");
1643                    return;
1644                }
1645            }
1646
1647            // Fragment and relation info
1648            refresh_fragment_info_metrics(
1649                &metadata_manager.catalog_controller,
1650                &metadata_manager.cluster_controller,
1651                &hummock_manager,
1652                meta_metrics.clone(),
1653            )
1654            .await;
1655
1656            refresh_relation_info_metrics(
1657                &metadata_manager.catalog_controller,
1658                meta_metrics.clone(),
1659            )
1660            .await;
1661
1662            refresh_database_info_metrics(
1663                &metadata_manager.catalog_controller,
1664                meta_metrics.clone(),
1665            )
1666            .await;
1667
1668            refresh_backfill_progress_metrics(
1669                &metadata_manager.catalog_controller,
1670                &hummock_manager,
1671                &barrier_manager,
1672                meta_metrics.clone(),
1673            )
1674            .await;
1675
1676            // System parameter info
1677            refresh_system_param_info_metrics(&system_params_controller, meta_metrics.clone())
1678                .await;
1679        }
1680    });
1681
1682    (join_handle, shutdown_tx)
1683}