@@ -116,15 +116,15 @@ impl<T: Serialize> Metrics<T> {
116
116
///
117
117
/// * `metrics_dest` - Buffer for JSON formatted metrics. Needs to implement `Write` and `Send`.
118
118
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 ) {
120
120
return Err ( MetricsError :: AlreadyInitialized ) ;
121
121
}
122
122
{
123
123
let mut g = extract_guard ( self . metrics_buf . lock ( ) ) ;
124
124
125
125
* g = Some ( metrics_dest) ;
126
126
}
127
- self . is_initialized . store ( true , Ordering :: Relaxed ) ;
127
+ self . is_initialized . store ( true , Ordering :: Release ) ;
128
128
Ok ( ( ) )
129
129
}
130
130
@@ -148,7 +148,7 @@ impl<T: Serialize> Metrics<T> {
148
148
/// The alternative is to hold a Mutex over the entire function call, but this increases the
149
149
/// known deadlock potential.
150
150
pub fn write ( & self ) -> Result < bool , MetricsError > {
151
- if self . is_initialized . load ( Ordering :: Relaxed ) {
151
+ if self . is_initialized . load ( Ordering :: Acquire ) {
152
152
match serde_json:: to_string ( & self . app_metrics ) {
153
153
Ok ( msg) => {
154
154
if let Some ( guard) = extract_guard ( self . metrics_buf . lock ( ) ) . as_mut ( ) {
@@ -251,48 +251,45 @@ pub struct SharedIncMetric(AtomicUsize, AtomicUsize);
251
251
pub struct SharedStoreMetric ( AtomicUsize ) ;
252
252
253
253
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?
258
254
fn add ( & self , value : usize ) {
259
- self . 0 . fetch_add ( value, Ordering :: Relaxed ) ;
255
+ self . 0 . fetch_add ( value, Ordering :: AcqRel ) ;
260
256
}
261
257
262
258
fn count ( & self ) -> usize {
263
- self . 0 . load ( Ordering :: Relaxed )
259
+ self . 0 . load ( Ordering :: Acquire )
264
260
}
265
261
}
266
262
267
263
impl StoreMetric for SharedStoreMetric {
268
264
fn fetch ( & self ) -> usize {
269
- self . 0 . load ( Ordering :: Relaxed )
265
+ self . 0 . load ( Ordering :: Acquire )
270
266
}
271
267
272
268
fn store ( & self , value : usize ) {
273
- self . 0 . store ( value, Ordering :: Relaxed ) ;
269
+ self . 0 . store ( value, Ordering :: Release ) ;
274
270
}
275
271
}
276
272
277
273
impl Serialize for SharedIncMetric {
278
274
/// Reset counters of each metrics. Here we suppose that Serialize's goal is to help with the
279
275
/// flushing of metrics.
280
276
/// !!! Any print of the metrics will also reset them. Use with caution !!!
277
+ /// !!! This function is not thread safe !!!
281
278
fn serialize < S : Serializer > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error > {
282
279
// 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 ) ;
285
282
286
283
if res. is_ok ( ) {
287
- self . 1 . store ( snapshot, Ordering :: Relaxed ) ;
284
+ self . 1 . store ( snapshot, Ordering :: Release ) ;
288
285
}
289
286
res
290
287
}
291
288
}
292
289
293
290
impl Serialize for SharedStoreMetric {
294
291
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 )
296
293
}
297
294
}
298
295
0 commit comments