diff --git a/wicketd/src/http_entrypoints.rs b/wicketd/src/http_entrypoints.rs index a28326ee147..da94c7df1c3 100644 --- a/wicketd/src/http_entrypoints.rs +++ b/wicketd/src/http_entrypoints.rs @@ -395,10 +395,32 @@ impl WicketdApi for WicketdApiImpl { // Fetch the transceiver information from the SP. let maybe_transceiver_inventory = match rqctx.context().transceiver_handle.get_transceivers() { - GetTransceiversResponse::Response { - transceivers, - transceivers_last_seen, - } => Some((transceivers, transceivers_last_seen)), + GetTransceiversResponse::Response { transceivers } => { + // transceivers tracks the last_seen for each switch + // independently. But the (currently frozen) wicketd API + // wire shape only has a single last_seen field. So we must + // pick: min or max? We choose max here, so that if one of + // the fetch tasks is wedged, the timestamp indicates that. + // + // TODO: clean this up (report per-switch last_seen) once + // rkdeploy is on the stable commissioning API. + let last_seen = transceivers + .iter() + .map(|switch| switch.updated_at.elapsed()) + .max(); + last_seen.map(|last_seen| { + // The (currently frozen) wicketd API is a HashMap, so + // collect into that. + // + // TODO: switch to IdOrdMap once rkdeploy is on the + // stable commissioning API. + let inventory = transceivers + .into_iter() + .map(|switch| (switch.switch, switch.transceivers)) + .collect(); + (inventory, last_seen) + }) + } GetTransceiversResponse::Unavailable => None, }; diff --git a/wicketd/src/transceivers.rs b/wicketd/src/transceivers.rs index 128fdd38613..c6c39ea6904 100644 --- a/wicketd/src/transceivers.rs +++ b/wicketd/src/transceivers.rs @@ -5,11 +5,11 @@ //! Fetching transceiver state from the SP. use gateway_types::component::SpIdentifier; +use iddqd::{IdOrdItem, IdOrdMap, id_ord_map, id_upcast}; use sled_agent_types::early_networking::SwitchSlot; use slog::{Logger, debug, error}; use slog_error_chain::InlineErrorChain; use std::{ - collections::HashMap, sync::{Arc, Mutex}, time::Duration, }; @@ -24,7 +24,30 @@ use transceiver_controller::{SpRequest, message::ExtendedStatus}; use wicket_common::inventory::{SpType, Transceiver}; /// Type alias for a map of all transceivers on each switch. -pub type TransceiverMap = HashMap>; +pub type TransceiverMap = IdOrdMap; + +/// Item in a [`TransceiverMap`]. +/// +/// This tracks the state of all transceivers on a single switch. +#[derive(Clone, Debug)] +pub struct SwitchTransceivers { + /// The switch slot. + pub switch: SwitchSlot, + /// The list of transceivers on this switch. + pub transceivers: Vec, + /// The last time we fetched transceivers from this switch. + pub updated_at: Instant, +} + +impl IdOrdItem for SwitchTransceivers { + type Key<'a> = SwitchSlot; + + fn key(&self) -> Self::Key<'_> { + self.switch + } + + id_upcast!(); +} // Queue size for passing messages between transceiver fetch task. const CHANNEL_CAPACITY: usize = 4; @@ -50,7 +73,7 @@ const OTHER_SWITCH_SP_INTERFACE: &str = "sidecar1"; #[derive(Clone, Debug)] pub enum GetTransceiversResponse { - Response { transceivers: TransceiverMap, transceivers_last_seen: Duration }, + Response { transceivers: TransceiverMap }, Unavailable, } @@ -171,22 +194,21 @@ impl Manager { error!(self.log, "all transceiver fetch tasks have exited"); return; }; + let update = SwitchTransceivers { + switch: switch_slot, + transceivers: these_transceivers, + updated_at, + }; let mut transceivers_by_switch = self.transceivers.lock().unwrap(); match &mut *transceivers_by_switch { - GetTransceiversResponse::Response { - transceivers, - transceivers_last_seen, - } => { - transceivers.insert(switch_slot, these_transceivers); - *transceivers_last_seen = updated_at.elapsed(); + GetTransceiversResponse::Response { transceivers } => { + transceivers.insert_overwrite(update); } GetTransceiversResponse::Unavailable => { - let mut all_transceivers = TransceiverMap::new(); - all_transceivers.insert(switch_slot, these_transceivers); + let all_transceivers = id_ord_map! { update }; *transceivers_by_switch = GetTransceiversResponse::Response { transceivers: all_transceivers, - transceivers_last_seen: updated_at.elapsed(), }; } }