Skip to content

Commit b4b5513

Browse files
committed
metrics: enforce tighter Atomic ordering
Metric values are accessed from all threads, so enforce Release/Acquire semantics to make sure that we always use the latest values. Signed-off-by: alindima <[email protected]>
1 parent ee8c9d6 commit b4b5513

File tree

1 file changed

+12
-15
lines changed

1 file changed

+12
-15
lines changed

src/logger/src/metrics.rs

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -116,15 +116,15 @@ impl<T: Serialize> Metrics<T> {
116116
///
117117
/// * `metrics_dest` - Buffer for JSON formatted metrics. Needs to implement `Write` and `Send`.
118118
pub fn init(&self, metrics_dest: Box<dyn Write + Send>) -> Result<(), MetricsError> {
119-
if self.is_initialized.load(Ordering::Relaxed) {
119+
if self.is_initialized.load(Ordering::Acquire) {
120120
return Err(MetricsError::AlreadyInitialized);
121121
}
122122
{
123123
let mut g = extract_guard(self.metrics_buf.lock());
124124

125125
*g = Some(metrics_dest);
126126
}
127-
self.is_initialized.store(true, Ordering::Relaxed);
127+
self.is_initialized.store(true, Ordering::Release);
128128
Ok(())
129129
}
130130

@@ -148,7 +148,7 @@ impl<T: Serialize> Metrics<T> {
148148
/// The alternative is to hold a Mutex over the entire function call, but this increases the
149149
/// known deadlock potential.
150150
pub fn write(&self) -> Result<bool, MetricsError> {
151-
if self.is_initialized.load(Ordering::Relaxed) {
151+
if self.is_initialized.load(Ordering::Acquire) {
152152
match serde_json::to_string(&self.app_metrics) {
153153
Ok(msg) => {
154154
if let Some(guard) = extract_guard(self.metrics_buf.lock()).as_mut() {
@@ -251,48 +251,45 @@ pub struct SharedIncMetric(AtomicUsize, AtomicUsize);
251251
pub struct SharedStoreMetric(AtomicUsize);
252252

253253
impl IncMetric for SharedIncMetric {
254-
// While the order specified for this operation is still Relaxed, the actual instruction will
255-
// be an asm "LOCK; something" and thus atomic across multiple threads, simply because of the
256-
// fetch_and_add (as opposed to "store(load() + 1)") implementation for atomics.
257-
// TODO: would a stronger ordering make a difference here?
258254
fn add(&self, value: usize) {
259-
self.0.fetch_add(value, Ordering::Relaxed);
255+
self.0.fetch_add(value, Ordering::AcqRel);
260256
}
261257

262258
fn count(&self) -> usize {
263-
self.0.load(Ordering::Relaxed)
259+
self.0.load(Ordering::Acquire)
264260
}
265261
}
266262

267263
impl StoreMetric for SharedStoreMetric {
268264
fn fetch(&self) -> usize {
269-
self.0.load(Ordering::Relaxed)
265+
self.0.load(Ordering::Acquire)
270266
}
271267

272268
fn store(&self, value: usize) {
273-
self.0.store(value, Ordering::Relaxed);
269+
self.0.store(value, Ordering::Release);
274270
}
275271
}
276272

277273
impl Serialize for SharedIncMetric {
278274
/// Reset counters of each metrics. Here we suppose that Serialize's goal is to help with the
279275
/// flushing of metrics.
280276
/// !!! Any print of the metrics will also reset them. Use with caution !!!
277+
/// !!! This function is not thread safe !!!
281278
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
282279
// There's no serializer.serialize_usize() for some reason :(
283-
let snapshot = self.0.load(Ordering::Relaxed);
284-
let res = serializer.serialize_u64(snapshot as u64 - self.1.load(Ordering::Relaxed) as u64);
280+
let snapshot = self.count();
281+
let res = serializer.serialize_u64(snapshot as u64 - self.1.load(Ordering::Acquire) as u64);
285282

286283
if res.is_ok() {
287-
self.1.store(snapshot, Ordering::Relaxed);
284+
self.1.store(snapshot, Ordering::Release);
288285
}
289286
res
290287
}
291288
}
292289

293290
impl Serialize for SharedStoreMetric {
294291
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
295-
serializer.serialize_u64(self.0.load(Ordering::Relaxed) as u64)
292+
serializer.serialize_u64(self.0.load(Ordering::Acquire) as u64)
296293
}
297294
}
298295

0 commit comments

Comments
 (0)