Skip to main content

reth_provider/providers/rocksdb/
metrics.rs

1use std::{collections::HashMap, time::Duration};
2
3use itertools::Itertools;
4use metrics::{Counter, Histogram};
5use reth_db::Tables;
6use reth_metrics::Metrics;
7use strum::{EnumIter, IntoEnumIterator};
8
9pub(super) const ROCKSDB_TABLES: &[&str] = &[
10    Tables::TransactionHashNumbers.name(),
11    Tables::BlockAccessLists.name(),
12    Tables::BlockAccessListBlockNumbers.name(),
13    Tables::StoragesHistory.name(),
14    Tables::AccountsHistory.name(),
15];
16
17/// Metrics for the `RocksDB` provider.
18#[derive(Debug)]
19pub(crate) struct RocksDBMetrics {
20    operations: HashMap<(&'static str, RocksDBOperation), RocksDBOperationMetrics>,
21}
22
23impl Default for RocksDBMetrics {
24    fn default() -> Self {
25        let mut operations = ROCKSDB_TABLES
26            .iter()
27            .copied()
28            .cartesian_product(RocksDBOperation::iter())
29            .map(|(table, operation)| {
30                (
31                    (table, operation),
32                    RocksDBOperationMetrics::new_with_labels(&[
33                        ("table", table),
34                        ("operation", operation.as_str()),
35                    ]),
36                )
37            })
38            .collect::<HashMap<_, _>>();
39
40        // Add special "Batch" entry for batch write operations
41        operations.insert(
42            ("Batch", RocksDBOperation::BatchWrite),
43            RocksDBOperationMetrics::new_with_labels(&[
44                ("table", "Batch"),
45                ("operation", RocksDBOperation::BatchWrite.as_str()),
46            ]),
47        );
48
49        Self { operations }
50    }
51}
52
53impl RocksDBMetrics {
54    /// Records operation metrics with the given operation label and table name.
55    pub(crate) fn record_operation(
56        &self,
57        operation: RocksDBOperation,
58        table: &'static str,
59        duration: Duration,
60    ) {
61        let metrics =
62            self.operations.get(&(table, operation)).expect("operation metrics should exist");
63
64        metrics.calls_total.increment(1);
65        metrics.duration_seconds.record(duration.as_secs_f64());
66    }
67}
68
69/// `RocksDB` operations that are tracked
70#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EnumIter)]
71pub(crate) enum RocksDBOperation {
72    Get,
73    Put,
74    Delete,
75    BatchWrite,
76}
77
78impl RocksDBOperation {
79    const fn as_str(&self) -> &'static str {
80        match self {
81            Self::Get => "get",
82            Self::Put => "put",
83            Self::Delete => "delete",
84            Self::BatchWrite => "batch-write",
85        }
86    }
87}
88
89/// Metrics for a specific `RocksDB` operation on a table
90#[derive(Metrics, Clone)]
91#[metrics(scope = "rocksdb.provider")]
92pub(crate) struct RocksDBOperationMetrics {
93    /// Total number of calls
94    calls_total: Counter,
95    /// Duration of operations
96    duration_seconds: Histogram,
97}