perf(db): pre-populate metric handles hashmap on env init (#6573)

This commit is contained in:
Seva Zhidkov
2024-02-13 01:59:52 +00:00
committed by GitHub
parent d4cf706ed2
commit 0e166f0f32
3 changed files with 27 additions and 19 deletions

1
Cargo.lock generated
View File

@ -5946,7 +5946,6 @@ dependencies = [
"assert_matches",
"bytes",
"criterion",
"dashmap",
"derive_more",
"eyre",
"iai",

View File

@ -38,7 +38,6 @@ parking_lot.workspace = true
derive_more.workspace = true
eyre.workspace = true
paste = "1.0"
dashmap = "5.5.3"
rustc-hash = "1.1.0"
# arbitrary utils

View File

@ -1,14 +1,14 @@
use crate::Tables;
use dashmap::DashMap;
use metrics::{Gauge, Histogram};
use reth_libmdbx::CommitLatency;
use reth_metrics::{metrics::Counter, Metrics};
use rustc_hash::FxHasher;
use std::{
collections::HashMap,
hash::BuildHasherDefault,
time::{Duration, Instant},
};
use strum::EnumCount;
use strum::{EnumCount, EnumIter, IntoEnumIterator};
const LARGE_VALUE_THRESHOLD_BYTES: usize = 4096;
@ -17,20 +17,33 @@ const LARGE_VALUE_THRESHOLD_BYTES: usize = 4096;
#[derive(Debug)]
pub struct DatabaseEnvMetrics {
/// Caches OperationMetrics handles for each table and operation tuple.
operations: DashMap<(Tables, Operation), OperationMetrics, BuildHasherDefault<FxHasher>>,
operations: HashMap<(Tables, Operation), OperationMetrics, BuildHasherDefault<FxHasher>>,
}
impl DatabaseEnvMetrics {
pub(crate) fn new() -> Self {
Self {
operations: DashMap::with_capacity_and_hasher(
// Pre-populate the map with all possible table and operation combinations
// to avoid runtime locks on the map when recording metrics.
let mut operations = HashMap::with_capacity_and_hasher(
Tables::COUNT * Operation::COUNT,
BuildHasherDefault::<FxHasher>::default(),
),
);
for table in Tables::ALL {
for operation in Operation::iter() {
operations.insert(
(*table, operation),
OperationMetrics::new_with_labels(&[
(Labels::Table.as_str(), table.name()),
(Labels::Operation.as_str(), operation.as_str()),
]),
);
}
}
Self { operations }
}
/// Record a metric for database operation executed in `f`. Panics if the table name is unknown.
/// Record a metric for database operation executed in `f`.
/// Panics if a metric recorder is not found for the given table and operation.
pub(crate) fn record_operation<R>(
&self,
table: Tables,
@ -38,13 +51,10 @@ impl DatabaseEnvMetrics {
value_size: Option<usize>,
f: impl FnOnce() -> R,
) -> R {
let handle = self.operations.entry((table, operation)).or_insert_with(|| {
OperationMetrics::new_with_labels(&[
(Labels::Table.as_str(), table.name()),
(Labels::Operation.as_str(), operation.as_str()),
])
});
handle.record(value_size, f)
self.operations
.get(&(table, operation))
.expect("operation & table metric handle not found")
.record(value_size, f)
}
}
@ -94,7 +104,7 @@ impl TransactionOutcome {
}
/// Types of operations conducted on the database: get, put, delete, and various cursor operations.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, EnumCount)]
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, EnumCount, EnumIter)]
pub(crate) enum Operation {
/// Database get operation.
Get,