1use async_stream::stream;
13use mz_persist_types::stats::PartStatsMetrics;
14use std::collections::BTreeMap;
15use std::sync::atomic::{AtomicBool, Ordering};
16use std::sync::{Arc, Mutex, Weak};
17use std::time::{Duration, Instant};
18use tokio::sync::{OnceCell, OwnedSemaphorePermit, Semaphore};
19
20use async_trait::async_trait;
21use bytes::Bytes;
22use futures_util::StreamExt;
23use mz_ore::bytes::SegmentedBytes;
24use mz_ore::cast::{CastFrom, CastLossy};
25use mz_ore::instrument;
26use mz_ore::metric;
27use mz_ore::metrics::{
28 ComputedGauge, ComputedUIntGauge, Counter, DeleteOnDropCounter, DeleteOnDropGauge, IntCounter,
29 MakeCollector, MetricsRegistry, UIntGauge, UIntGaugeVec, raw,
30};
31use mz_ore::stats::histogram_seconds_buckets;
32use mz_persist::location::{
33 Blob, BlobMetadata, CaSResult, Consensus, ExternalError, ResultStream, SeqNo, VersionedData,
34};
35use mz_persist::metrics::{BlobHedgeMetrics, ColumnarMetrics, S3BlobMetrics};
36use mz_persist::retry::RetryStream;
37use mz_persist_types::Codec64;
38use mz_postgres_client::metrics::PostgresClientMetrics;
39use prometheus::core::{AtomicI64, AtomicU64, Collector, Desc, GenericGauge};
40use prometheus::proto::MetricFamily;
41use prometheus::{CounterVec, Gauge, GaugeVec, Histogram, HistogramVec, IntCounterVec};
42use timely::progress::Antichain;
43use tokio_metrics::TaskMonitor;
44use tracing::{Instrument, debug, info, info_span};
45
46use crate::fetch::{FETCH_SEMAPHORE_COST_ADJUSTMENT, FETCH_SEMAPHORE_PERMIT_ADJUSTMENT};
47use crate::internal::paths::BlobKey;
48use crate::{PersistConfig, ShardId};
49
50pub struct Metrics {
55 _vecs: MetricsVecs,
56 _uptime: ComputedGauge,
57
58 pub blob: BlobMetrics,
60 pub consensus: ConsensusMetrics,
62 pub cmds: CmdsMetrics,
64 pub retries: RetriesMetrics,
66 pub user: BatchWriteMetrics,
69 pub read: BatchPartReadMetrics,
71 pub compaction: CompactionMetrics,
73 pub gc: GcMetrics,
75 pub lease: LeaseMetrics,
77 pub codecs: CodecsMetrics,
79 pub state: StateMetrics,
81 pub shards: ShardsMetrics,
83 pub audit: UsageAuditMetrics,
85 pub locks: LocksMetrics,
87 pub watch: WatchMetrics,
89 pub pubsub_client: PubSubClientMetrics,
91 pub pushdown: PushdownMetrics,
93 pub consolidation: ConsolidationMetrics,
95 pub blob_cache_mem: BlobMemCache,
97 pub tasks: TasksMetrics,
99 pub columnar: ColumnarMetrics,
101 pub schema: SchemaMetrics,
103 pub inline: InlineMetrics,
105 pub(crate) semaphore: SemaphoreMetrics,
107
108 pub sink: SinkMetrics,
110 pub backpressure: BackpressureMetrics,
112
113 pub s3_blob: S3BlobMetrics,
115 pub blob_hedge: BlobHedgeMetrics,
117 pub postgres_consensus: PostgresClientMetrics,
119
120 #[allow(dead_code)]
121 pub(crate) registry: MetricsRegistry,
122}
123
124impl std::fmt::Debug for Metrics {
125 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
126 f.debug_struct("Metrics").finish_non_exhaustive()
127 }
128}
129
130impl Metrics {
131 pub fn new(cfg: &PersistConfig, registry: &MetricsRegistry) -> Self {
133 let vecs = MetricsVecs::new(registry);
134 let start = Instant::now();
135 let uptime = registry.register_computed_gauge(
136 metric!(
137 name: "mz_persist_metadata_seconds",
138 help: "server uptime, labels are build metadata",
139 const_labels: {
140 "version" => cfg.build_version,
141 "build_type" => if cfg!(release) { "release" } else { "debug" }
142 },
143 ),
144 move || start.elapsed().as_secs_f64(),
145 );
146 let s3_blob = S3BlobMetrics::new(registry);
147 let columnar = ColumnarMetrics::new(registry);
148 Metrics {
149 blob: vecs.blob_metrics(),
150 consensus: vecs.consensus_metrics(),
151 cmds: vecs.cmds_metrics(registry),
152 retries: vecs.retries_metrics(),
153 codecs: vecs.codecs_metrics(),
154 user: BatchWriteMetrics::new(registry, "user"),
155 read: vecs.batch_part_read_metrics(),
156 compaction: CompactionMetrics::new(registry),
157 gc: GcMetrics::new(registry),
158 lease: LeaseMetrics::new(registry),
159 state: StateMetrics::new(registry),
160 shards: ShardsMetrics::new(registry),
161 audit: UsageAuditMetrics::new(registry),
162 locks: vecs.locks_metrics(),
163 watch: WatchMetrics::new(registry),
164 pubsub_client: PubSubClientMetrics::new(registry),
165 pushdown: PushdownMetrics::new(registry),
166 consolidation: ConsolidationMetrics::new(registry),
167 blob_cache_mem: BlobMemCache::new(registry),
168 tasks: TasksMetrics::new(registry),
169 columnar,
170 schema: SchemaMetrics::new(registry),
171 inline: InlineMetrics::new(registry),
172 semaphore: SemaphoreMetrics::new(cfg.clone(), registry.clone()),
173 sink: SinkMetrics::new(registry),
174 backpressure: BackpressureMetrics::new(registry),
175 s3_blob,
176 blob_hedge: BlobHedgeMetrics::new(registry),
177 postgres_consensus: PostgresClientMetrics::new(registry, "mz_persist"),
178 _vecs: vecs,
179 _uptime: uptime,
180 registry: registry.clone(),
181 }
182 }
183
184 pub fn write_amplification(&self) -> f64 {
189 let total_written = self.blob.set.bytes.get();
192 let user_written = self.user.goodbytes.get();
193 #[allow(clippy::as_conversions)]
194 {
195 total_written as f64 / user_written as f64
196 }
197 }
198}
199
200#[derive(Debug)]
201struct MetricsVecs {
202 cmd_started: IntCounterVec,
203 cmd_cas_mismatch: IntCounterVec,
204 cmd_succeeded: IntCounterVec,
205 cmd_failed: IntCounterVec,
206 cmd_seconds: CounterVec,
207
208 external_op_started: IntCounterVec,
209 external_op_succeeded: IntCounterVec,
210 external_op_failed: IntCounterVec,
211 external_op_bytes: IntCounterVec,
212 external_op_seconds: CounterVec,
213 external_consensus_truncated_count: IntCounter,
214 external_blob_delete_noop_count: IntCounter,
215 external_blob_sizes: Histogram,
216 external_rtt_latency: GaugeVec,
217 external_op_latency: HistogramVec,
218
219 retry_started: IntCounterVec,
220 retry_finished: IntCounterVec,
221 retry_retries: IntCounterVec,
222 retry_sleep_seconds: CounterVec,
223
224 encode_count: IntCounterVec,
225 encode_seconds: CounterVec,
226 decode_count: IntCounterVec,
227 decode_seconds: CounterVec,
228
229 read_part_bytes: IntCounterVec,
230 read_part_goodbytes: IntCounterVec,
231 read_part_count: IntCounterVec,
232 read_part_seconds: CounterVec,
233 read_ts_rewrite: IntCounterVec,
234
235 lock_acquire_count: IntCounterVec,
236 lock_blocking_acquire_count: IntCounterVec,
237 lock_blocking_seconds: CounterVec,
238
239 alerts_metrics: Arc<AlertsMetrics>,
241}
242
243impl MetricsVecs {
244 fn new(registry: &MetricsRegistry) -> Self {
245 MetricsVecs {
246 cmd_started: registry.register(metric!(
247 name: "mz_persist_cmd_started_count",
248 help: "count of commands started",
249 var_labels: ["cmd"],
250 )),
251 cmd_cas_mismatch: registry.register(metric!(
252 name: "mz_persist_cmd_cas_mismatch_count",
253 help: "count of command retries from CaS mismatch",
254 var_labels: ["cmd"],
255 )),
256 cmd_succeeded: registry.register(metric!(
257 name: "mz_persist_cmd_succeeded_count",
258 help: "count of commands succeeded",
259 var_labels: ["cmd"],
260 )),
261 cmd_failed: registry.register(metric!(
262 name: "mz_persist_cmd_failed_count",
263 help: "count of commands failed",
264 var_labels: ["cmd"],
265 )),
266 cmd_seconds: registry.register(metric!(
267 name: "mz_persist_cmd_seconds",
268 help: "time spent applying commands",
269 var_labels: ["cmd"],
270 )),
271
272 external_op_started: registry.register(metric!(
273 name: "mz_persist_external_started_count",
274 help: "count of external service calls started",
275 var_labels: ["op"],
276 )),
277 external_op_succeeded: registry.register(metric!(
278 name: "mz_persist_external_succeeded_count",
279 help: "count of external service calls succeeded",
280 var_labels: ["op"],
281 )),
282 external_op_failed: registry.register(metric!(
283 name: "mz_persist_external_failed_count",
284 help: "count of external service calls failed",
285 var_labels: ["op"],
286 )),
287 external_op_bytes: registry.register(metric!(
288 name: "mz_persist_external_bytes_count",
289 help: "total size represented by external service calls",
290 var_labels: ["op"],
291 )),
292 external_op_seconds: registry.register(metric!(
293 name: "mz_persist_external_seconds",
294 help: "time spent in external service calls",
295 var_labels: ["op"],
296 )),
297 external_consensus_truncated_count: registry.register(metric!(
298 name: "mz_persist_external_consensus_truncated_count",
299 help: "count of versions deleted by consensus truncate calls",
300 )),
301 external_blob_delete_noop_count: registry.register(metric!(
302 name: "mz_persist_external_blob_delete_noop_count",
303 help: "count of blob delete calls that deleted a non-existent key",
304 )),
305 external_blob_sizes: registry.register(metric!(
306 name: "mz_persist_external_blob_sizes",
307 help: "histogram of blob sizes at put time",
308 buckets: mz_ore::stats::HISTOGRAM_BYTE_BUCKETS.to_vec(),
309 )),
310 external_rtt_latency: registry.register(metric!(
311 name: "mz_persist_external_rtt_latency",
312 help: "roundtrip-time to external service as seen by this process",
313 var_labels: ["external"],
314 )),
315 external_op_latency: registry.register(metric!(
316 name: "mz_persist_external_op_latency",
317 help: "rountrip latency observed by individual performance-critical operations",
318 var_labels: ["op"],
319 buckets: histogram_seconds_buckets(0.000_500, 32.0),
322 )),
323
324 retry_started: registry.register(metric!(
325 name: "mz_persist_retry_started_count",
326 help: "count of retry loops started",
327 var_labels: ["op"],
328 )),
329 retry_finished: registry.register(metric!(
330 name: "mz_persist_retry_finished_count",
331 help: "count of retry loops finished",
332 var_labels: ["op"],
333 )),
334 retry_retries: registry.register(metric!(
335 name: "mz_persist_retry_retries_count",
336 help: "count of total attempts by retry loops",
337 var_labels: ["op"],
338 )),
339 retry_sleep_seconds: registry.register(metric!(
340 name: "mz_persist_retry_sleep_seconds",
341 help: "time spent in retry loop backoff",
342 var_labels: ["op"],
343 )),
344
345 encode_count: registry.register(metric!(
346 name: "mz_persist_encode_count",
347 help: "count of op encodes",
348 var_labels: ["op"],
349 )),
350 encode_seconds: registry.register(metric!(
351 name: "mz_persist_encode_seconds",
352 help: "time spent in op encodes",
353 var_labels: ["op"],
354 )),
355 decode_count: registry.register(metric!(
356 name: "mz_persist_decode_count",
357 help: "count of op decodes",
358 var_labels: ["op"],
359 )),
360 decode_seconds: registry.register(metric!(
361 name: "mz_persist_decode_seconds",
362 help: "time spent in op decodes",
363 var_labels: ["op"],
364 )),
365
366 read_part_bytes: registry.register(metric!(
367 name: "mz_persist_read_batch_part_bytes",
368 help: "total encoded size of batch parts read",
369 var_labels: ["op"],
370 )),
371 read_part_goodbytes: registry.register(metric!(
372 name: "mz_persist_read_batch_part_goodbytes",
373 help: "total logical size of batch parts read",
374 var_labels: ["op"],
375 )),
376 read_part_count: registry.register(metric!(
377 name: "mz_persist_read_batch_part_count",
378 help: "count of batch parts read",
379 var_labels: ["op"],
380 )),
381 read_part_seconds: registry.register(metric!(
382 name: "mz_persist_read_batch_part_seconds",
383 help: "time spent reading batch parts",
384 var_labels: ["op"],
385 )),
386 read_ts_rewrite: registry.register(metric!(
387 name: "mz_persist_read_ts_rewite",
388 help: "count of updates read with rewritten ts",
389 var_labels: ["op"],
390 )),
391
392 lock_acquire_count: registry.register(metric!(
393 name: "mz_persist_lock_acquire_count",
394 help: "count of locks acquired",
395 var_labels: ["op"],
396 )),
397 lock_blocking_acquire_count: registry.register(metric!(
398 name: "mz_persist_lock_blocking_acquire_count",
399 help: "count of locks acquired that required blocking",
400 var_labels: ["op"],
401 )),
402 lock_blocking_seconds: registry.register(metric!(
403 name: "mz_persist_lock_blocking_seconds",
404 help: "time spent blocked for a lock",
405 var_labels: ["op"],
406 )),
407
408 alerts_metrics: Arc::new(AlertsMetrics::new(registry)),
409 }
410 }
411
412 fn cmds_metrics(&self, registry: &MetricsRegistry) -> CmdsMetrics {
413 CmdsMetrics {
414 init_state: self.cmd_metrics("init_state"),
415 add_rollup: self.cmd_metrics("add_rollup"),
416 remove_rollups: self.cmd_metrics("remove_rollups"),
417 upgrade_version: self.cmd_metrics("upgrade_version"),
418 register: self.cmd_metrics("register"),
419 compare_and_append: self.cmd_metrics("compare_and_append"),
420 compare_and_append_noop: registry.register(metric!(
421 name: "mz_persist_cmd_compare_and_append_noop",
422 help: "count of compare_and_append retries that were discoverd to have already committed",
423 )),
424 compare_and_downgrade_since: self.cmd_metrics("compare_and_downgrade_since"),
425 downgrade_since: self.cmd_metrics("downgrade_since"),
426 expire_reader: self.cmd_metrics("expire_reader"),
427 expire_writer: self.cmd_metrics("expire_writer"),
428 merge_res: self.cmd_metrics("merge_res"),
429 become_tombstone: self.cmd_metrics("become_tombstone"),
430 compare_and_evolve_schema: self.cmd_metrics("compare_and_evolve_schema"),
431 spine_exert: self.cmd_metrics("spine_exert"),
432 fetch_upper_count: registry.register(metric!(
433 name: "mz_persist_cmd_fetch_upper_count",
434 help: "count of fetch_upper calls",
435 ))
436 }
437 }
438
439 fn cmd_metrics(&self, cmd: &str) -> CmdMetrics {
440 CmdMetrics {
441 name: cmd.to_owned(),
442 started: self.cmd_started.with_label_values(&[cmd]),
443 succeeded: self.cmd_succeeded.with_label_values(&[cmd]),
444 cas_mismatch: self.cmd_cas_mismatch.with_label_values(&[cmd]),
445 failed: self.cmd_failed.with_label_values(&[cmd]),
446 seconds: self.cmd_seconds.with_label_values(&[cmd]),
447 }
448 }
449
450 fn retries_metrics(&self) -> RetriesMetrics {
451 RetriesMetrics {
452 determinate: RetryDeterminate {
453 apply_unbatched_cmd_cas: self.retry_metrics("apply_unbatched_cmd::cas"),
454 },
455 external: RetryExternal {
456 batch_delete: Arc::new(self.retry_metrics("batch::delete")),
457 batch_set: self.retry_metrics("batch::set"),
458 blob_open: self.retry_metrics("blob::open"),
459 compaction_noop_delete: Arc::new(self.retry_metrics("compaction_noop::delete")),
460 consensus_open: self.retry_metrics("consensus::open"),
461 fetch_batch_get: self.retry_metrics("fetch_batch::get"),
462 fetch_state_scan: self.retry_metrics("fetch_state::scan"),
463 gc_truncate: self.retry_metrics("gc::truncate"),
464 maybe_init_cas: self.retry_metrics("maybe_init::cas"),
465 rollup_delete: self.retry_metrics("rollup::delete"),
466 rollup_get: self.retry_metrics("rollup::get"),
467 rollup_set: self.retry_metrics("rollup::set"),
468 hollow_run_get: self.retry_metrics("hollow_run::get"),
469 hollow_run_set: self.retry_metrics("hollow_run::set"),
470 storage_usage_shard_size: self.retry_metrics("storage_usage::shard_size"),
471 },
472 compare_and_append_idempotent: self.retry_metrics("compare_and_append_idempotent"),
473 fetch_latest_state: self.retry_metrics("fetch_latest_state"),
474 fetch_live_states: self.retry_metrics("fetch_live_states"),
475 idempotent_cmd: self.retry_metrics("idempotent_cmd"),
476 next_listen_batch: self.retry_metrics("next_listen_batch"),
477 snapshot: self.retry_metrics("snapshot"),
478 }
479 }
480
481 fn retry_metrics(&self, name: &str) -> RetryMetrics {
482 RetryMetrics {
483 name: name.to_owned(),
484 started: self.retry_started.with_label_values(&[name]),
485 finished: self.retry_finished.with_label_values(&[name]),
486 retries: self.retry_retries.with_label_values(&[name]),
487 sleep_seconds: self.retry_sleep_seconds.with_label_values(&[name]),
488 }
489 }
490
491 fn codecs_metrics(&self) -> CodecsMetrics {
492 CodecsMetrics {
493 state: self.codec_metrics("state"),
494 state_diff: self.codec_metrics("state_diff"),
495 batch: self.codec_metrics("batch"),
496 key: self.codec_metrics("key"),
497 val: self.codec_metrics("val"),
498 }
499 }
500
501 fn codec_metrics(&self, op: &str) -> CodecMetrics {
502 CodecMetrics {
503 encode_count: self.encode_count.with_label_values(&[op]),
504 encode_seconds: self.encode_seconds.with_label_values(&[op]),
505 decode_count: self.decode_count.with_label_values(&[op]),
506 decode_seconds: self.decode_seconds.with_label_values(&[op]),
507 }
508 }
509
510 fn blob_metrics(&self) -> BlobMetrics {
511 BlobMetrics {
512 set: self.external_op_metrics("blob_set", true),
513 get: self.external_op_metrics("blob_get", true),
514 list_keys: self.external_op_metrics("blob_list_keys", false),
515 delete: self.external_op_metrics("blob_delete", false),
516 restore: self.external_op_metrics("restore", false),
517 delete_noop: self.external_blob_delete_noop_count.clone(),
518 blob_sizes: self.external_blob_sizes.clone(),
519 rtt_latency: self.external_rtt_latency.with_label_values(&["blob"]),
520 }
521 }
522
523 fn consensus_metrics(&self) -> ConsensusMetrics {
524 ConsensusMetrics {
525 list_keys: self.external_op_metrics("consensus_list_keys", false),
526 head: self.external_op_metrics("consensus_head", false),
527 compare_and_set: self.external_op_metrics("consensus_cas", true),
528 scan: self.external_op_metrics("consensus_scan", false),
529 truncate: self.external_op_metrics("consensus_truncate", false),
530 truncated_count: self.external_consensus_truncated_count.clone(),
531 rtt_latency: self.external_rtt_latency.with_label_values(&["consensus"]),
532 }
533 }
534
535 fn external_op_metrics(&self, op: &str, latency_histogram: bool) -> ExternalOpMetrics {
536 ExternalOpMetrics {
537 started: self.external_op_started.with_label_values(&[op]),
538 succeeded: self.external_op_succeeded.with_label_values(&[op]),
539 failed: self.external_op_failed.with_label_values(&[op]),
540 bytes: self.external_op_bytes.with_label_values(&[op]),
541 seconds: self.external_op_seconds.with_label_values(&[op]),
542 seconds_histogram: if latency_histogram {
543 Some(self.external_op_latency.with_label_values(&[op]))
544 } else {
545 None
546 },
547 alerts_metrics: Arc::clone(&self.alerts_metrics),
548 }
549 }
550
551 fn batch_part_read_metrics(&self) -> BatchPartReadMetrics {
552 BatchPartReadMetrics {
553 listen: self.read_metrics("listen"),
554 snapshot: self.read_metrics("snapshot"),
555 batch_fetcher: self.read_metrics("batch_fetcher"),
556 compaction: self.read_metrics("compaction"),
557 unindexed: self.read_metrics("unindexed"),
558 }
559 }
560
561 fn read_metrics(&self, op: &str) -> ReadMetrics {
562 ReadMetrics {
563 part_bytes: self.read_part_bytes.with_label_values(&[op]),
564 part_goodbytes: self.read_part_goodbytes.with_label_values(&[op]),
565 part_count: self.read_part_count.with_label_values(&[op]),
566 seconds: self.read_part_seconds.with_label_values(&[op]),
567 ts_rewrite: self.read_ts_rewrite.with_label_values(&[op]),
568 }
569 }
570
571 fn locks_metrics(&self) -> LocksMetrics {
572 LocksMetrics {
573 applier_read_cacheable: self.lock_metrics("applier_read_cacheable"),
574 applier_read_noncacheable: self.lock_metrics("applier_read_noncacheable"),
575 applier_write: self.lock_metrics("applier_write"),
576 watch: self.lock_metrics("watch"),
577 }
578 }
579
580 fn lock_metrics(&self, op: &str) -> LockMetrics {
581 LockMetrics {
582 acquire_count: self.lock_acquire_count.with_label_values(&[op]),
583 blocking_acquire_count: self.lock_blocking_acquire_count.with_label_values(&[op]),
584 blocking_seconds: self.lock_blocking_seconds.with_label_values(&[op]),
585 }
586 }
587}
588
589#[derive(Debug)]
590pub struct CmdMetrics {
591 pub(crate) name: String,
592 pub(crate) started: IntCounter,
593 pub(crate) cas_mismatch: IntCounter,
594 pub(crate) succeeded: IntCounter,
595 pub(crate) failed: IntCounter,
596 pub(crate) seconds: Counter,
597}
598
599impl CmdMetrics {
600 pub async fn run_cmd<R, E, F, CmdFn>(
601 &self,
602 shard_metrics: &ShardMetrics,
603 cmd_fn: CmdFn,
604 ) -> Result<R, E>
605 where
606 F: std::future::Future<Output = Result<R, E>>,
607 CmdFn: FnOnce() -> F,
608 {
609 self.started.inc();
610 let start = Instant::now();
611 let res = cmd_fn().await;
612 self.seconds.inc_by(start.elapsed().as_secs_f64());
613 match res.as_ref() {
614 Ok(_) => {
615 self.succeeded.inc();
616 shard_metrics.cmd_succeeded.inc();
617 }
618 Err(_) => self.failed.inc(),
619 };
620 res
621 }
622}
623
624#[derive(Debug)]
625pub struct CmdsMetrics {
626 pub(crate) init_state: CmdMetrics,
627 pub(crate) add_rollup: CmdMetrics,
628 pub(crate) remove_rollups: CmdMetrics,
629 pub(crate) upgrade_version: CmdMetrics,
630 pub(crate) register: CmdMetrics,
631 pub(crate) compare_and_append: CmdMetrics,
632 pub(crate) compare_and_append_noop: IntCounter,
633 pub(crate) compare_and_downgrade_since: CmdMetrics,
634 pub(crate) downgrade_since: CmdMetrics,
635 pub(crate) expire_reader: CmdMetrics,
636 pub(crate) expire_writer: CmdMetrics,
637 pub(crate) merge_res: CmdMetrics,
638 pub(crate) become_tombstone: CmdMetrics,
639 pub(crate) compare_and_evolve_schema: CmdMetrics,
640 pub(crate) spine_exert: CmdMetrics,
641 pub(crate) fetch_upper_count: IntCounter,
642}
643
644#[derive(Debug)]
645pub struct RetryMetrics {
646 pub(crate) name: String,
647 pub(crate) started: IntCounter,
648 pub(crate) finished: IntCounter,
649 pub(crate) retries: IntCounter,
650 pub(crate) sleep_seconds: Counter,
651}
652
653impl RetryMetrics {
654 pub(crate) fn stream(&self, retry: RetryStream) -> MetricsRetryStream {
655 MetricsRetryStream::new(retry, self)
656 }
657}
658
659#[derive(Debug)]
660pub struct RetryDeterminate {
661 pub(crate) apply_unbatched_cmd_cas: RetryMetrics,
662}
663
664#[derive(Debug)]
665pub struct RetryExternal {
666 pub(crate) batch_delete: Arc<RetryMetrics>,
667 pub(crate) batch_set: RetryMetrics,
668 pub(crate) blob_open: RetryMetrics,
669 pub(crate) compaction_noop_delete: Arc<RetryMetrics>,
670 pub(crate) consensus_open: RetryMetrics,
671 pub(crate) fetch_batch_get: RetryMetrics,
672 pub(crate) fetch_state_scan: RetryMetrics,
673 pub(crate) gc_truncate: RetryMetrics,
674 pub(crate) maybe_init_cas: RetryMetrics,
675 pub(crate) rollup_delete: RetryMetrics,
676 pub(crate) rollup_get: RetryMetrics,
677 pub(crate) rollup_set: RetryMetrics,
678 pub(crate) hollow_run_get: RetryMetrics,
679 pub(crate) hollow_run_set: RetryMetrics,
680 pub(crate) storage_usage_shard_size: RetryMetrics,
681}
682
683#[derive(Debug)]
684pub struct RetriesMetrics {
685 pub(crate) determinate: RetryDeterminate,
686 pub(crate) external: RetryExternal,
687
688 pub(crate) compare_and_append_idempotent: RetryMetrics,
689 pub(crate) fetch_latest_state: RetryMetrics,
690 pub(crate) fetch_live_states: RetryMetrics,
691 pub(crate) idempotent_cmd: RetryMetrics,
692 pub(crate) next_listen_batch: RetryMetrics,
693 pub(crate) snapshot: RetryMetrics,
694}
695
696#[derive(Debug)]
697pub struct BatchPartReadMetrics {
698 pub(crate) listen: ReadMetrics,
699 pub(crate) snapshot: ReadMetrics,
700 pub(crate) batch_fetcher: ReadMetrics,
701 pub(crate) compaction: ReadMetrics,
702 pub(crate) unindexed: ReadMetrics,
703}
704
705#[derive(Debug, Clone)]
706pub struct ReadMetrics {
707 pub(crate) part_bytes: IntCounter,
708 pub(crate) part_goodbytes: IntCounter,
709 pub(crate) part_count: IntCounter,
710 pub(crate) seconds: Counter,
711 pub(crate) ts_rewrite: IntCounter,
712}
713
714#[derive(Debug, Clone)]
717pub struct BatchWriteMetrics {
718 pub(crate) bytes: IntCounter,
719 pub(crate) goodbytes: IntCounter,
720 pub(crate) seconds: Counter,
721 pub(crate) write_stalls: IntCounter,
722 pub(crate) key_lower_too_big: IntCounter,
723
724 pub(crate) unordered: IntCounter,
725 pub(crate) codec_order: IntCounter,
726 pub(crate) structured_order: IntCounter,
727 _order_counts: IntCounterVec,
728
729 pub(crate) step_stats: Counter,
730 pub(crate) step_part_writing: Counter,
731 pub(crate) step_inline: Counter,
732}
733
734impl BatchWriteMetrics {
735 fn new(registry: &MetricsRegistry, name: &str) -> Self {
736 let order_counts: IntCounterVec = registry.register(metric!(
737 name: format!("mz_persist_{}_write_batch_order", name),
738 help: "count of batches by the data ordering",
739 var_labels: ["order"],
740 ));
741 let unordered = order_counts.with_label_values(&["unordered"]);
742 let codec_order = order_counts.with_label_values(&["codec"]);
743 let structured_order = order_counts.with_label_values(&["structured"]);
744
745 BatchWriteMetrics {
746 bytes: registry.register(metric!(
747 name: format!("mz_persist_{}_bytes", name),
748 help: format!("total encoded size of {} batches written", name),
749 )),
750 goodbytes: registry.register(metric!(
751 name: format!("mz_persist_{}_goodbytes", name),
752 help: format!("total logical size of {} batches written", name),
753 )),
754 seconds: registry.register(metric!(
755 name: format!("mz_persist_{}_write_batch_part_seconds", name),
756 help: format!("time spent writing {} batches", name),
757 )),
758 write_stalls: registry.register(metric!(
759 name: format!("mz_persist_{}_write_stall_count", name),
760 help: format!(
761 "count of {} writes stalling to await max outstanding reqs",
762 name
763 ),
764 )),
765 key_lower_too_big: registry.register(metric!(
766 name: format!("mz_persist_{}_key_lower_too_big", name),
767 help: format!(
768 "count of {} writes that were unable to write a key lower, because the size threshold was too low",
769 name
770 ),
771 )),
772 unordered,
773 codec_order,
774 structured_order,
775 _order_counts: order_counts,
776 step_stats: registry.register(metric!(
777 name: format!("mz_persist_{}_step_stats", name),
778 help: format!("time spent computing {} update stats", name),
779 )),
780 step_part_writing: registry.register(metric!(
781 name: format!("mz_persist_{}_step_part_writing", name),
782 help: format!("blocking time spent writing parts for {} updates", name),
783 )),
784 step_inline: registry.register(metric!(
785 name: format!("mz_persist_{}_step_inline", name),
786 help: format!("time spent encoding {} inline batches", name)
787 )),
788 }
789 }
790}
791
792#[derive(Debug)]
793pub struct CompactionMetrics {
794 pub(crate) requested: IntCounter,
795 pub(crate) dropped: IntCounter,
796 pub(crate) disabled: IntCounter,
797 pub(crate) skipped: IntCounter,
798 pub(crate) started: IntCounter,
799 pub(crate) applied: IntCounter,
800 pub(crate) timed_out: IntCounter,
801 pub(crate) failed: IntCounter,
802 pub(crate) noop: IntCounter,
803 pub(crate) seconds: Counter,
804 pub(crate) concurrency_waits: IntCounter,
805 pub(crate) queued_seconds: Counter,
806 pub(crate) memory_violations: IntCounter,
807 pub(crate) runs_compacted: IntCounter,
808 pub(crate) chunks_compacted: IntCounter,
809 pub(crate) not_all_prefetched: IntCounter,
810 pub(crate) parts_prefetched: IntCounter,
811 pub(crate) parts_waited: IntCounter,
812 pub(crate) fast_path_eligible: IntCounter,
813 pub(crate) admin_count: IntCounter,
814
815 pub(crate) applied_exact_match: IntCounter,
816 pub(crate) applied_subset_match: IntCounter,
817 pub(crate) not_applied_too_many_updates: IntCounter,
818
819 pub(crate) batch: BatchWriteMetrics,
820 pub(crate) steps: CompactionStepTimings,
821 pub(crate) schema_selection: CompactionSchemaSelection,
822
823 pub(crate) _steps_vec: CounterVec,
824}
825
826impl CompactionMetrics {
827 fn new(registry: &MetricsRegistry) -> Self {
828 let step_timings: CounterVec = registry.register(metric!(
829 name: "mz_persist_compaction_step_seconds",
830 help: "time spent on individual steps of compaction",
831 var_labels: ["step"],
832 ));
833 let schema_selection: CounterVec = registry.register(metric!(
834 name: "mz_persist_compaction_schema_selection",
835 help: "count of compactions and how we did schema selection",
836 var_labels: ["selection"],
837 ));
838
839 CompactionMetrics {
840 requested: registry.register(metric!(
841 name: "mz_persist_compaction_requested",
842 help: "count of total compaction requests",
843 )),
844 dropped: registry.register(metric!(
845 name: "mz_persist_compaction_dropped",
846 help: "count of total compaction requests dropped due to a full queue",
847 )),
848 disabled: registry.register(metric!(
849 name: "mz_persist_compaction_disabled",
850 help: "count of total compaction requests dropped because compaction was disabled",
851 )),
852 skipped: registry.register(metric!(
853 name: "mz_persist_compaction_skipped",
854 help: "count of compactions skipped due to heuristics",
855 )),
856 started: registry.register(metric!(
857 name: "mz_persist_compaction_started",
858 help: "count of compactions started",
859 )),
860 failed: registry.register(metric!(
861 name: "mz_persist_compaction_failed",
862 help: "count of compactions failed",
863 )),
864 applied: registry.register(metric!(
865 name: "mz_persist_compaction_applied",
866 help: "count of compactions applied to state",
867 )),
868 timed_out: registry.register(metric!(
869 name: "mz_persist_compaction_timed_out",
870 help: "count of compactions that timed out",
871 )),
872 noop: registry.register(metric!(
873 name: "mz_persist_compaction_noop",
874 help: "count of compactions discarded (obsolete)",
875 )),
876 seconds: registry.register(metric!(
877 name: "mz_persist_compaction_seconds",
878 help: "time spent in compaction",
879 )),
880 concurrency_waits: registry.register(metric!(
881 name: "mz_persist_compaction_concurrency_waits",
882 help: "count of compaction requests that ever blocked due to concurrency limit",
883 )),
884 queued_seconds: registry.register(metric!(
885 name: "mz_persist_compaction_queued_seconds",
886 help: "time that compaction requests spent queued",
887 )),
888 memory_violations: registry.register(metric!(
889 name: "mz_persist_compaction_memory_violations",
890 help: "count of compaction memory requirement violations",
891 )),
892 runs_compacted: registry.register(metric!(
893 name: "mz_persist_compaction_runs_compacted",
894 help: "count of runs compacted",
895 )),
896 chunks_compacted: registry.register(metric!(
897 name: "mz_persist_compaction_chunks_compacted",
898 help: "count of run chunks compacted",
899 )),
900 not_all_prefetched: registry.register(metric!(
901 name: "mz_persist_compaction_not_all_prefetched",
902 help: "count of compactions where not all inputs were prefetched",
903 )),
904 parts_prefetched: registry.register(metric!(
905 name: "mz_persist_compaction_parts_prefetched",
906 help: "count of compaction parts completely prefetched by the time they're needed",
907 )),
908 parts_waited: registry.register(metric!(
909 name: "mz_persist_compaction_parts_waited",
910 help: "count of compaction parts that had to be waited on",
911 )),
912 fast_path_eligible: registry.register(metric!(
913 name: "mz_persist_compaction_fast_path_eligible",
914 help: "count of compaction requests that could have used the fast-path optimization",
915 )),
916 admin_count: registry.register(metric!(
917 name: "mz_persist_compaction_admin_count",
918 help: "count of compaction requests that were performed by admin tooling",
919 )),
920 applied_exact_match: registry.register(metric!(
921 name: "mz_persist_compaction_applied_exact_match",
922 help: "count of merge results that exactly replaced a SpineBatch",
923 )),
924 applied_subset_match: registry.register(metric!(
925 name: "mz_persist_compaction_applied_subset_match",
926 help: "count of merge results that replaced a subset of a SpineBatch",
927 )),
928 not_applied_too_many_updates: registry.register(metric!(
929 name: "mz_persist_compaction_not_applied_too_many_updates",
930 help: "count of merge results that did not apply due to too many updates",
931 )),
932 batch: BatchWriteMetrics::new(registry, "compaction"),
933 steps: CompactionStepTimings::new(step_timings.clone()),
934 schema_selection: CompactionSchemaSelection::new(schema_selection.clone()),
935 _steps_vec: step_timings,
936 }
937 }
938}
939
940#[derive(Debug)]
941pub struct CompactionStepTimings {
942 pub(crate) part_fetch_seconds: Counter,
943 pub(crate) heap_population_seconds: Counter,
944}
945
946impl CompactionStepTimings {
947 fn new(step_timings: CounterVec) -> CompactionStepTimings {
948 CompactionStepTimings {
949 part_fetch_seconds: step_timings.with_label_values(&["part_fetch"]),
950 heap_population_seconds: step_timings.with_label_values(&["heap_population"]),
951 }
952 }
953}
954
955#[derive(Debug)]
956pub struct CompactionSchemaSelection {
957 pub(crate) recent_schema: Counter,
958 pub(crate) no_schema: Counter,
959}
960
961impl CompactionSchemaSelection {
962 fn new(schema_selection: CounterVec) -> CompactionSchemaSelection {
963 CompactionSchemaSelection {
964 recent_schema: schema_selection.with_label_values(&["recent"]),
965 no_schema: schema_selection.with_label_values(&["none"]),
966 }
967 }
968}
969
970#[derive(Debug)]
971pub struct GcMetrics {
972 pub(crate) noop: IntCounter,
973 pub(crate) started: IntCounter,
974 pub(crate) finished: IntCounter,
975 pub(crate) merged: IntCounter,
976 pub(crate) seconds: Counter,
977 pub(crate) steps: GcStepTimings,
978}
979
980#[derive(Debug)]
981pub struct GcStepTimings {
982 pub(crate) find_removable_rollups: Counter,
983 pub(crate) fetch_seconds: Counter,
984 pub(crate) find_deletable_blobs_seconds: Counter,
985 pub(crate) delete_rollup_seconds: Counter,
986 pub(crate) delete_batch_part_seconds: Counter,
987 pub(crate) truncate_diff_seconds: Counter,
988 pub(crate) remove_rollups_from_state: Counter,
989 pub(crate) post_gc_calculations_seconds: Counter,
990}
991
992impl GcStepTimings {
993 fn new(step_timings: CounterVec) -> Self {
994 Self {
995 find_removable_rollups: step_timings.with_label_values(&["find_removable_rollups"]),
996 fetch_seconds: step_timings.with_label_values(&["fetch"]),
997 find_deletable_blobs_seconds: step_timings.with_label_values(&["find_deletable_blobs"]),
998 delete_rollup_seconds: step_timings.with_label_values(&["delete_rollup"]),
999 delete_batch_part_seconds: step_timings.with_label_values(&["delete_batch_part"]),
1000 truncate_diff_seconds: step_timings.with_label_values(&["truncate_diff"]),
1001 remove_rollups_from_state: step_timings
1002 .with_label_values(&["remove_rollups_from_state"]),
1003 post_gc_calculations_seconds: step_timings.with_label_values(&["post_gc_calculations"]),
1004 }
1005 }
1006}
1007
1008impl GcMetrics {
1009 fn new(registry: &MetricsRegistry) -> Self {
1010 let step_timings: CounterVec = registry.register(metric!(
1011 name: "mz_persist_gc_step_seconds",
1012 help: "time spent on individual steps of gc",
1013 var_labels: ["step"],
1014 ));
1015 GcMetrics {
1016 noop: registry.register(metric!(
1017 name: "mz_persist_gc_noop",
1018 help: "count of garbage collections skipped because they were already done",
1019 )),
1020 started: registry.register(metric!(
1021 name: "mz_persist_gc_started",
1022 help: "count of garbage collections started",
1023 )),
1024 finished: registry.register(metric!(
1025 name: "mz_persist_gc_finished",
1026 help: "count of garbage collections finished",
1027 )),
1028 merged: registry.register(metric!(
1029 name: "mz_persist_gc_merged_reqs",
1030 help: "count of garbage collection requests merged",
1031 )),
1032 seconds: registry.register(metric!(
1033 name: "mz_persist_gc_seconds",
1034 help: "time spent in garbage collections",
1035 )),
1036 steps: GcStepTimings::new(step_timings),
1037 }
1038 }
1039}
1040
1041#[derive(Debug)]
1042pub struct LeaseMetrics {
1043 pub(crate) timeout_read: IntCounter,
1044 pub(crate) dropped_part: IntCounter,
1045}
1046
1047impl LeaseMetrics {
1048 fn new(registry: &MetricsRegistry) -> Self {
1049 LeaseMetrics {
1050 timeout_read: registry.register(metric!(
1051 name: "mz_persist_lease_timeout_read",
1052 help: "count of readers whose lease timed out",
1053 )),
1054 dropped_part: registry.register(metric!(
1055 name: "mz_persist_lease_dropped_part",
1056 help: "count of LeasedBatchParts that were dropped without being politely returned",
1057 )),
1058 }
1059 }
1060}
1061
1062struct IncOnDrop(IntCounter);
1063
1064impl Drop for IncOnDrop {
1065 fn drop(&mut self) {
1066 self.0.inc()
1067 }
1068}
1069
1070pub struct MetricsRetryStream {
1071 retry: RetryStream,
1072 pub(crate) retries: IntCounter,
1073 sleep_seconds: Counter,
1074 _finished: IncOnDrop,
1075}
1076
1077impl MetricsRetryStream {
1078 pub fn new(retry: RetryStream, metrics: &RetryMetrics) -> Self {
1079 metrics.started.inc();
1080 MetricsRetryStream {
1081 retry,
1082 retries: metrics.retries.clone(),
1083 sleep_seconds: metrics.sleep_seconds.clone(),
1084 _finished: IncOnDrop(metrics.finished.clone()),
1085 }
1086 }
1087
1088 pub fn attempt(&self) -> usize {
1090 self.retry.attempt()
1091 }
1092
1093 pub fn next_sleep(&self) -> Duration {
1095 self.retry.next_sleep()
1096 }
1097
1098 pub async fn sleep(self) -> Self {
1103 self.retries.inc();
1104 self.sleep_seconds
1105 .inc_by(self.retry.next_sleep().as_secs_f64());
1106 let retry = self.retry.sleep().await;
1107 MetricsRetryStream {
1108 retry,
1109 retries: self.retries,
1110 sleep_seconds: self.sleep_seconds,
1111 _finished: self._finished,
1112 }
1113 }
1114}
1115
1116#[derive(Debug)]
1117pub struct CodecsMetrics {
1118 pub(crate) state: CodecMetrics,
1119 pub(crate) state_diff: CodecMetrics,
1120 pub(crate) batch: CodecMetrics,
1121 pub(crate) key: CodecMetrics,
1122 pub(crate) val: CodecMetrics,
1123 }
1126
1127#[derive(Debug)]
1128pub struct CodecMetrics {
1129 pub(crate) encode_count: IntCounter,
1130 pub(crate) encode_seconds: Counter,
1131 pub(crate) decode_count: IntCounter,
1132 pub(crate) decode_seconds: Counter,
1133}
1134
1135impl CodecMetrics {
1136 pub(crate) fn encode<R, F: FnOnce() -> R>(&self, f: F) -> R {
1137 let now = Instant::now();
1138 let r = f();
1139 self.encode_count.inc();
1140 self.encode_seconds.inc_by(now.elapsed().as_secs_f64());
1141 r
1142 }
1143
1144 pub(crate) fn decode<R, F: FnOnce() -> R>(&self, f: F) -> R {
1145 let now = Instant::now();
1146 let r = f();
1147 self.decode_count.inc();
1148 self.decode_seconds.inc_by(now.elapsed().as_secs_f64());
1149 r
1150 }
1151}
1152
1153#[derive(Debug)]
1154pub struct StateMetrics {
1155 pub(crate) apply_spine_fast_path: IntCounter,
1156 pub(crate) apply_spine_slow_path: IntCounter,
1157 pub(crate) apply_spine_slow_path_lenient: IntCounter,
1158 pub(crate) apply_spine_slow_path_lenient_adjustment: IntCounter,
1159 pub(crate) apply_spine_slow_path_with_reconstruction: IntCounter,
1160 pub(crate) apply_spine_flattened: IntCounter,
1161 pub(crate) update_state_noop_path: IntCounter,
1162 pub(crate) update_state_empty_path: IntCounter,
1163 pub(crate) update_state_fast_path: IntCounter,
1164 pub(crate) update_state_slow_path: IntCounter,
1165 pub(crate) rollup_at_seqno_migration: IntCounter,
1166 pub(crate) fetch_recent_live_diffs_fast_path: IntCounter,
1167 pub(crate) fetch_recent_live_diffs_slow_path: IntCounter,
1168 pub(crate) writer_added: IntCounter,
1169 pub(crate) writer_removed: IntCounter,
1170 pub(crate) force_apply_hostname: IntCounter,
1171 pub(crate) rollup_write_success: IntCounter,
1172 pub(crate) rollup_write_noop_latest: IntCounter,
1173 pub(crate) rollup_write_noop_truncated: IntCounter,
1174}
1175
1176impl StateMetrics {
1177 pub(crate) fn new(registry: &MetricsRegistry) -> Self {
1178 let rollup_write_noop: IntCounterVec = registry.register(metric!(
1179 name: "mz_persist_state_rollup_write_noop",
1180 help: "count of no-op rollup writes",
1181 var_labels: ["reason"],
1182 ));
1183
1184 StateMetrics {
1185 apply_spine_fast_path: registry.register(metric!(
1186 name: "mz_persist_state_apply_spine_fast_path",
1187 help: "count of spine diff applications that hit the fast path",
1188 )),
1189 apply_spine_slow_path: registry.register(metric!(
1190 name: "mz_persist_state_apply_spine_slow_path",
1191 help: "count of spine diff applications that hit the slow path",
1192 )),
1193 apply_spine_slow_path_lenient: registry.register(metric!(
1194 name: "mz_persist_state_apply_spine_slow_path_lenient",
1195 help: "count of spine diff applications that hit the lenient compaction apply path",
1196 )),
1197 apply_spine_slow_path_lenient_adjustment: registry.register(metric!(
1198 name: "mz_persist_state_apply_spine_slow_path_lenient_adjustment",
1199 help: "count of adjustments made by the lenient compaction apply path",
1200 )),
1201 apply_spine_slow_path_with_reconstruction: registry.register(metric!(
1202 name: "mz_persist_state_apply_spine_slow_path_with_reconstruction",
1203 help: "count of spine diff applications that hit the slow path with extra spine reconstruction step",
1204 )),
1205 apply_spine_flattened: registry.register(metric!(
1206 name: "mz_persist_state_apply_spine_flattened",
1207 help: "count of spine diff applications that flatten the trace",
1208 )),
1209 update_state_noop_path: registry.register(metric!(
1210 name: "mz_persist_state_update_state_noop_path",
1211 help: "count of state update applications that no-oped due to shared state",
1212 )),
1213 update_state_empty_path: registry.register(metric!(
1214 name: "mz_persist_state_update_state_empty_path",
1215 help: "count of state update applications that found no new updates",
1216 )),
1217 update_state_fast_path: registry.register(metric!(
1218 name: "mz_persist_state_update_state_fast_path",
1219 help: "count of state update applications that hit the fast path",
1220 )),
1221 update_state_slow_path: registry.register(metric!(
1222 name: "mz_persist_state_update_state_slow_path",
1223 help: "count of state update applications that hit the slow path",
1224 )),
1225 rollup_at_seqno_migration: registry.register(metric!(
1226 name: "mz_persist_state_rollup_at_seqno_migration",
1227 help: "count of fetch_rollup_at_seqno calls that only worked because of the migration",
1228 )),
1229 fetch_recent_live_diffs_fast_path: registry.register(metric!(
1230 name: "mz_persist_state_fetch_recent_live_diffs_fast_path",
1231 help: "count of fetch_recent_live_diffs that hit the fast path",
1232 )),
1233 fetch_recent_live_diffs_slow_path: registry.register(metric!(
1234 name: "mz_persist_state_fetch_recent_live_diffs_slow_path",
1235 help: "count of fetch_recent_live_diffs that hit the slow path",
1236 )),
1237 writer_added: registry.register(metric!(
1238 name: "mz_persist_state_writer_added",
1239 help: "count of writers added to the state",
1240 )),
1241 writer_removed: registry.register(metric!(
1242 name: "mz_persist_state_writer_removed",
1243 help: "count of writers removed from the state",
1244 )),
1245 force_apply_hostname: registry.register(metric!(
1246 name: "mz_persist_state_force_applied_hostname",
1247 help: "count of when hostname diffs needed to be force applied",
1248 )),
1249 rollup_write_success: registry.register(metric!(
1250 name: "mz_persist_state_rollup_write_success",
1251 help: "count of rollups written successful (may not be linked in to state)",
1252 )),
1253 rollup_write_noop_latest: rollup_write_noop.with_label_values(&["latest"]),
1254 rollup_write_noop_truncated: rollup_write_noop.with_label_values(&["truncated"]),
1255 }
1256 }
1257}
1258
1259#[derive(Debug)]
1260pub struct ShardsMetrics {
1261 encoded_rollup_size: mz_ore::metrics::UIntGaugeVec,
1270 encoded_diff_size: mz_ore::metrics::IntCounterVec,
1271 hollow_batch_count: mz_ore::metrics::UIntGaugeVec,
1272 spine_batch_count: mz_ore::metrics::UIntGaugeVec,
1273 batch_part_count: mz_ore::metrics::UIntGaugeVec,
1274 batch_part_version_count: mz_ore::metrics::UIntGaugeVec,
1275 update_count: mz_ore::metrics::UIntGaugeVec,
1276 rollup_count: mz_ore::metrics::UIntGaugeVec,
1277 largest_batch_size: mz_ore::metrics::UIntGaugeVec,
1278 seqnos_held: mz_ore::metrics::UIntGaugeVec,
1279 seqnos_since_last_rollup: mz_ore::metrics::UIntGaugeVec,
1280 gc_seqno_held_parts: mz_ore::metrics::UIntGaugeVec,
1281 gc_live_diffs: mz_ore::metrics::UIntGaugeVec,
1282 gc_finished: mz_ore::metrics::IntCounterVec,
1283 compaction_applied: mz_ore::metrics::IntCounterVec,
1284 cmd_succeeded: mz_ore::metrics::IntCounterVec,
1285 usage_current_state_batches_bytes: mz_ore::metrics::UIntGaugeVec,
1286 usage_current_state_rollups_bytes: mz_ore::metrics::UIntGaugeVec,
1287 usage_referenced_not_current_state_bytes: mz_ore::metrics::UIntGaugeVec,
1288 usage_not_leaked_not_referenced_bytes: mz_ore::metrics::UIntGaugeVec,
1289 usage_leaked_bytes: mz_ore::metrics::UIntGaugeVec,
1290 blob_gets: mz_ore::metrics::IntCounterVec,
1291 blob_sets: mz_ore::metrics::IntCounterVec,
1292 unconsolidated_snapshot: mz_ore::metrics::IntCounterVec,
1293 inline_part_count: UIntGaugeVec,
1294 compact_batches: UIntGaugeVec,
1295 compacting_batches: UIntGaugeVec,
1296 noncompact_batches: UIntGaugeVec,
1297 shards: Arc<Mutex<BTreeMap<ShardId, Weak<ShardMetrics>>>>,
1301}
1302
1303impl ShardsMetrics {
1304 fn new(registry: &MetricsRegistry) -> Self {
1305 let shards = Arc::new(Mutex::new(BTreeMap::new()));
1306 registry.register_collector(ShardsAggregateMetrics::new(Arc::clone(&shards)));
1307 ShardsMetrics {
1308 encoded_rollup_size: registry.register(metric!(
1309 name: "mz_persist_shard_rollup_size_bytes",
1310 help: "total encoded rollup size by shard",
1311 var_labels: ["shard", "name"],
1312 )),
1313 encoded_diff_size: registry.register(metric!(
1314 name: "mz_persist_shard_diff_size_bytes",
1315 help: "total encoded diff size by shard",
1316 var_labels: ["shard", "name"],
1317 )),
1318 hollow_batch_count: registry.register(metric!(
1319 name: "mz_persist_shard_hollow_batch_count",
1320 help: "count of hollow batches by shard",
1321 var_labels: ["shard", "name"],
1322 )),
1323 spine_batch_count: registry.register(metric!(
1324 name: "mz_persist_shard_spine_batch_count",
1325 help: "count of spine batches by shard",
1326 var_labels: ["shard", "name"],
1327 )),
1328 batch_part_count: registry.register(metric!(
1329 name: "mz_persist_shard_batch_part_count",
1330 help: "count of batch parts by shard",
1331 var_labels: ["shard", "name"],
1332 )),
1333 batch_part_version_count: registry.register(metric!(
1334 name: "mz_persist_shard_batch_part_version_count",
1335 help: "count of batch parts by shard and version",
1336 var_labels: ["shard", "name", "version"],
1337 )),
1338 update_count: registry.register(metric!(
1339 name: "mz_persist_shard_update_count",
1340 help: "count of updates by shard",
1341 var_labels: ["shard", "name"],
1342 )),
1343 rollup_count: registry.register(metric!(
1344 name: "mz_persist_shard_rollup_count",
1345 help: "count of rollups by shard",
1346 var_labels: ["shard", "name"],
1347 )),
1348 largest_batch_size: registry.register(metric!(
1349 name: "mz_persist_shard_largest_batch_size",
1350 help: "largest encoded batch size by shard",
1351 var_labels: ["shard", "name"],
1352 )),
1353 seqnos_held: registry.register(metric!(
1354 name: "mz_persist_shard_seqnos_held",
1355 help: "maximum count of gc-ineligible states by shard",
1356 var_labels: ["shard", "name"],
1357 )),
1358 seqnos_since_last_rollup: registry.register(metric!(
1359 name: "mz_persist_shard_seqnos_since_last_rollup",
1360 help: "count of seqnos since last rollup",
1361 var_labels: ["shard", "name"],
1362 )),
1363 gc_seqno_held_parts: registry.register(metric!(
1364 name: "mz_persist_shard_gc_seqno_held_parts",
1365 help: "count of parts referenced by some live state but not the current state (ie. parts kept only to satisfy seqno holds) at GC time",
1366 var_labels: ["shard", "name"],
1367 )),
1368 gc_live_diffs: registry.register(metric!(
1369 name: "mz_persist_shard_gc_live_diffs",
1370 help: "the number of diffs (or, alternatively, the number of seqnos) present in consensus state at GC time",
1371 var_labels: ["shard", "name"],
1372 )),
1373 gc_finished: registry.register(metric!(
1374 name: "mz_persist_shard_gc_finished",
1375 help: "count of garbage collections finished by shard",
1376 var_labels: ["shard", "name"],
1377 )),
1378 compaction_applied: registry.register(metric!(
1379 name: "mz_persist_shard_compaction_applied",
1380 help: "count of compactions applied to state by shard",
1381 var_labels: ["shard", "name"],
1382 )),
1383 cmd_succeeded: registry.register(metric!(
1384 name: "mz_persist_shard_cmd_succeeded",
1385 help: "count of commands succeeded by shard",
1386 var_labels: ["shard", "name"],
1387 )),
1388 usage_current_state_batches_bytes: registry.register(metric!(
1389 name: "mz_persist_shard_usage_current_state_batches_bytes",
1390 help: "data in batches/parts referenced by current version of state",
1391 var_labels: ["shard", "name"],
1392 )),
1393 usage_current_state_rollups_bytes: registry.register(metric!(
1394 name: "mz_persist_shard_usage_current_state_rollups_bytes",
1395 help: "data in rollups referenced by current version of state",
1396 var_labels: ["shard", "name"],
1397 )),
1398 usage_referenced_not_current_state_bytes: registry.register(metric!(
1399 name: "mz_persist_shard_usage_referenced_not_current_state_bytes",
1400 help: "data referenced only by a previous version of state",
1401 var_labels: ["shard", "name"],
1402 )),
1403 usage_not_leaked_not_referenced_bytes: registry.register(metric!(
1404 name: "mz_persist_shard_usage_not_leaked_not_referenced_bytes",
1405 help: "data written by an active writer but not referenced by any version of state",
1406 var_labels: ["shard", "name"],
1407 )),
1408 usage_leaked_bytes: registry.register(metric!(
1409 name: "mz_persist_shard_usage_leaked_bytes",
1410 help: "data reclaimable by a leaked blob detector",
1411 var_labels: ["shard", "name"],
1412 )),
1413 blob_gets: registry.register(metric!(
1414 name: "mz_persist_shard_blob_gets",
1415 help: "number of Blob::get calls for this shard",
1416 var_labels: ["shard", "name"],
1417 )),
1418 blob_sets: registry.register(metric!(
1419 name: "mz_persist_shard_blob_sets",
1420 help: "number of Blob::set calls for this shard",
1421 var_labels: ["shard", "name"],
1422 )),
1423 unconsolidated_snapshot: registry.register(metric!(
1424 name: "mz_persist_shard_unconsolidated_snapshot",
1425 help: "in snapshot_and_read, the number of times consolidating the raw data wasn't enough to produce consolidated output",
1426 var_labels: ["shard", "name"],
1427 )),
1428 inline_part_count: registry.register(metric!(
1429 name: "mz_persist_shard_inline_part_count",
1430 help: "count of parts inline in shard metadata",
1431 var_labels: ["shard", "name"],
1432 )),
1433 compact_batches: registry.register(metric!(
1434 name: "mz_persist_shard_compact_batches",
1435 help: "number of fully compact batches in the shard",
1436 var_labels: ["shard", "name"],
1437 )),
1438 compacting_batches: registry.register(metric!(
1439 name: "mz_persist_shard_compacting_batches",
1440 help: "number of batches in the shard with compactions in progress",
1441 var_labels: ["shard", "name"],
1442 )),
1443 noncompact_batches: registry.register(metric!(
1444 name: "mz_persist_shard_noncompact_batches",
1445 help: "number of batches in the shard that aren't compact and have no ongoing compaction",
1446 var_labels: ["shard", "name"],
1447 )),
1448 shards,
1449 }
1450 }
1451
1452 pub fn shard(&self, shard_id: &ShardId, name: &str) -> Arc<ShardMetrics> {
1453 let mut shards = self.shards.lock().expect("mutex poisoned");
1454 if let Some(shard) = shards.get(shard_id) {
1455 if let Some(shard) = shard.upgrade() {
1456 return Arc::clone(&shard);
1457 } else {
1458 assert!(shards.remove(shard_id).is_some());
1459 }
1460 }
1461 let shard = Arc::new(ShardMetrics::new(shard_id, name, self));
1462 assert!(
1463 shards
1464 .insert(shard_id.clone(), Arc::downgrade(&shard))
1465 .is_none()
1466 );
1467 shard
1468 }
1469
1470 fn compute<F: FnMut(&ShardMetrics)>(
1471 shards: &Arc<Mutex<BTreeMap<ShardId, Weak<ShardMetrics>>>>,
1472 mut f: F,
1473 ) {
1474 let mut shards = shards.lock().expect("mutex poisoned");
1475 let mut deleted_shards = Vec::new();
1476 for (shard_id, metrics) in shards.iter() {
1477 if let Some(metrics) = metrics.upgrade() {
1478 f(&metrics);
1479 } else {
1480 deleted_shards.push(shard_id.clone());
1481 }
1482 }
1483 for deleted_shard_id in deleted_shards {
1484 assert!(shards.remove(&deleted_shard_id).is_some());
1485 }
1486 }
1487}
1488
1489#[derive(Debug)]
1496struct ShardsAggregateMetrics {
1497 shards: Arc<Mutex<BTreeMap<ShardId, Weak<ShardMetrics>>>>,
1498 count: GenericGauge<AtomicI64>,
1499 stale_count: GenericGauge<AtomicI64>,
1500}
1501
1502impl ShardsAggregateMetrics {
1503 fn new(shards: Arc<Mutex<BTreeMap<ShardId, Weak<ShardMetrics>>>>) -> Self {
1504 ShardsAggregateMetrics {
1505 shards,
1506 count: MakeCollector::make_collector(metric!(
1507 name: "mz_persist_shard_count",
1508 help: "count of all active shards on this process",
1509 )),
1510 stale_count: MakeCollector::make_collector(metric!(
1511 name: "mz_persist_stale_shard_count",
1512 help: "count of shards on this process whose persisted state version \
1513 is behind this process's build version; per-process, so summing \
1514 across processes counts (shard, process) pairs, not distinct shards",
1515 )),
1516 }
1517 }
1518}
1519
1520impl Collector for ShardsAggregateMetrics {
1521 fn desc(&self) -> Vec<&Desc> {
1522 let mut descs = self.count.desc();
1523 descs.extend(self.stale_count.desc());
1524 descs
1525 }
1526
1527 fn collect(&self) -> Vec<MetricFamily> {
1528 let mut count = 0;
1529 let mut stale_count = 0;
1530 ShardsMetrics::compute(&self.shards, |m| {
1531 count += 1;
1532 if m.stale.load(Ordering::Relaxed) {
1533 stale_count += 1;
1534 }
1535 });
1536 self.count.set(count);
1537 self.stale_count.set(stale_count);
1538 let mut families = self.count.collect();
1539 families.extend(self.stale_count.collect());
1540 families
1541 }
1542}
1543
1544#[derive(Debug)]
1545pub struct ShardMetrics {
1546 pub shard_id: ShardId,
1547 pub name: String,
1548 pub largest_batch_size: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1549 pub latest_rollup_size: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1550 pub encoded_diff_size: DeleteOnDropCounter<AtomicU64, Vec<String>>,
1551 pub hollow_batch_count: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1552 pub spine_batch_count: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1553 pub batch_part_count: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1554 batch_part_version_count: mz_ore::metrics::UIntGaugeVec,
1555 batch_part_version_map: Mutex<BTreeMap<String, BatchPartVersionMetrics>>,
1556 pub update_count: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1557 pub rollup_count: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1558 pub seqnos_held: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1559 pub seqnos_since_last_rollup: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1560 pub gc_seqno_held_parts: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1561 pub gc_live_diffs: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1562 pub usage_current_state_batches_bytes: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1563 pub usage_current_state_rollups_bytes: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1564 pub usage_referenced_not_current_state_bytes: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1565 pub usage_not_leaked_not_referenced_bytes: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1566 pub usage_leaked_bytes: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1567 pub gc_finished: DeleteOnDropCounter<AtomicU64, Vec<String>>,
1568 pub compaction_applied: DeleteOnDropCounter<AtomicU64, Vec<String>>,
1569 pub cmd_succeeded: DeleteOnDropCounter<AtomicU64, Vec<String>>,
1570 pub blob_gets: DeleteOnDropCounter<AtomicU64, Vec<String>>,
1571 pub blob_sets: DeleteOnDropCounter<AtomicU64, Vec<String>>,
1572 pub unconsolidated_snapshot: DeleteOnDropCounter<AtomicU64, Vec<String>>,
1573 pub inline_part_count: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1574 pub compact_batches: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1575 pub compacting_batches: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1576 pub noncompact_batches: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1577 pub stale: AtomicBool,
1581}
1582
1583impl ShardMetrics {
1584 pub fn new(shard_id: &ShardId, name: &str, shards_metrics: &ShardsMetrics) -> Self {
1585 let shard = shard_id.to_string();
1586 ShardMetrics {
1587 shard_id: *shard_id,
1588 name: name.to_string(),
1589 latest_rollup_size: shards_metrics
1590 .encoded_rollup_size
1591 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1592 encoded_diff_size: shards_metrics
1593 .encoded_diff_size
1594 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1595 hollow_batch_count: shards_metrics
1596 .hollow_batch_count
1597 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1598 spine_batch_count: shards_metrics
1599 .spine_batch_count
1600 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1601 batch_part_count: shards_metrics
1602 .batch_part_count
1603 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1604 batch_part_version_count: shards_metrics.batch_part_version_count.clone(),
1605 batch_part_version_map: Mutex::new(BTreeMap::new()),
1606 update_count: shards_metrics
1607 .update_count
1608 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1609 rollup_count: shards_metrics
1610 .rollup_count
1611 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1612 largest_batch_size: shards_metrics
1613 .largest_batch_size
1614 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1615 seqnos_held: shards_metrics
1616 .seqnos_held
1617 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1618 seqnos_since_last_rollup: shards_metrics
1619 .seqnos_since_last_rollup
1620 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1621 gc_seqno_held_parts: shards_metrics
1622 .gc_seqno_held_parts
1623 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1624 gc_live_diffs: shards_metrics
1625 .gc_live_diffs
1626 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1627 gc_finished: shards_metrics
1628 .gc_finished
1629 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1630 compaction_applied: shards_metrics
1631 .compaction_applied
1632 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1633 cmd_succeeded: shards_metrics
1634 .cmd_succeeded
1635 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1636 usage_current_state_batches_bytes: shards_metrics
1637 .usage_current_state_batches_bytes
1638 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1639 usage_current_state_rollups_bytes: shards_metrics
1640 .usage_current_state_rollups_bytes
1641 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1642 usage_referenced_not_current_state_bytes: shards_metrics
1643 .usage_referenced_not_current_state_bytes
1644 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1645 usage_not_leaked_not_referenced_bytes: shards_metrics
1646 .usage_not_leaked_not_referenced_bytes
1647 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1648 usage_leaked_bytes: shards_metrics
1649 .usage_leaked_bytes
1650 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1651 blob_gets: shards_metrics
1652 .blob_gets
1653 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1654 blob_sets: shards_metrics
1655 .blob_sets
1656 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1657 unconsolidated_snapshot: shards_metrics
1658 .unconsolidated_snapshot
1659 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1660 inline_part_count: shards_metrics
1661 .inline_part_count
1662 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1663 compact_batches: shards_metrics
1664 .compact_batches
1665 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1666 compacting_batches: shards_metrics
1667 .compacting_batches
1668 .get_delete_on_drop_metric(vec![shard.clone(), name.to_string()]),
1669 noncompact_batches: shards_metrics
1670 .noncompact_batches
1671 .get_delete_on_drop_metric(vec![shard, name.to_string()]),
1672 stale: AtomicBool::new(false),
1673 }
1674 }
1675
1676 pub(crate) fn set_batch_part_versions<'a>(
1677 &self,
1678 batch_parts_by_version: impl Iterator<Item = &'a str>,
1679 ) {
1680 let mut map = self
1681 .batch_part_version_map
1682 .lock()
1683 .expect("mutex should not be poisoned");
1684 for x in map.values() {
1691 x.batch_part_version_count.set(0);
1692 }
1693
1694 for key in batch_parts_by_version {
1697 if !map.contains_key(key) {
1698 map.insert(
1699 key.to_owned(),
1700 BatchPartVersionMetrics {
1701 batch_part_version_count: self
1702 .batch_part_version_count
1703 .get_delete_on_drop_metric(vec![
1704 self.shard_id.to_string(),
1705 self.name.clone(),
1706 key.to_owned(),
1707 ]),
1708 },
1709 );
1710 }
1711 let value = map.get(key).expect("inserted above");
1712 value.batch_part_version_count.inc();
1713 }
1714 }
1715}
1716
1717#[derive(Debug)]
1718pub struct BatchPartVersionMetrics {
1719 pub batch_part_version_count: DeleteOnDropGauge<AtomicU64, Vec<String>>,
1720}
1721
1722#[derive(Debug)]
1724pub struct UsageAuditMetrics {
1725 pub blob_batch_part_bytes: UIntGauge,
1727 pub blob_batch_part_count: UIntGauge,
1729 pub blob_rollup_bytes: UIntGauge,
1731 pub blob_rollup_count: UIntGauge,
1733 pub blob_bytes: UIntGauge,
1735 pub blob_count: UIntGauge,
1737 pub step_blob_metadata: Counter,
1739 pub step_state: Counter,
1741 pub step_math: Counter,
1743}
1744
1745impl UsageAuditMetrics {
1746 fn new(registry: &MetricsRegistry) -> Self {
1747 let step_timings: CounterVec = registry.register(metric!(
1748 name: "mz_persist_audit_step_seconds",
1749 help: "time spent on individual steps of audit",
1750 var_labels: ["step"],
1751 ));
1752 UsageAuditMetrics {
1753 blob_batch_part_bytes: registry.register(metric!(
1754 name: "mz_persist_audit_blob_batch_part_bytes",
1755 help: "total size of batch parts in blob",
1756 )),
1757 blob_batch_part_count: registry.register(metric!(
1758 name: "mz_persist_audit_blob_batch_part_count",
1759 help: "count of batch parts in blob",
1760 )),
1761 blob_rollup_bytes: registry.register(metric!(
1762 name: "mz_persist_audit_blob_rollup_bytes",
1763 help: "total size of state rollups stored in blob",
1764 )),
1765 blob_rollup_count: registry.register(metric!(
1766 name: "mz_persist_audit_blob_rollup_count",
1767 help: "count of all state rollups in blob",
1768 )),
1769 blob_bytes: registry.register(metric!(
1770 name: "mz_persist_audit_blob_bytes",
1771 help: "total size of blob",
1772 )),
1773 blob_count: registry.register(metric!(
1774 name: "mz_persist_audit_blob_count",
1775 help: "count of all blobs",
1776 )),
1777 step_blob_metadata: step_timings.with_label_values(&["blob_metadata"]),
1778 step_state: step_timings.with_label_values(&["state"]),
1779 step_math: step_timings.with_label_values(&["math"]),
1780 }
1781 }
1782}
1783
1784#[derive(Debug)]
1787pub enum UpdateDelta {
1788 Negative(u64),
1790 NonNegative(u64),
1792}
1793
1794impl UpdateDelta {
1795 pub fn new(new: usize, old: usize) -> Self {
1798 if new < old {
1799 UpdateDelta::Negative(CastFrom::cast_from(old - new))
1800 } else {
1801 UpdateDelta::NonNegative(CastFrom::cast_from(new - old))
1802 }
1803 }
1804}
1805
1806#[derive(Debug, Clone)]
1809pub struct SinkMetrics {
1810 correction_insertions_total: IntCounter,
1812 correction_deletions_total: IntCounter,
1814 correction_capacity_increases_total: IntCounter,
1816 correction_capacity_decreases_total: IntCounter,
1818 correction_max_per_sink_worker_len_updates: raw::UIntGaugeVec,
1820 correction_max_per_sink_worker_capacity_updates: raw::UIntGaugeVec,
1822}
1823
1824impl SinkMetrics {
1825 fn new(registry: &MetricsRegistry) -> Self {
1826 SinkMetrics {
1827 correction_insertions_total: registry.register(metric!(
1828 name: "mz_persist_sink_correction_insertions_total",
1829 help: "The cumulative insertions observed on the correction buffer across workers and persist sinks.",
1830 )),
1831 correction_deletions_total: registry.register(metric!(
1832 name: "mz_persist_sink_correction_deletions_total",
1833 help: "The cumulative deletions observed on the correction buffer across workers and persist sinks.",
1834 )),
1835 correction_capacity_increases_total: registry.register(metric!(
1836 name: "mz_persist_sink_correction_capacity_increases_total",
1837 help: "The cumulative capacity increases observed on the correction buffer across workers and persist sinks.",
1838 )),
1839 correction_capacity_decreases_total: registry.register(metric!(
1840 name: "mz_persist_sink_correction_capacity_decreases_total",
1841 help: "The cumulative capacity decreases observed on the correction buffer across workers and persist sinks.",
1842 )),
1843 correction_max_per_sink_worker_len_updates: registry.register(metric!(
1844 name: "mz_persist_sink_correction_max_per_sink_worker_len_updates",
1845 help: "The maximum length observed for the correction buffer of any single persist sink per worker.",
1846 var_labels: ["worker_id"],
1847 )),
1848 correction_max_per_sink_worker_capacity_updates: registry.register(metric!(
1849 name: "mz_persist_sink_correction_max_per_sink_worker_capacity_updates",
1850 help: "The maximum capacity observed for the correction buffer of any single persist sink per worker.",
1851 var_labels: ["worker_id"],
1852 )),
1853 }
1854 }
1855
1856 pub fn for_worker(&self, worker_id: usize) -> SinkWorkerMetrics {
1861 let worker = worker_id.to_string();
1862 let correction_max_per_sink_worker_len_updates = self
1863 .correction_max_per_sink_worker_len_updates
1864 .with_label_values(&[&worker]);
1865 let correction_max_per_sink_worker_capacity_updates = self
1866 .correction_max_per_sink_worker_capacity_updates
1867 .with_label_values(&[&worker]);
1868 SinkWorkerMetrics {
1869 correction_max_per_sink_worker_len_updates,
1870 correction_max_per_sink_worker_capacity_updates,
1871 }
1872 }
1873
1874 pub fn report_correction_update_deltas(
1880 &self,
1881 correction_len_delta: UpdateDelta,
1882 correction_cap_delta: UpdateDelta,
1883 ) {
1884 match correction_len_delta {
1886 UpdateDelta::NonNegative(delta) => {
1887 if delta > 0 {
1888 self.correction_insertions_total.inc_by(delta)
1889 }
1890 }
1891 UpdateDelta::Negative(delta) => self.correction_deletions_total.inc_by(delta),
1892 }
1893 match correction_cap_delta {
1895 UpdateDelta::NonNegative(delta) => {
1896 if delta > 0 {
1897 self.correction_capacity_increases_total.inc_by(delta)
1898 }
1899 }
1900 UpdateDelta::Negative(delta) => self.correction_capacity_decreases_total.inc_by(delta),
1901 }
1902 }
1903}
1904
1905#[derive(Clone, Debug)]
1907pub struct SinkWorkerMetrics {
1908 correction_max_per_sink_worker_len_updates: UIntGauge,
1909 correction_max_per_sink_worker_capacity_updates: UIntGauge,
1910}
1911
1912impl SinkWorkerMetrics {
1913 pub fn report_correction_update_totals(&self, correction_len: usize, correction_cap: usize) {
1918 let correction_len = CastFrom::cast_from(correction_len);
1920 if correction_len > self.correction_max_per_sink_worker_len_updates.get() {
1921 self.correction_max_per_sink_worker_len_updates
1922 .set(correction_len);
1923 }
1924 let correction_cap = CastFrom::cast_from(correction_cap);
1925 if correction_cap > self.correction_max_per_sink_worker_capacity_updates.get() {
1926 self.correction_max_per_sink_worker_capacity_updates
1927 .set(correction_cap);
1928 }
1929 }
1930}
1931
1932#[derive(Debug)]
1937pub struct BackpressureMetrics {
1938 pub emitted_bytes: IntCounter,
1940 pub last_backpressured_bytes: UIntGauge,
1944 pub retired_bytes: IntCounter,
1946}
1947
1948impl BackpressureMetrics {
1949 fn new(registry: &MetricsRegistry) -> Self {
1950 BackpressureMetrics {
1951 emitted_bytes: registry.register(metric!(
1952 name: "mz_persist_backpressure_emitted_bytes",
1953 help: "bytes emitted by backpressure operators",
1954 )),
1955 last_backpressured_bytes: registry.register(metric!(
1956 name: "mz_persist_backpressure_last_backpressured_bytes",
1957 help: "sum over backpressure operators of the inflight bytes each last \
1958 stalled on; not comparable to retired bytes, but nonzero growth \
1959 indicates backpressure is happening",
1960 )),
1961 retired_bytes: registry.register(metric!(
1962 name: "mz_persist_backpressure_retired_bytes",
1963 help: "bytes retired by processing downstream of backpressure operators",
1964 )),
1965 }
1966 }
1967}
1968
1969#[derive(Debug)]
1971pub struct AlertsMetrics {
1972 pub(crate) blob_failures: IntCounter,
1973 pub(crate) consensus_failures: IntCounter,
1974}
1975
1976impl AlertsMetrics {
1977 fn new(registry: &MetricsRegistry) -> Self {
1978 AlertsMetrics {
1979 blob_failures: registry.register(metric!(
1980 name: "mz_persist_blob_failures",
1981 help: "count of all blob operation failures",
1982 const_labels: {"honeycomb" => "import"},
1983 )),
1984 consensus_failures: registry.register(metric!(
1985 name: "mz_persist_consensus_failures",
1986 help: "count of determinate consensus operation failures",
1987 const_labels: {"honeycomb" => "import"},
1988 )),
1989 }
1990 }
1991}
1992
1993#[derive(Debug)]
1995pub struct PubSubServerMetrics {
1996 pub(crate) active_connections: UIntGauge,
1997 pub(crate) broadcasted_diff_count: IntCounter,
1998 pub(crate) broadcasted_diff_bytes: IntCounter,
1999 pub(crate) broadcasted_diff_dropped_channel_full: IntCounter,
2000
2001 pub(crate) push_seconds: Counter,
2002 pub(crate) subscribe_seconds: Counter,
2003 pub(crate) unsubscribe_seconds: Counter,
2004 pub(crate) connection_cleanup_seconds: Counter,
2005
2006 pub(crate) push_call_count: IntCounter,
2007 pub(crate) subscribe_call_count: IntCounter,
2008 pub(crate) unsubscribe_call_count: IntCounter,
2009}
2010
2011impl PubSubServerMetrics {
2012 pub(crate) fn new(registry: &MetricsRegistry) -> Self {
2013 let op_timings: CounterVec = registry.register(metric!(
2014 name: "mz_persist_pubsub_server_operation_seconds",
2015 help: "time spent in pubsub server performing each operation",
2016 var_labels: ["op"],
2017 ));
2018 let call_count: IntCounterVec = registry.register(metric!(
2019 name: "mz_persist_pubsub_server_call_count",
2020 help: "count of each pubsub server message received",
2021 var_labels: ["call"],
2022 ));
2023
2024 Self {
2025 active_connections: registry.register(metric!(
2026 name: "mz_persist_pubsub_server_active_connections",
2027 help: "number of active connections to server",
2028 )),
2029 broadcasted_diff_count: registry.register(metric!(
2030 name: "mz_persist_pubsub_server_broadcasted_diff_count",
2031 help: "count of total broadcast diff messages sent",
2032 )),
2033 broadcasted_diff_bytes: registry.register(metric!(
2034 name: "mz_persist_pubsub_server_broadcasted_diff_bytes",
2035 help: "count of total broadcast diff bytes sent",
2036 )),
2037 broadcasted_diff_dropped_channel_full: registry.register(metric!(
2038 name: "mz_persist_pubsub_server_broadcasted_diff_dropped_channel_full",
2039 help: "count of diffs dropped due to full connection channel",
2040 )),
2041
2042 push_seconds: op_timings.with_label_values(&["push"]),
2043 subscribe_seconds: op_timings.with_label_values(&["subscribe"]),
2044 unsubscribe_seconds: op_timings.with_label_values(&["unsubscribe"]),
2045 connection_cleanup_seconds: op_timings.with_label_values(&["cleanup"]),
2046
2047 push_call_count: call_count.with_label_values(&["push"]),
2048 subscribe_call_count: call_count.with_label_values(&["subscribe"]),
2049 unsubscribe_call_count: call_count.with_label_values(&["unsubscribe"]),
2050 }
2051 }
2052}
2053
2054#[derive(Debug)]
2056pub struct PubSubClientMetrics {
2057 pub sender: PubSubClientSenderMetrics,
2058 pub receiver: PubSubClientReceiverMetrics,
2059 pub grpc_connection: PubSubGrpcClientConnectionMetrics,
2060}
2061
2062impl PubSubClientMetrics {
2063 fn new(registry: &MetricsRegistry) -> Self {
2064 PubSubClientMetrics {
2065 sender: PubSubClientSenderMetrics::new(registry),
2066 receiver: PubSubClientReceiverMetrics::new(registry),
2067 grpc_connection: PubSubGrpcClientConnectionMetrics::new(registry),
2068 }
2069 }
2070}
2071
2072#[derive(Debug)]
2073pub struct PubSubGrpcClientConnectionMetrics {
2074 pub(crate) connected: UIntGauge,
2075 pub(crate) connection_established_count: IntCounter,
2076 pub(crate) connect_call_attempt_count: IntCounter,
2077 pub(crate) broadcast_recv_lagged_count: IntCounter,
2078 pub(crate) grpc_error_count: IntCounter,
2079}
2080
2081impl PubSubGrpcClientConnectionMetrics {
2082 fn new(registry: &MetricsRegistry) -> Self {
2083 Self {
2084 connected: registry.register(metric!(
2085 name: "mz_persist_pubsub_client_grpc_connected",
2086 help: "whether the grpc client is currently connected",
2087 )),
2088 connection_established_count: registry.register(metric!(
2089 name: "mz_persist_pubsub_client_grpc_connection_established_count",
2090 help: "count of grpc connection establishments to pubsub server",
2091 )),
2092 connect_call_attempt_count: registry.register(metric!(
2093 name: "mz_persist_pubsub_client_grpc_connect_call_attempt_count",
2094 help: "count of connection call attempts (including retries) to pubsub server",
2095 )),
2096 broadcast_recv_lagged_count: registry.register(metric!(
2097 name: "mz_persist_pubsub_client_grpc_broadcast_recv_lagged_count",
2098 help: "times a message was missed by broadcast receiver due to lag",
2099 )),
2100 grpc_error_count: registry.register(metric!(
2101 name: "mz_persist_pubsub_client_grpc_error_count",
2102 help: "count of grpc errors received",
2103 )),
2104 }
2105 }
2106}
2107
2108#[derive(Clone, Debug)]
2109pub struct PubSubClientReceiverMetrics {
2110 pub(crate) push_received: IntCounter,
2111 pub(crate) unknown_message_received: IntCounter,
2112 pub(crate) approx_diff_latency_seconds: Histogram,
2113
2114 pub(crate) state_pushed_diff_fast_path: IntCounter,
2115 pub(crate) state_pushed_diff_slow_path_succeeded: IntCounter,
2116 pub(crate) state_pushed_diff_slow_path_failed: IntCounter,
2117
2118 pub(crate) diff_applied: IntCounter,
2119 pub(crate) diff_not_applied_stale: IntCounter,
2120 pub(crate) diff_not_applied_out_of_order: IntCounter,
2121}
2122
2123impl PubSubClientReceiverMetrics {
2124 fn new(registry: &MetricsRegistry) -> Self {
2125 let call_received: IntCounterVec = registry.register(metric!(
2126 name: "mz_persist_pubsub_client_call_received",
2127 help: "times a pubsub client call was received",
2128 var_labels: ["call"],
2129 ));
2130
2131 Self {
2132 push_received: call_received.with_label_values(&["push"]),
2133 unknown_message_received: call_received.with_label_values(&["unknown"]),
2134 approx_diff_latency_seconds: registry.register(metric!(
2135 name: "mz_persist_pubsub_client_approx_diff_apply_latency_seconds",
2136 help: "histogram of (approximate) latency between sending a diff and applying it",
2137 buckets: prometheus::exponential_buckets(0.001, 2.0, 13).expect("buckets"),
2138 )),
2139
2140 state_pushed_diff_fast_path: registry.register(metric!(
2141 name: "mz_persist_pubsub_client_receiver_state_push_diff_fast_path",
2142 help: "count fast-path state push_diff calls",
2143 )),
2144 state_pushed_diff_slow_path_succeeded: registry.register(metric!(
2145 name: "mz_persist_pubsub_client_receiver_state_push_diff_slow_path_succeeded",
2146 help: "count of successful slow-path state push_diff calls",
2147 )),
2148 state_pushed_diff_slow_path_failed: registry.register(metric!(
2149 name: "mz_persist_pubsub_client_receiver_state_push_diff_slow_path_failed",
2150 help: "count of unsuccessful slow-path state push_diff calls",
2151 )),
2152 diff_applied: registry.register(metric!(
2153 name: "mz_persist_pubsub_client_receiver_diff_applied",
2154 help: "number of diffs received via pubsub that applied",
2155 )),
2156 diff_not_applied_stale: registry.register(metric!(
2157 name: "mz_persist_pubsub_client_receiver_diff_not_applied_stale",
2158 help: "number of diffs received via pubsub that did not apply due to staleness",
2159 )),
2160 diff_not_applied_out_of_order: registry.register(metric!(
2161 name: "mz_persist_pubsub_client_receiver_diff_not_applied_out_of_order",
2162 help: "number of diffs received via pubsub that did not apply due to out-of-order delivery",
2163 )),
2164 }
2165 }
2166}
2167
2168#[derive(Debug)]
2169pub struct PubSubClientSenderMetrics {
2170 pub push: PubSubClientCallMetrics,
2171 pub subscribe: PubSubClientCallMetrics,
2172 pub unsubscribe: PubSubClientCallMetrics,
2173}
2174
2175#[derive(Debug)]
2176pub struct PubSubClientCallMetrics {
2177 pub(crate) succeeded: IntCounter,
2178 pub(crate) bytes_sent: IntCounter,
2179 pub(crate) failed: IntCounter,
2180}
2181
2182impl PubSubClientSenderMetrics {
2183 fn new(registry: &MetricsRegistry) -> Self {
2184 let call_bytes_sent: IntCounterVec = registry.register(metric!(
2185 name: "mz_persist_pubsub_client_call_bytes_sent",
2186 help: "number of bytes sent for a given pubsub client call",
2187 var_labels: ["call"],
2188 ));
2189 let call_succeeded: IntCounterVec = registry.register(metric!(
2190 name: "mz_persist_pubsub_client_call_succeeded",
2191 help: "times a pubsub client call succeeded",
2192 var_labels: ["call"],
2193 ));
2194 let call_failed: IntCounterVec = registry.register(metric!(
2195 name: "mz_persist_pubsub_client_call_failed",
2196 help: "times a pubsub client call failed",
2197 var_labels: ["call"],
2198 ));
2199
2200 Self {
2201 push: PubSubClientCallMetrics {
2202 succeeded: call_succeeded.with_label_values(&["push"]),
2203 failed: call_failed.with_label_values(&["push"]),
2204 bytes_sent: call_bytes_sent.with_label_values(&["push"]),
2205 },
2206 subscribe: PubSubClientCallMetrics {
2207 succeeded: call_succeeded.with_label_values(&["subscribe"]),
2208 failed: call_failed.with_label_values(&["subscribe"]),
2209 bytes_sent: call_bytes_sent.with_label_values(&["subscribe"]),
2210 },
2211 unsubscribe: PubSubClientCallMetrics {
2212 succeeded: call_succeeded.with_label_values(&["unsubscribe"]),
2213 failed: call_failed.with_label_values(&["unsubscribe"]),
2214 bytes_sent: call_bytes_sent.with_label_values(&["unsubscribe"]),
2215 },
2216 }
2217 }
2218}
2219
2220#[derive(Debug)]
2221pub struct LocksMetrics {
2222 pub(crate) applier_read_cacheable: LockMetrics,
2223 pub(crate) applier_read_noncacheable: LockMetrics,
2224 pub(crate) applier_write: LockMetrics,
2225 pub(crate) watch: LockMetrics,
2226}
2227
2228#[derive(Debug, Clone)]
2229pub struct LockMetrics {
2230 pub(crate) acquire_count: IntCounter,
2231 pub(crate) blocking_acquire_count: IntCounter,
2232 pub(crate) blocking_seconds: Counter,
2233}
2234
2235#[derive(Debug)]
2236pub struct WatchMetrics {
2237 pub(crate) wait_woken_via_watch: IntCounter,
2238 pub(crate) wait_woken_via_sleep: IntCounter,
2239 pub(crate) wait_resolved_via_watch: IntCounter,
2240 pub(crate) wait_resolved_via_sleep: IntCounter,
2241 pub(crate) notify_sent: IntCounter,
2242 pub(crate) notify_upper_sent: IntCounter,
2243 pub(crate) notify_noop: IntCounter,
2244 pub(crate) notify_recv: IntCounter,
2245 pub(crate) notify_lagged: IntCounter,
2246 pub(crate) notify_wait_started: IntCounter,
2247 pub(crate) notify_wait_finished: IntCounter,
2248}
2249
2250impl WatchMetrics {
2251 fn new(registry: &MetricsRegistry) -> Self {
2252 WatchMetrics {
2253 wait_woken_via_watch: registry.register(metric!(
2254 name: "mz_persist_wait_woken_via_watch",
2255 help: "count of wait-for-uppers wakes via watch notify",
2256 )),
2257 wait_woken_via_sleep: registry.register(metric!(
2258 name: "mz_persist_wait_woken_via_sleep",
2259 help: "count of wait-for-uppers wakes via sleep",
2260 )),
2261 wait_resolved_via_watch: registry.register(metric!(
2262 name: "mz_persist_wait_resolved_via_watch",
2263 help: "count of wait-for-uppers resolved via watch notify",
2264 )),
2265 wait_resolved_via_sleep: registry.register(metric!(
2266 name: "mz_persist_wait_resolved_via_sleep",
2267 help: "count of wait-for-uppers resolved via sleep",
2268 )),
2269 notify_sent: registry.register(metric!(
2270 name: "mz_persist_watch_notify_sent",
2271 help: "count of watch notifications sent to a non-empty broadcast channel",
2272 )),
2273 notify_upper_sent: registry.register(metric!(
2274 name: "mz_persist_watch_notify_upper_sent",
2275 help: "count of strict shard upper advances signaled to upper waiters",
2276 )),
2277 notify_noop: registry.register(metric!(
2278 name: "mz_persist_watch_notify_noop",
2279 help: "count of watch notifications sent to an broadcast channel",
2280 )),
2281 notify_recv: registry.register(metric!(
2282 name: "mz_persist_watch_notify_recv",
2283 help: "count of watch notifications received from the broadcast channel",
2284 )),
2285 notify_lagged: registry.register(metric!(
2286 name: "mz_persist_watch_notify_lagged",
2287 help: "count of lagged events in the watch notification broadcast channel",
2288 )),
2289 notify_wait_started: registry.register(metric!(
2290 name: "mz_persist_watch_notify_wait_started",
2291 help: "count of watch wait calls started",
2292 )),
2293 notify_wait_finished: registry.register(metric!(
2294 name: "mz_persist_watch_notify_wait_finished",
2295 help: "count of watch wait calls resolved",
2296 )),
2297 }
2298 }
2299}
2300
2301#[derive(Debug)]
2302pub struct PushdownMetrics {
2303 pub(crate) parts_filtered_count: IntCounter,
2304 pub(crate) parts_filtered_bytes: IntCounter,
2305 pub(crate) parts_fetched_count: IntCounter,
2306 pub(crate) parts_fetched_bytes: IntCounter,
2307 pub(crate) parts_audited_count: IntCounter,
2308 pub(crate) parts_audited_bytes: IntCounter,
2309 pub(crate) parts_inline_count: IntCounter,
2310 pub(crate) parts_inline_bytes: IntCounter,
2311 pub(crate) parts_faked_count: IntCounter,
2312 pub(crate) parts_faked_bytes: IntCounter,
2313 pub(crate) parts_stats_trimmed_count: IntCounter,
2314 pub(crate) parts_stats_trimmed_bytes: IntCounter,
2315 pub(crate) parts_projection_trimmed_bytes: IntCounter,
2316 pub part_stats: PartStatsMetrics,
2317}
2318
2319impl PushdownMetrics {
2320 fn new(registry: &MetricsRegistry) -> Self {
2321 PushdownMetrics {
2322 parts_filtered_count: registry.register(metric!(
2323 name: "mz_persist_pushdown_parts_filtered_count",
2324 help: "count of parts filtered by pushdown",
2325 )),
2326 parts_filtered_bytes: registry.register(metric!(
2327 name: "mz_persist_pushdown_parts_filtered_bytes",
2328 help: "total size of parts filtered by pushdown in bytes",
2329 )),
2330 parts_fetched_count: registry.register(metric!(
2331 name: "mz_persist_pushdown_parts_fetched_count",
2332 help: "count of parts not filtered by pushdown",
2333 )),
2334 parts_fetched_bytes: registry.register(metric!(
2335 name: "mz_persist_pushdown_parts_fetched_bytes",
2336 help: "total size of parts not filtered by pushdown in bytes",
2337 )),
2338 parts_audited_count: registry.register(metric!(
2339 name: "mz_persist_pushdown_parts_audited_count",
2340 help: "count of parts fetched only for pushdown audit",
2341 )),
2342 parts_audited_bytes: registry.register(metric!(
2343 name: "mz_persist_pushdown_parts_audited_bytes",
2344 help: "total size of parts fetched only for pushdown audit",
2345 )),
2346 parts_inline_count: registry.register(metric!(
2347 name: "mz_persist_pushdown_parts_inline_count",
2348 help: "count of parts not fetched because they were inline",
2349 )),
2350 parts_inline_bytes: registry.register(metric!(
2351 name: "mz_persist_pushdown_parts_inline_bytes",
2352 help: "total size of parts not fetched because they were inline",
2353 )),
2354 parts_faked_count: registry.register(metric!(
2355 name: "mz_persist_pushdown_parts_faked_count",
2356 help: "count of parts faked because of aggressive projection pushdown",
2357 )),
2358 parts_faked_bytes: registry.register(metric!(
2359 name: "mz_persist_pushdown_parts_faked_bytes",
2360 help: "total size of parts replaced with fakes by aggressive projection pushdown",
2361 )),
2362 parts_stats_trimmed_count: registry.register(metric!(
2363 name: "mz_persist_pushdown_parts_stats_trimmed_count",
2364 help: "count of trimmed part stats",
2365 )),
2366 parts_stats_trimmed_bytes: registry.register(metric!(
2367 name: "mz_persist_pushdown_parts_stats_trimmed_bytes",
2368 help: "total bytes trimmed from part stats",
2369 )),
2370 parts_projection_trimmed_bytes: registry.register(metric!(
2371 name: "mz_persist_pushdown_parts_projection_trimmed_bytes",
2372 help: "total bytes trimmed from columnar data because of projection pushdown",
2373 )),
2374 part_stats: PartStatsMetrics::new(registry),
2375 }
2376 }
2377}
2378
2379#[derive(Debug)]
2380pub struct ConsolidationMetrics {
2381 pub(crate) parts_fetched: IntCounter,
2382 pub(crate) parts_skipped: IntCounter,
2383 pub(crate) parts_wasted: IntCounter,
2384 pub(crate) wrong_sort: IntCounter,
2385}
2386
2387impl ConsolidationMetrics {
2388 fn new(registry: &MetricsRegistry) -> Self {
2389 ConsolidationMetrics {
2390 parts_fetched: registry.register(metric!(
2391 name: "mz_persist_consolidation_parts_fetched_count",
2392 help: "count of parts that were fetched and used during consolidation",
2393 )),
2394 parts_skipped: registry.register(metric!(
2395 name: "mz_persist_consolidation_parts_skipped_count",
2396 help: "count of parts that were never needed during consolidation",
2397 )),
2398 parts_wasted: registry.register(metric!(
2399 name: "mz_persist_consolidation_parts_wasted_count",
2400 help: "count of parts that were fetched but not needed during consolidation",
2401 )),
2402 wrong_sort: registry.register(metric!(
2403 name: "mz_persist_consolidation_wrong_sort_count",
2404 help: "count of runs that were sorted using the wrong ordering for the current consolidation",
2405 )),
2406 }
2407 }
2408}
2409
2410#[derive(Debug)]
2411pub struct BlobMemCache {
2412 pub(crate) size_blobs: UIntGauge,
2413 pub(crate) size_bytes: UIntGauge,
2414 pub(crate) hits_blobs: IntCounter,
2415 pub(crate) hits_bytes: IntCounter,
2416 pub(crate) evictions: IntCounter,
2417}
2418
2419impl BlobMemCache {
2420 fn new(registry: &MetricsRegistry) -> Self {
2421 BlobMemCache {
2422 size_blobs: registry.register(metric!(
2423 name: "mz_persist_blob_cache_size_blobs",
2424 help: "count of blobs in the cache",
2425 const_labels: {"cache" => "mem"},
2426 )),
2427 size_bytes: registry.register(metric!(
2428 name: "mz_persist_blob_cache_size_bytes",
2429 help: "total size of blobs in the cache",
2430 const_labels: {"cache" => "mem"},
2431 )),
2432 hits_blobs: registry.register(metric!(
2433 name: "mz_persist_blob_cache_hits_blobs",
2434 help: "count of blobs served via cache instead of s3",
2435 const_labels: {"cache" => "mem"},
2436 )),
2437 hits_bytes: registry.register(metric!(
2438 name: "mz_persist_blob_cache_hits_bytes",
2439 help: "total size of blobs served via cache instead of s3",
2440 const_labels: {"cache" => "mem"},
2441 )),
2442 evictions: registry.register(metric!(
2443 name: "mz_persist_blob_cache_evictions",
2444 help: "count of capacity-based cache evictions",
2445 const_labels: {"cache" => "mem"},
2446 )),
2447 }
2448 }
2449}
2450
2451#[derive(Debug)]
2452pub struct SemaphoreMetrics {
2453 cfg: PersistConfig,
2454 registry: MetricsRegistry,
2455 fetch: OnceCell<MetricsSemaphore>,
2456}
2457
2458impl SemaphoreMetrics {
2459 fn new(cfg: PersistConfig, registry: MetricsRegistry) -> Self {
2460 SemaphoreMetrics {
2461 cfg,
2462 registry,
2463 fetch: OnceCell::new(),
2464 }
2465 }
2466
2467 async fn fetch(&self) -> &MetricsSemaphore {
2471 if let Some(x) = self.fetch.get() {
2472 return x;
2474 }
2475 let cfg = self.cfg.clone();
2476 let registry = self.registry.clone();
2477 let init = async move {
2478 let total_permits = match cfg.announce_memory_limit {
2479 Some(mem) if cfg.is_cc_active => {
2482 info!("fetch semaphore awaiting first dyncfg values");
2485 let () = cfg.configs_synced_once().await;
2486 let total_permits = usize::cast_lossy(
2487 f64::cast_lossy(mem) * FETCH_SEMAPHORE_PERMIT_ADJUSTMENT.get(&cfg),
2488 );
2489 info!("fetch_semaphore got first dyncfg values");
2490 total_permits
2491 }
2492 Some(_) | None => Semaphore::MAX_PERMITS,
2493 };
2494 MetricsSemaphore::new(®istry, "fetch", total_permits)
2495 };
2496 self.fetch.get_or_init(|| init).await
2497 }
2498
2499 pub(crate) async fn acquire_fetch_permits(&self, encoded_size_bytes: usize) -> MetricsPermits {
2500 let requested_permits = f64::cast_lossy(encoded_size_bytes);
2503 let requested_permits = requested_permits * FETCH_SEMAPHORE_COST_ADJUSTMENT.get(&self.cfg);
2504 let requested_permits = usize::cast_lossy(requested_permits);
2505 self.fetch().await.acquire_permits(requested_permits).await
2506 }
2507}
2508
2509#[derive(Debug)]
2510pub struct MetricsSemaphore {
2511 name: &'static str,
2512 semaphore: Arc<Semaphore>,
2513 total_permits: usize,
2514 acquire_count: IntCounter,
2515 blocking_count: IntCounter,
2516 blocking_seconds: Counter,
2517 acquired_permits: IntCounter,
2518 released_permits: IntCounter,
2519 _available_permits: ComputedUIntGauge,
2520}
2521
2522impl MetricsSemaphore {
2523 pub fn new(registry: &MetricsRegistry, name: &'static str, total_permits: usize) -> Self {
2524 let total_permits = std::cmp::min(total_permits, Semaphore::MAX_PERMITS);
2525 let semaphore = Arc::new(Semaphore::new(total_permits));
2528 MetricsSemaphore {
2529 name,
2530 total_permits,
2531 acquire_count: registry.register(metric!(
2532 name: "mz_persist_semaphore_acquire_count",
2533 help: "count of acquire calls (not acquired permits count)",
2534 const_labels: {"name" => name},
2535 )),
2536 blocking_count: registry.register(metric!(
2537 name: "mz_persist_semaphore_blocking_count",
2538 help: "count of acquire calls that had to block",
2539 const_labels: {"name" => name},
2540 )),
2541 blocking_seconds: registry.register(metric!(
2542 name: "mz_persist_semaphore_blocking_seconds",
2543 help: "total time spent blocking on permit acquisition",
2544 const_labels: {"name" => name},
2545 )),
2546 acquired_permits: registry.register(metric!(
2547 name: "mz_persist_semaphore_acquired_permits",
2548 help: "total sum of acquired permits",
2549 const_labels: {"name" => name},
2550 )),
2551 released_permits: registry.register(metric!(
2552 name: "mz_persist_semaphore_released_permits",
2553 help: "total sum of released permits",
2554 const_labels: {"name" => name},
2555 )),
2556 _available_permits: registry.register_computed_gauge(
2557 metric!(
2558 name: "mz_persist_semaphore_available_permits",
2559 help: "currently available permits according to the semaphore",
2560 ),
2561 {
2562 let semaphore = Arc::clone(&semaphore);
2563 move || u64::cast_from(semaphore.available_permits())
2564 },
2565 ),
2566 semaphore,
2567 }
2568 }
2569
2570 pub async fn acquire_permits(&self, requested_permits: usize) -> MetricsPermits {
2571 let total_permits = u32::try_from(self.total_permits).unwrap_or(u32::MAX);
2574 let requested_permits = u32::try_from(requested_permits).unwrap_or(u32::MAX);
2575 let requested_permits = std::cmp::min(requested_permits, total_permits);
2576 let wrap = |_permit| {
2577 self.acquired_permits.inc_by(u64::from(requested_permits));
2578 MetricsPermits {
2579 _permit,
2580 released_metric: self.released_permits.clone(),
2581 count: requested_permits,
2582 }
2583 };
2584
2585 self.acquire_count.inc();
2587 match Arc::clone(&self.semaphore).try_acquire_many_owned(requested_permits) {
2588 Ok(x) => return wrap(x),
2589 Err(_) => {}
2590 };
2591
2592 self.blocking_count.inc();
2594 let start = Instant::now();
2595 let ret = Arc::clone(&self.semaphore)
2596 .acquire_many_owned(requested_permits)
2597 .instrument(info_span!("acquire_permits"))
2598 .await;
2599 let elapsed = start.elapsed();
2600 self.blocking_seconds.inc_by(elapsed.as_secs_f64());
2601 debug!(
2602 "acquisition of {} {} permits blocked for {:?}",
2603 self.name, requested_permits, elapsed
2604 );
2605 wrap(ret.expect("semaphore is never closed"))
2606 }
2607}
2608
2609#[derive(Debug)]
2610pub struct MetricsPermits {
2611 _permit: OwnedSemaphorePermit,
2612 released_metric: IntCounter,
2613 count: u32,
2614}
2615
2616impl Drop for MetricsPermits {
2617 fn drop(&mut self) {
2618 self.released_metric.inc_by(u64::from(self.count))
2619 }
2620}
2621
2622#[derive(Debug)]
2623pub struct ExternalOpMetrics {
2624 started: IntCounter,
2625 succeeded: IntCounter,
2626 failed: IntCounter,
2627 bytes: IntCounter,
2628 seconds: Counter,
2629 seconds_histogram: Option<Histogram>,
2630 alerts_metrics: Arc<AlertsMetrics>,
2631}
2632
2633impl ExternalOpMetrics {
2634 async fn run_op<R, F, OpFn, ErrFn>(
2635 &self,
2636 op_fn: OpFn,
2637 on_err_fn: ErrFn,
2638 ) -> Result<R, ExternalError>
2639 where
2640 F: std::future::Future<Output = Result<R, ExternalError>>,
2641 OpFn: FnOnce() -> F,
2642 ErrFn: FnOnce(&AlertsMetrics, &ExternalError),
2643 {
2644 self.started.inc();
2645 let start = Instant::now();
2646 let res = op_fn().await;
2647 let elapsed_seconds = start.elapsed().as_secs_f64();
2648 self.seconds.inc_by(elapsed_seconds);
2649 if let Some(h) = &self.seconds_histogram {
2650 h.observe(elapsed_seconds);
2651 }
2652 match res.as_ref() {
2653 Ok(_) => self.succeeded.inc(),
2654 Err(err) => {
2655 self.failed.inc();
2656 on_err_fn(&self.alerts_metrics, err);
2657 }
2658 };
2659 res
2660 }
2661
2662 fn run_stream<'a, R: 'a, S, OpFn, ErrFn>(
2663 &'a self,
2664 op_fn: OpFn,
2665 mut on_err_fn: ErrFn,
2666 ) -> impl futures::Stream<Item = Result<R, ExternalError>> + 'a
2667 where
2668 S: futures::Stream<Item = Result<R, ExternalError>> + Unpin + 'a,
2669 OpFn: FnOnce() -> S,
2670 ErrFn: FnMut(&AlertsMetrics, &ExternalError) + 'a,
2671 {
2672 self.started.inc();
2673 let start = Instant::now();
2674 let mut stream = op_fn();
2675 stream! {
2676 let mut succeeded = true;
2677 while let Some(res) = stream.next().await {
2678 if let Err(err) = res.as_ref() {
2679 on_err_fn(&self.alerts_metrics, err);
2680 succeeded = false;
2681 }
2682 yield res;
2683 }
2684 if succeeded {
2685 self.succeeded.inc()
2686 } else {
2687 self.failed.inc()
2688 }
2689 let elapsed_seconds = start.elapsed().as_secs_f64();
2690 self.seconds.inc_by(elapsed_seconds);
2691 if let Some(h) = &self.seconds_histogram {
2692 h.observe(elapsed_seconds);
2693 }
2694 }
2695 }
2696}
2697
2698#[derive(Debug)]
2699pub struct BlobMetrics {
2700 set: ExternalOpMetrics,
2701 get: ExternalOpMetrics,
2702 list_keys: ExternalOpMetrics,
2703 delete: ExternalOpMetrics,
2704 restore: ExternalOpMetrics,
2705 delete_noop: IntCounter,
2706 blob_sizes: Histogram,
2707 pub rtt_latency: Gauge,
2708}
2709
2710#[derive(Debug)]
2711pub struct MetricsBlob {
2712 blob: Arc<dyn Blob>,
2713 metrics: Arc<Metrics>,
2714}
2715
2716impl MetricsBlob {
2717 pub fn new(blob: Arc<dyn Blob>, metrics: Arc<Metrics>) -> Self {
2718 MetricsBlob { blob, metrics }
2719 }
2720
2721 fn on_err(alerts_metrics: &AlertsMetrics, _err: &ExternalError) {
2722 alerts_metrics.blob_failures.inc()
2723 }
2724}
2725
2726#[async_trait]
2727impl Blob for MetricsBlob {
2728 #[instrument(name = "blob::get", fields(shard=blob_key_shard_id(key)))]
2729 async fn get(&self, key: &str) -> Result<Option<SegmentedBytes>, ExternalError> {
2730 let res = self
2731 .metrics
2732 .blob
2733 .get
2734 .run_op(|| self.blob.get(key), Self::on_err)
2735 .await;
2736 if let Ok(Some(value)) = res.as_ref() {
2737 self.metrics
2738 .blob
2739 .get
2740 .bytes
2741 .inc_by(u64::cast_from(value.len()));
2742 }
2743 res
2744 }
2745
2746 #[instrument(name = "blob::list_keys_and_metadata", fields(shard=blob_key_shard_id(key_prefix)))]
2747 async fn list_keys_and_metadata(
2748 &self,
2749 key_prefix: &str,
2750 f: &mut (dyn FnMut(BlobMetadata) + Send + Sync),
2751 ) -> Result<(), ExternalError> {
2752 let mut byte_total = 0;
2753 let mut instrumented = |blob_metadata: BlobMetadata| {
2754 byte_total += blob_metadata.key.len();
2757 f(blob_metadata)
2758 };
2759
2760 let res = self
2761 .metrics
2762 .blob
2763 .list_keys
2764 .run_op(
2765 || {
2766 self.blob
2767 .list_keys_and_metadata(key_prefix, &mut instrumented)
2768 },
2769 Self::on_err,
2770 )
2771 .await;
2772
2773 self.metrics
2774 .blob
2775 .list_keys
2776 .bytes
2777 .inc_by(u64::cast_from(byte_total));
2778
2779 res
2780 }
2781
2782 #[instrument(name = "blob::set", fields(shard=blob_key_shard_id(key),size_bytes=value.len()))]
2783 async fn set(&self, key: &str, value: Bytes) -> Result<(), ExternalError> {
2784 let bytes = value.len();
2785 let res = self
2786 .metrics
2787 .blob
2788 .set
2789 .run_op(|| self.blob.set(key, value), Self::on_err)
2790 .await;
2791 if res.is_ok() {
2792 self.metrics.blob.set.bytes.inc_by(u64::cast_from(bytes));
2793 self.metrics.blob.blob_sizes.observe(f64::cast_lossy(bytes));
2794 }
2795 res
2796 }
2797
2798 #[instrument(name = "blob::delete", fields(shard=blob_key_shard_id(key)))]
2799 async fn delete(&self, key: &str) -> Result<Option<usize>, ExternalError> {
2800 let bytes = self
2801 .metrics
2802 .blob
2803 .delete
2804 .run_op(|| self.blob.delete(key), Self::on_err)
2805 .await?;
2806 if let Some(bytes) = bytes {
2807 self.metrics.blob.delete.bytes.inc_by(u64::cast_from(bytes));
2808 } else {
2809 self.metrics.blob.delete_noop.inc();
2810 }
2811 Ok(bytes)
2812 }
2813
2814 async fn restore(&self, key: &str) -> Result<(), ExternalError> {
2815 self.metrics
2816 .blob
2817 .restore
2818 .run_op(|| self.blob.restore(key), Self::on_err)
2819 .await
2820 }
2821}
2822
2823#[derive(Debug)]
2824pub struct ConsensusMetrics {
2825 list_keys: ExternalOpMetrics,
2826 head: ExternalOpMetrics,
2827 compare_and_set: ExternalOpMetrics,
2828 scan: ExternalOpMetrics,
2829 truncate: ExternalOpMetrics,
2830 truncated_count: IntCounter,
2831 pub rtt_latency: Gauge,
2832}
2833
2834#[derive(Debug)]
2835pub struct MetricsConsensus {
2836 consensus: Arc<dyn Consensus>,
2837 metrics: Arc<Metrics>,
2838}
2839
2840impl MetricsConsensus {
2841 pub fn new(consensus: Arc<dyn Consensus>, metrics: Arc<Metrics>) -> Self {
2842 MetricsConsensus { consensus, metrics }
2843 }
2844
2845 fn on_err(alerts_metrics: &AlertsMetrics, err: &ExternalError) {
2846 if let ExternalError::Indeterminate(_) = err {
2850 alerts_metrics.consensus_failures.inc()
2851 }
2852 }
2853}
2854
2855#[async_trait]
2856impl Consensus for MetricsConsensus {
2857 fn list_keys(&self) -> ResultStream<'_, String> {
2858 Box::pin(
2859 self.metrics
2860 .consensus
2861 .list_keys
2862 .run_stream(|| self.consensus.list_keys(), Self::on_err),
2863 )
2864 }
2865
2866 #[instrument(name = "consensus::head", fields(shard=key))]
2867 async fn head(&self, key: &str) -> Result<Option<VersionedData>, ExternalError> {
2868 let res = self
2869 .metrics
2870 .consensus
2871 .head
2872 .run_op(|| self.consensus.head(key), Self::on_err)
2873 .await;
2874 if let Ok(Some(data)) = res.as_ref() {
2875 self.metrics
2876 .consensus
2877 .head
2878 .bytes
2879 .inc_by(u64::cast_from(data.data.len()));
2880 }
2881 res
2882 }
2883
2884 #[instrument(name = "consensus::compare_and_set", fields(shard=key,size_bytes=new.data.len()))]
2885 async fn compare_and_set(
2886 &self,
2887 key: &str,
2888 new: VersionedData,
2889 ) -> Result<CaSResult, ExternalError> {
2890 let bytes = new.data.len();
2891 let res = self
2892 .metrics
2893 .consensus
2894 .compare_and_set
2895 .run_op(|| self.consensus.compare_and_set(key, new), Self::on_err)
2896 .await;
2897 match res.as_ref() {
2898 Ok(CaSResult::Committed) => self
2899 .metrics
2900 .consensus
2901 .compare_and_set
2902 .bytes
2903 .inc_by(u64::cast_from(bytes)),
2904 Ok(CaSResult::ExpectationMismatch) | Err(_) => {}
2905 }
2906 res
2907 }
2908
2909 #[instrument(name = "consensus::scan", fields(shard=key))]
2910 async fn scan(
2911 &self,
2912 key: &str,
2913 from: SeqNo,
2914 limit: usize,
2915 ) -> Result<Vec<VersionedData>, ExternalError> {
2916 let res = self
2917 .metrics
2918 .consensus
2919 .scan
2920 .run_op(|| self.consensus.scan(key, from, limit), Self::on_err)
2921 .await;
2922 if let Ok(dataz) = res.as_ref() {
2923 let bytes: usize = dataz.iter().map(|x| x.data.len()).sum();
2924 self.metrics
2925 .consensus
2926 .scan
2927 .bytes
2928 .inc_by(u64::cast_from(bytes));
2929 }
2930 res
2931 }
2932
2933 #[instrument(name = "consensus::truncate", fields(shard=key))]
2934 async fn truncate(&self, key: &str, seqno: SeqNo) -> Result<Option<usize>, ExternalError> {
2935 let metrics = &self.metrics.consensus;
2936 let deleted = metrics
2937 .truncate
2938 .run_op(|| self.consensus.truncate(key, seqno), Self::on_err)
2939 .await?;
2940 if let Some(deleted) = deleted {
2941 metrics.truncated_count.inc_by(u64::cast_from(deleted));
2942 }
2943 Ok(deleted)
2944 }
2945}
2946
2947#[derive(Debug, Clone)]
2950pub struct TaskMetrics {
2951 f64_gauges: Vec<(Gauge, fn(&tokio_metrics::TaskMetrics) -> f64)>,
2952 u64_gauges: Vec<(
2953 GenericGauge<AtomicU64>,
2954 fn(&tokio_metrics::TaskMetrics) -> u64,
2955 )>,
2956 monitor: TaskMonitor,
2957}
2958
2959impl TaskMetrics {
2960 pub fn new(name: &str) -> Self {
2961 let monitor = TaskMonitor::new();
2962 Self {
2963 f64_gauges: vec![
2964 (
2965 Gauge::make_collector(metric!(
2966 name: "mz_persist_task_total_idle_duration",
2967 help: "Seconds of time spent idling, ie. waiting for a task to be woken up.",
2968 const_labels: {"name" => name}
2969 )),
2970 |m| m.total_idle_duration.as_secs_f64(),
2971 ),
2972 (
2973 Gauge::make_collector(metric!(
2974 name: "mz_persist_task_total_scheduled_duration",
2975 help: "Seconds of time spent scheduled, ie. ready to poll but not yet polled.",
2976 const_labels: {"name" => name}
2977 )),
2978 |m| m.total_scheduled_duration.as_secs_f64(),
2979 ),
2980 ],
2981 u64_gauges: vec![
2982 (
2983 MakeCollector::make_collector(metric!(
2984 name: "mz_persist_task_total_scheduled_count",
2985 help: "The total number of task schedules. Useful for computing the average scheduled time.",
2986 const_labels: {"name" => name}
2987 )),
2988 |m| m.total_scheduled_count,
2989 ),
2990 (
2991 MakeCollector::make_collector(metric!(
2992 name: "mz_persist_task_total_idled_count",
2993 help: "The total number of task idles. Useful for computing the average idle time.",
2994 const_labels: {"name" => name}
2995 ,
2996 )),
2997 |m| m.total_idled_count,
2998 ),
2999 ],
3000 monitor,
3001 }
3002 }
3003
3004 pub fn instrument_task<F>(&self, task: F) -> tokio_metrics::Instrumented<F> {
3007 TaskMonitor::instrument(&self.monitor, task)
3008 }
3009}
3010
3011impl Collector for TaskMetrics {
3012 fn desc(&self) -> Vec<&Desc> {
3013 let mut descs = Vec::with_capacity(self.f64_gauges.len() + self.u64_gauges.len());
3014 for (g, _) in &self.f64_gauges {
3015 descs.extend(g.desc());
3016 }
3017 for (g, _) in &self.u64_gauges {
3018 descs.extend(g.desc());
3019 }
3020 descs
3021 }
3022
3023 fn collect(&self) -> Vec<MetricFamily> {
3024 let mut families = Vec::with_capacity(self.f64_gauges.len() + self.u64_gauges.len());
3025 let metrics = self.monitor.cumulative();
3026 for (g, metrics_fn) in &self.f64_gauges {
3027 g.set(metrics_fn(&metrics));
3028 families.extend(g.collect());
3029 }
3030 for (g, metrics_fn) in &self.u64_gauges {
3031 g.set(metrics_fn(&metrics));
3032 families.extend(g.collect());
3033 }
3034 families
3035 }
3036}
3037
3038#[derive(Debug)]
3039pub struct TasksMetrics {
3040 pub heartbeat_read: TaskMetrics,
3041}
3042
3043impl TasksMetrics {
3044 fn new(registry: &MetricsRegistry) -> Self {
3045 let heartbeat_read = TaskMetrics::new("heartbeat_read");
3046 registry.register_collector(heartbeat_read.clone());
3047 TasksMetrics { heartbeat_read }
3048 }
3049}
3050
3051#[derive(Debug)]
3052pub struct SchemaMetrics {
3053 pub(crate) cache_fetch_state_count: IntCounter,
3054 pub(crate) cache_schema: SchemaCacheMetrics,
3055 pub(crate) cache_migration: SchemaCacheMetrics,
3056 pub(crate) migration_count_same: IntCounter,
3057 pub(crate) migration_count_codec: IntCounter,
3058 pub(crate) migration_count_either: IntCounter,
3059 pub(crate) migration_len_legacy_codec: IntCounter,
3060 pub(crate) migration_len_either_codec: IntCounter,
3061 pub(crate) migration_len_either_arrow: IntCounter,
3062 pub(crate) migration_new_count: IntCounter,
3063 pub(crate) migration_new_seconds: Counter,
3064 pub(crate) migration_migrate_seconds: Counter,
3065}
3066
3067impl SchemaMetrics {
3068 fn new(registry: &MetricsRegistry) -> Self {
3069 let cached: IntCounterVec = registry.register(metric!(
3070 name: "mz_persist_schema_cache_cached_count",
3071 help: "count of schema cache entries served from cache",
3072 var_labels: ["op"],
3073 ));
3074 let computed: IntCounterVec = registry.register(metric!(
3075 name: "mz_persist_schema_cache_computed_count",
3076 help: "count of schema cache entries computed",
3077 var_labels: ["op"],
3078 ));
3079 let unavailable: IntCounterVec = registry.register(metric!(
3080 name: "mz_persist_schema_cache_unavailable_count",
3081 help: "count of schema cache entries unavailable at current state",
3082 var_labels: ["op"],
3083 ));
3084 let added: IntCounterVec = registry.register(metric!(
3085 name: "mz_persist_schema_cache_added_count",
3086 help: "count of schema cache entries added",
3087 var_labels: ["op"],
3088 ));
3089 let dropped: IntCounterVec = registry.register(metric!(
3090 name: "mz_persist_schema_cache_dropped_count",
3091 help: "count of schema cache entries dropped",
3092 var_labels: ["op"],
3093 ));
3094 let cache = |name| SchemaCacheMetrics {
3095 cached_count: cached.with_label_values(&[name]),
3096 computed_count: computed.with_label_values(&[name]),
3097 unavailable_count: unavailable.with_label_values(&[name]),
3098 added_count: added.with_label_values(&[name]),
3099 dropped_count: dropped.with_label_values(&[name]),
3100 };
3101 let migration_count: IntCounterVec = registry.register(metric!(
3102 name: "mz_persist_schema_migration_count",
3103 help: "count of fetch part migrations",
3104 var_labels: ["op"],
3105 ));
3106 let migration_len: IntCounterVec = registry.register(metric!(
3107 name: "mz_persist_schema_migration_len",
3108 help: "count of migrated update records",
3109 var_labels: ["op"],
3110 ));
3111 SchemaMetrics {
3112 cache_fetch_state_count: registry.register(metric!(
3113 name: "mz_persist_schema_cache_fetch_state_count",
3114 help: "count of state fetches by the schema cache",
3115 )),
3116 cache_schema: cache("schema"),
3117 cache_migration: cache("migration"),
3118 migration_count_same: migration_count.with_label_values(&["same"]),
3119 migration_count_codec: migration_count.with_label_values(&["codec"]),
3120 migration_count_either: migration_count.with_label_values(&["either"]),
3121 migration_len_legacy_codec: migration_len.with_label_values(&["legacy_codec"]),
3122 migration_len_either_codec: migration_len.with_label_values(&["either_codec"]),
3123 migration_len_either_arrow: migration_len.with_label_values(&["either_arrow"]),
3124 migration_new_count: registry.register(metric!(
3125 name: "mz_persist_schema_migration_new_count",
3126 help: "count of migrations constructed",
3127 )),
3128 migration_new_seconds: registry.register(metric!(
3129 name: "mz_persist_schema_migration_new_seconds",
3130 help: "seconds spent constructing migration logic",
3131 )),
3132 migration_migrate_seconds: registry.register(metric!(
3133 name: "mz_persist_schema_migration_migrate_seconds",
3134 help: "seconds spent applying migration logic",
3135 )),
3136 }
3137 }
3138}
3139
3140#[derive(Debug, Clone)]
3141pub struct SchemaCacheMetrics {
3142 pub(crate) cached_count: IntCounter,
3143 pub(crate) computed_count: IntCounter,
3144 pub(crate) unavailable_count: IntCounter,
3145 pub(crate) added_count: IntCounter,
3146 pub(crate) dropped_count: IntCounter,
3147}
3148
3149#[derive(Debug)]
3150pub struct InlineMetrics {
3151 pub(crate) part_commit_count: IntCounter,
3152 pub(crate) part_commit_bytes: IntCounter,
3153 pub(crate) backpressure: BatchWriteMetrics,
3154}
3155
3156impl InlineMetrics {
3157 fn new(registry: &MetricsRegistry) -> Self {
3158 InlineMetrics {
3159 part_commit_count: registry.register(metric!(
3160 name: "mz_persist_inline_part_commit_count",
3161 help: "count of inline parts committed to state",
3162 )),
3163 part_commit_bytes: registry.register(metric!(
3164 name: "mz_persist_inline_part_commit_bytes",
3165 help: "total size of of inline parts committed to state",
3166 )),
3167 backpressure: BatchWriteMetrics::new(registry, "inline_backpressure"),
3168 }
3169 }
3170}
3171
3172fn blob_key_shard_id(key: &str) -> Option<String> {
3173 let (shard_id, _) = BlobKey::parse_ids(key).ok()?;
3174 Some(shard_id.to_string())
3175}
3176
3177pub fn encode_ts_metric<T: Codec64>(ts: &Antichain<T>) -> i64 {
3179 match ts.elements().first() {
3189 Some(ts) => i64::from_le_bytes(Codec64::encode(ts)),
3190 None => i64::MAX,
3191 }
3192}
3193
3194#[cfg(test)]
3195mod tests {
3196 use super::*;
3197
3198 #[mz_ore::test]
3199 fn shards_aggregate_metrics_one_pass() {
3200 let registry = MetricsRegistry::new();
3201 let shards = ShardsMetrics::new(®istry);
3202 let agg = ShardsAggregateMetrics::new(Arc::clone(&shards.shards));
3203 let a = shards.shard(&ShardId::new(), "a");
3204 let b = shards.shard(&ShardId::new(), "b");
3205
3206 agg.collect();
3208 assert_eq!(agg.count.get(), 2);
3209 assert_eq!(agg.stale_count.get(), 0);
3210
3211 a.stale.store(true, Ordering::Relaxed);
3212 agg.collect();
3213 assert_eq!(agg.count.get(), 2);
3214 assert_eq!(agg.stale_count.get(), 1);
3215
3216 b.stale.store(true, Ordering::Relaxed);
3217 agg.collect();
3218 assert_eq!(agg.stale_count.get(), 2);
3219
3220 a.stale.store(false, Ordering::Relaxed);
3223 drop(b);
3224 agg.collect();
3225 assert_eq!(agg.count.get(), 1);
3226 assert_eq!(agg.stale_count.get(), 0);
3227 }
3228}