Skip to content

Commit 878c999

Browse files
committed
perf: replace RwLock with SCC HashMap for lock-free metadata access
1 parent ec1dac5 commit 878c999

File tree

5 files changed

+35
-31
lines changed

5 files changed

+35
-31
lines changed

Cargo.lock

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ radix_trie = { version = "0.2", default-features = false }
7171
rand = { version = "0.9", default-features = false, features = [ "thread_rng" ] }
7272
rand_xoshiro = { version = "0.7", default-features = false }
7373
ratatui = { version = "0.28", default-features = false }
74+
scc = { version = "2.1", default-features = false }
7475
sketches-ddsketch = { version = "0.3", default-features = false }
7576
thiserror = { version = "2", default-features = false }
7677
tokio = { version = "1", default-features = false, features = ["rt", "net", "time", "rt-multi-thread"] }

metrics-exporter-opentelemetry/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ metrics = { version = "^0.24", path = "../metrics" }
2020
metrics-util = { version = "^0.20", path = "../metrics-util", default-features = false, features = ["registry"] }
2121
opentelemetry = { workspace = true, features = ["metrics"] }
2222
portable-atomic = { workspace = true, features = ["float", "critical-section"] }
23+
scc = { workspace = true }
2324

2425
[dev-dependencies]
2526
opentelemetry_sdk = { workspace = true, features = ["metrics", "rt-tokio", "testing"] }

metrics-exporter-opentelemetry/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,11 @@ impl Recorder for OpenTelemetryRecorder {
5353
_unit: Option<Unit>,
5454
_description: SharedString,
5555
) {
56-
self.metadata.add_description(_key_name, MetricKind::Counter, _unit, _description);
56+
self.metadata.set_description(_key_name, MetricKind::Counter, _unit, _description);
5757
}
5858

5959
fn describe_gauge(&self, _key_name: KeyName, _unit: Option<Unit>, _description: SharedString) {
60-
self.metadata.add_description(_key_name, MetricKind::Gauge, _unit, _description);
60+
self.metadata.set_description(_key_name, MetricKind::Gauge, _unit, _description);
6161
}
6262

6363
fn describe_histogram(
@@ -66,7 +66,7 @@ impl Recorder for OpenTelemetryRecorder {
6666
_unit: Option<Unit>,
6767
_description: SharedString,
6868
) {
69-
self.metadata.add_description(_key_name, MetricKind::Histogram, _unit, _description);
69+
self.metadata.set_description(_key_name, MetricKind::Histogram, _unit, _description);
7070
}
7171

7272
fn register_counter(&self, key: &Key, _metadata: &metrics::Metadata<'_>) -> Counter {
Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use metrics::{KeyName, SharedString, Unit};
22
use metrics_util::MetricKind;
3-
use std::collections::HashMap;
4-
use std::sync::{Arc, PoisonError, RwLock};
3+
use scc::HashMap;
4+
use std::sync::Arc;
55

66
#[derive(Clone)]
77
pub struct MetricDescription {
@@ -20,58 +20,44 @@ impl MetricDescription {
2020
}
2121

2222
/// Stores all metric metadata including descriptions and histogram bounds
23-
#[derive(Default)]
23+
#[derive(Clone, Default)]
2424
pub struct MetricMetadata {
25-
inner: Arc<RwLock<MetricMetadataInner>>,
26-
}
27-
28-
#[derive(Default)]
29-
struct MetricMetadataInner {
30-
descriptions: HashMap<(KeyName, MetricKind), MetricDescription>,
31-
histogram_bounds: HashMap<KeyName, Vec<f64>>,
25+
descriptions: Arc<HashMap<(KeyName, MetricKind), MetricDescription>>,
26+
histogram_bounds: Arc<HashMap<KeyName, Vec<f64>>>,
3227
}
3328

3429
impl MetricMetadata {
3530
pub fn new() -> Self {
36-
Self::default()
31+
Self {
32+
descriptions: Arc::new(HashMap::new()),
33+
histogram_bounds: Arc::new(HashMap::new()),
34+
}
3735
}
3836

39-
pub fn add_description(
37+
pub fn set_description(
4038
&self,
4139
key_name: KeyName,
4240
metric_kind: MetricKind,
4341
unit: Option<Unit>,
4442
description: SharedString,
4543
) {
4644
let new_entry = MetricDescription { unit, description };
47-
let mut inner = self.inner.write().unwrap_or_else(PoisonError::into_inner);
48-
inner.descriptions.insert((key_name, metric_kind), new_entry);
45+
let _ = self.descriptions.insert((key_name, metric_kind), new_entry);
4946
}
5047

5148
pub fn get_description(
5249
&self,
5350
key_name: &KeyName,
5451
metric_kind: MetricKind,
5552
) -> Option<MetricDescription> {
56-
let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
57-
inner.descriptions.get(&(key_name.clone(), metric_kind)).cloned()
53+
self.descriptions.read(&(key_name.clone(), metric_kind), |_, v| v.clone())
5854
}
5955

6056
pub fn set_histogram_bounds(&self, key_name: KeyName, bounds: Vec<f64>) {
61-
let mut inner = self.inner.write().unwrap_or_else(PoisonError::into_inner);
62-
inner.histogram_bounds.insert(key_name, bounds);
57+
let _ = self.histogram_bounds.insert(key_name, bounds);
6358
}
6459

6560
pub fn get_histogram_bounds(&self, key_name: &KeyName) -> Option<Vec<f64>> {
66-
let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
67-
inner.histogram_bounds.get(key_name).cloned()
61+
self.histogram_bounds.read(key_name, |_, v| v.clone())
6862
}
6963
}
70-
71-
impl Clone for MetricMetadata {
72-
fn clone(&self) -> Self {
73-
Self {
74-
inner: Arc::clone(&self.inner),
75-
}
76-
}
77-
}

0 commit comments

Comments
 (0)