Skip to content

Commit fb1c854

Browse files
committed
hmon: logic monitor post-review fixes
- Move `loom` imports to `common`. - Remove `Sync` from `LogicMonitor`. - `PhantomUnsync` added to `common`. - `LogicEvaluationError` -> replace `From` with `TryFrom`. - Replace `monitor_status` and `set_monitor_status` type. - From `u8` to `LogicEvaluationError`. - Replace `update` with `swap` in `LogicState`.
1 parent 48bc6f2 commit fb1c854

4 files changed

Lines changed: 86 additions & 87 deletions

File tree

src/health_monitoring_lib/rust/common.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ use crate::heartbeat::HeartbeatEvaluationError;
1616
use crate::log::ScoreDebug;
1717
use crate::logic::LogicEvaluationError;
1818
use crate::tag::MonitorTag;
19+
use core::cell::Cell;
1920
use core::hash::Hash;
21+
use core::marker::PhantomData;
2022
use core::time::Duration;
2123
use std::sync::Arc;
2224
use std::time::Instant;
@@ -151,6 +153,14 @@ where
151153
T::try_from(millis).expect("Duration is too big for the integer of this type")
152154
}
153155

156+
/// Marker for disabling [`Sync`].
157+
pub(crate) type PhantomUnsync = PhantomData<Cell<()>>;
158+
159+
#[cfg(not(loom))]
160+
pub use core::sync::atomic::{AtomicU64, Ordering};
161+
#[cfg(loom)]
162+
pub use loom::sync::atomic::{AtomicU64, Ordering};
163+
154164
#[cfg(all(test, not(loom)))]
155165
mod tests {
156166
use crate::common::{duration_to_int, time_offset, TimeRange};

src/health_monitoring_lib/rust/heartbeat/heartbeat_state.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,9 @@
1111
// SPDX-License-Identifier: Apache-2.0
1212
// *******************************************************************************
1313

14+
use crate::common::{AtomicU64, Ordering};
1415
use core::cmp::min;
1516

16-
#[cfg(not(loom))]
17-
use core::sync::atomic::{AtomicU64, Ordering};
18-
#[cfg(loom)]
19-
use loom::sync::atomic::{AtomicU64, Ordering};
20-
2117
/// Snapshot of a heartbeat state.
2218
/// Layout (u64) = | heartbeat timestamp: 62 bits | heartbeat counter: 2 bits |
2319
#[derive(Clone, Copy, Default)]

src/health_monitoring_lib/rust/logic/logic_monitor.rs

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,20 @@
1111
// SPDX-License-Identifier: Apache-2.0
1212
// *******************************************************************************
1313

14-
use crate::common::{Monitor, MonitorEvalHandle, MonitorEvaluationError, MonitorEvaluator};
14+
use crate::common::{Monitor, MonitorEvalHandle, MonitorEvaluationError, MonitorEvaluator, PhantomUnsync};
1515
use crate::log::{error, warn, ScoreDebug};
1616
use crate::logic::logic_state::LogicState;
1717
use crate::protected_memory::ProtectedMemoryAllocator;
1818
use crate::tag::{MonitorTag, StateTag};
1919
use crate::HealthMonitorError;
2020
use core::hash::Hash;
21+
use core::marker::PhantomData;
2122
use std::collections::HashMap;
2223
use std::sync::Arc;
2324
use std::time::Instant;
2425

2526
/// Internal OK state representation.
26-
const OK_STATE: u8 = 0;
27+
pub(super) const OK_STATE: u8 = 0;
2728

2829
/// Logic evaluation errors.
2930
#[repr(u8)]
@@ -33,6 +34,8 @@ pub enum LogicEvaluationError {
3334
InvalidState = OK_STATE + 1,
3435
/// Transition is invalid.
3536
InvalidTransition,
37+
/// Unknown error.
38+
UnmappedError,
3639
}
3740

3841
impl From<LogicEvaluationError> for u8 {
@@ -41,12 +44,18 @@ impl From<LogicEvaluationError> for u8 {
4144
}
4245
}
4346

44-
impl From<u8> for LogicEvaluationError {
45-
fn from(value: u8) -> Self {
47+
impl TryFrom<u8> for LogicEvaluationError {
48+
type Error = ();
49+
50+
fn try_from(value: u8) -> Result<Self, Self::Error> {
51+
const INVALID_STATE: u8 = LogicEvaluationError::InvalidState as u8;
52+
const INVALID_TRANSITION: u8 = LogicEvaluationError::InvalidTransition as u8;
53+
const UNMAPPED_ERROR: u8 = LogicEvaluationError::UnmappedError as u8;
4654
match value {
47-
value if value == LogicEvaluationError::InvalidState as u8 => LogicEvaluationError::InvalidState,
48-
value if value == LogicEvaluationError::InvalidTransition as u8 => LogicEvaluationError::InvalidTransition,
49-
_ => panic!("Invalid underlying value of logic evaluation error."),
55+
INVALID_STATE => Ok(LogicEvaluationError::InvalidState),
56+
INVALID_TRANSITION => Ok(LogicEvaluationError::InvalidTransition),
57+
UNMAPPED_ERROR => Ok(LogicEvaluationError::UnmappedError),
58+
_ => Err(()),
5059
}
5160
}
5261
}
@@ -157,12 +166,16 @@ impl LogicMonitorBuilder {
157166
/// Logic monitor.
158167
pub struct LogicMonitor {
159168
inner: Arc<LogicMonitorInner>,
169+
_unsync: PhantomUnsync,
160170
}
161171

162172
impl LogicMonitor {
163173
/// Create a new [`LogicMonitor`] instance.
164174
fn new(inner: Arc<LogicMonitorInner>) -> Self {
165-
Self { inner }
175+
Self {
176+
inner,
177+
_unsync: PhantomData,
178+
}
166179
}
167180

168181
/// Perform transition to a new state.
@@ -198,8 +211,7 @@ struct LogicMonitorInner {
198211
impl MonitorEvaluator for LogicMonitorInner {
199212
fn evaluate(&self, _hmon_starting_point: Instant, on_error: &mut dyn FnMut(&MonitorTag, MonitorEvaluationError)) {
200213
let snapshot = self.logic_state.snapshot();
201-
if snapshot.monitor_status() != OK_STATE {
202-
let error = LogicEvaluationError::from(snapshot.monitor_status());
214+
if let Err(error) = snapshot.monitor_status() {
203215
warn!("Logic monitor error observed: {:?}", error);
204216
on_error(&self.monitor_tag, error.into());
205217
}
@@ -235,10 +247,10 @@ impl LogicMonitorInner {
235247

236248
fn transition(&self, target_state: StateTag) -> Result<StateTag, LogicEvaluationError> {
237249
// Load current monitor state.
238-
let snapshot = self.logic_state.snapshot();
250+
let mut snapshot = self.logic_state.snapshot();
239251

240252
// Disallow operation in erroneous state.
241-
if snapshot.monitor_status() != OK_STATE {
253+
if snapshot.monitor_status().is_err() {
242254
warn!("Current logic monitor state cannot be determined");
243255
return Err(LogicEvaluationError::InvalidState);
244256
}
@@ -254,20 +266,17 @@ impl LogicMonitorInner {
254266
"Requested state transition is invalid: {:?} -> {:?}",
255267
current_state_node.tag, target_state
256268
);
269+
257270
let error = LogicEvaluationError::InvalidTransition;
258-
let _ = self.logic_state.update(|mut current_state| {
259-
current_state.set_monitor_status(error.into());
260-
Some(current_state)
261-
});
271+
snapshot.set_monitor_status(error);
272+
let _ = self.logic_state.swap(snapshot);
262273
return Err(error);
263274
}
264275

265276
// Find index of target state, then change current state.
266277
let target_state_index = self.find_index_by_tag(target_state)?;
267-
let _ = self.logic_state.update(|mut current_state| {
268-
current_state.set_current_state_index(target_state_index);
269-
Some(current_state)
270-
});
278+
snapshot.set_current_state_index(target_state_index);
279+
let _ = self.logic_state.swap(snapshot);
271280

272281
Ok(target_state)
273282
}
@@ -277,7 +286,7 @@ impl LogicMonitorInner {
277286
let snapshot = self.logic_state.snapshot();
278287

279288
// Disallow operation in erroneous state.
280-
if snapshot.monitor_status() != OK_STATE {
289+
if snapshot.monitor_status().is_err() {
281290
warn!("Current logic monitor state cannot be determined");
282291
return Err(LogicEvaluationError::InvalidState);
283292
}

src/health_monitoring_lib/rust/logic/logic_state.rs

Lines changed: 45 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@
1111
// SPDX-License-Identifier: Apache-2.0
1212
// *******************************************************************************
1313

14-
#[cfg(not(loom))]
15-
use core::sync::atomic::{AtomicU64, Ordering};
16-
#[cfg(loom)]
17-
use loom::sync::atomic::{AtomicU64, Ordering};
14+
use crate::common::{AtomicU64, Ordering};
15+
use crate::logic::logic_monitor::OK_STATE;
16+
use crate::logic::LogicEvaluationError;
1817

1918
/// Snapshot of a logic state.
2019
/// Layout (u64) = | current state index: 56 bits | monitor status: u8 |
@@ -53,12 +52,17 @@ impl LogicStateSnapshot {
5352
/// Monitor status.
5453
/// - zero if healthy.
5554
/// - `LogicEvaluationError` if not.
56-
pub fn monitor_status(&self) -> u8 {
57-
(self.0 & STATUS_MASK) as u8
55+
pub fn monitor_status(&self) -> Result<(), LogicEvaluationError> {
56+
let value = (self.0 & STATUS_MASK) as u8;
57+
if value == OK_STATE {
58+
Ok(())
59+
} else {
60+
Err(value.try_into().map_err(|_| LogicEvaluationError::UnmappedError)?)
61+
}
5862
}
5963

6064
/// Set monitor status.
61-
pub fn set_monitor_status(&mut self, value: u8) {
65+
pub fn set_monitor_status(&mut self, value: LogicEvaluationError) {
6266
self.0 = (value as u64) | (self.0 & !STATUS_MASK);
6367
}
6468
}
@@ -85,26 +89,16 @@ impl LogicState {
8589
LogicStateSnapshot::from(self.0.load(Ordering::Acquire))
8690
}
8791

88-
/// Update the logic state using the provided closure.
89-
/// Closure receives the current state and should return an [`Option`] containing a new state.
90-
/// If [`None`] is returned then the state was not updated.
91-
pub fn update<F: FnMut(LogicStateSnapshot) -> Option<LogicStateSnapshot>>(
92-
&self,
93-
mut f: F,
94-
) -> Result<LogicStateSnapshot, LogicStateSnapshot> {
95-
self.0
96-
.fetch_update(Ordering::AcqRel, Ordering::Acquire, |prev| {
97-
let snapshot = LogicStateSnapshot::from(prev);
98-
f(snapshot).map(|new_snapshot: LogicStateSnapshot| new_snapshot.as_u64())
99-
})
100-
.map(LogicStateSnapshot::from)
101-
.map_err(LogicStateSnapshot::from)
92+
/// Store a new [`LogicStateSnapshot`] and return the previous one.
93+
pub fn swap(&self, new: LogicStateSnapshot) -> LogicStateSnapshot {
94+
self.0.swap(new.as_u64(), Ordering::AcqRel).into()
10295
}
10396
}
10497

10598
#[cfg(all(test, not(loom)))]
10699
mod tests {
107100
use crate::logic::logic_state::{LogicState, LogicStateSnapshot};
101+
use crate::logic::LogicEvaluationError;
108102
use core::sync::atomic::Ordering;
109103

110104
#[test]
@@ -114,7 +108,7 @@ mod tests {
114108

115109
assert_eq!(state.as_u64(), (initial_state_index as u64) << u8::BITS);
116110
assert_eq!(state.current_state_index(), initial_state_index);
117-
assert_eq!(state.monitor_status(), 0);
111+
assert!(state.monitor_status().is_ok());
118112
}
119113

120114
#[test]
@@ -123,16 +117,18 @@ mod tests {
123117

124118
assert_eq!(state.as_u64(), 0x00);
125119
assert_eq!(state.current_state_index(), 0);
126-
assert_eq!(state.monitor_status(), 0);
120+
assert!(state.monitor_status().is_ok());
127121
}
128122

129123
#[test]
130124
fn snapshot_from_u64_valid() {
131-
let state = LogicStateSnapshot::from(0xDEADBEEF_DEADBEEF);
125+
let state = LogicStateSnapshot::from(0xDEADBEEF_DEADBE01);
132126

133-
assert_eq!(state.as_u64(), 0xDEADBEEF_DEADBEEF);
134-
assert_eq!(state.current_state_index(), 0xDEADBEEF_DEADBEEF >> u8::BITS);
135-
assert_eq!(state.monitor_status(), 0xEF);
127+
assert_eq!(state.as_u64(), 0xDEADBEEF_DEADBE01);
128+
assert_eq!(state.current_state_index(), 0xDEADBEEF_DEADBE01 >> u8::BITS);
129+
assert!(state
130+
.monitor_status()
131+
.is_err_and(|e| e == LogicEvaluationError::InvalidState));
136132
}
137133

138134
#[test]
@@ -141,18 +137,20 @@ mod tests {
141137

142138
assert_eq!(state.as_u64(), u64::MAX);
143139
assert_eq!(state.current_state_index(), (u64::MAX >> u8::BITS) as usize);
144-
assert_eq!(state.monitor_status(), u8::MAX);
140+
assert!(state
141+
.monitor_status()
142+
.is_err_and(|e| e == LogicEvaluationError::UnmappedError));
145143
}
146144

147145
#[test]
148146
fn snapshot_set_current_state_index_valid() {
149-
let mut state = LogicStateSnapshot::from(0xDEADBEEF_DEADBEEF);
147+
let mut state = LogicStateSnapshot::from(0xDEADBEEF_DEADBE00);
150148
state.set_current_state_index(0x00CAFEBA_DCAFEBAD);
151149

152150
assert_eq!(state.current_state_index(), 0x00CAFEBA_DCAFEBAD);
153151

154152
// Check other parameters unchanged.
155-
assert_eq!(state.monitor_status(), 0xEF);
153+
assert!(state.monitor_status().is_ok());
156154
}
157155

158156
#[test]
@@ -165,9 +163,11 @@ mod tests {
165163
#[test]
166164
fn snapshot_set_monitor_status_valid() {
167165
let mut state = LogicStateSnapshot::from(0xDEADBEEF_DEADBEEF);
168-
state.set_monitor_status(0xFA);
166+
state.set_monitor_status(LogicEvaluationError::InvalidTransition);
169167

170-
assert_eq!(state.monitor_status(), 0xFA);
168+
assert!(state
169+
.monitor_status()
170+
.is_err_and(|e| e == LogicEvaluationError::InvalidTransition));
171171

172172
// Check other parameters unchanged.
173173
assert_eq!(state.current_state_index(), 0xDEADBEEF_DEADBEEF >> u8::BITS);
@@ -191,35 +191,19 @@ mod tests {
191191
}
192192

193193
#[test]
194-
fn state_update_some() {
194+
fn state_swap() {
195195
let state = LogicState::new(0);
196-
let _ = state.update(|prev_snapshot| {
197-
// Make sure state is as expected.
198-
assert_eq!(prev_snapshot.as_u64(), 0x00);
199-
assert_eq!(prev_snapshot.current_state_index(), 0);
200-
assert_eq!(prev_snapshot.monitor_status(), 0);
201-
202-
Some(LogicStateSnapshot::from(0xDEADBEEF_DEADBEEF))
203-
});
204-
205-
let _ = state.update(|prev_snapshot| {
206-
// Make sure state is as expected.
207-
assert_eq!(prev_snapshot.as_u64(), 0xDEADBEEF_DEADBEEF);
208-
assert_eq!(prev_snapshot.current_state_index(), 0xDEADBEEF_DEADBEEF >> u8::BITS);
209-
assert_eq!(prev_snapshot.monitor_status(), 0xEF);
210-
211-
Some(LogicStateSnapshot::from(0))
212-
});
213-
214-
assert_eq!(state.snapshot().as_u64(), 0);
215-
}
216-
217-
#[test]
218-
fn state_update_none() {
219-
let state = LogicState::new(4321);
220-
let _ = state.update(|_| Some(LogicStateSnapshot::from(0xDEADBEEF_DEADBEEF)));
221-
let _ = state.update(|_| None);
222-
223-
assert_eq!(state.snapshot().as_u64(), 0xDEADBEEF_DEADBEEF);
196+
let prev_snapshot = state.swap(LogicStateSnapshot::from(0xDEADBEEF_DEADBE02));
197+
198+
assert_eq!(prev_snapshot.as_u64(), 0x00);
199+
assert_eq!(prev_snapshot.current_state_index(), 0);
200+
assert!(prev_snapshot.monitor_status().is_ok());
201+
202+
let curr_snapshot = state.snapshot();
203+
assert_eq!(curr_snapshot.as_u64(), 0xDEADBEEF_DEADBE02);
204+
assert_eq!(curr_snapshot.current_state_index(), 0xDEADBEEF_DEADBE02 >> u8::BITS);
205+
assert!(curr_snapshot
206+
.monitor_status()
207+
.is_err_and(|e| e == LogicEvaluationError::InvalidTransition));
224208
}
225209
}

0 commit comments

Comments
 (0)