ic_timers/snapshot/
mod.rs1mod identity;
7mod metrics;
8mod model;
9
10pub use identity::{
11 MAX_TIMER_IDENTITY_COMPONENT_BYTES, TimerIdentity, TimerIdentityError, TimerIdentityField,
12};
13pub use metrics::{
14 MeasurementSummary, MemoryPageExtent, MemoryPageSample, MemoryPageSummary, TimerCounters,
15 TimerObservabilitySnapshot, TimerPerformance,
16};
17pub use model::{
18 DeclarationLifetime, InactiveReason, OrdinaryRuntimeStateSnapshot, TimerCompletion,
19 TimerCompletionOutcome, TimerControlFailure, TimerDirectiveSnapshot, TimerEpoch,
20 TimerLastOutcome, TimerOutcomeSnapshot, TimerPolicy, TimerProcessCondition,
21 TimerRegistrationStatus, TimerRunResult, TimerRuntimeStateSnapshot, TimerSchedulingMode,
22 WatchdogAttemptSnapshot, WatchdogAttemptStatus, WatchdogDecision, WatchdogRunResult,
23 WatchdogRuntimeStateSnapshot,
24};
25
26#[derive(Clone, Debug, Eq, PartialEq)]
32pub struct TimerInventorySnapshot {
33 epoch: TimerEpoch,
34 timers: Vec<TimerSnapshot>,
35}
36
37impl TimerInventorySnapshot {
38 pub(crate) const fn new(epoch: TimerEpoch, timers: Vec<TimerSnapshot>) -> Self {
39 Self { epoch, timers }
40 }
41
42 #[must_use]
44 pub const fn epoch(&self) -> TimerEpoch {
45 self.epoch
46 }
47
48 #[must_use]
50 pub fn timers(&self) -> &[TimerSnapshot] {
51 &self.timers
52 }
53
54 #[must_use]
56 pub fn into_timers(self) -> Vec<TimerSnapshot> {
57 self.timers
58 }
59
60 #[must_use]
62 pub const fn len(&self) -> usize {
63 self.timers.len()
64 }
65
66 #[must_use]
68 pub const fn is_empty(&self) -> bool {
69 self.timers.is_empty()
70 }
71}
72
73#[derive(Clone, Debug, Eq, PartialEq)]
75pub struct TimerSnapshot {
76 identity: TimerIdentity,
77 policy: TimerPolicy,
78 lifetime: DeclarationLifetime,
79 state: TimerRuntimeStateSnapshot,
80 scheduling_mode: TimerSchedulingMode,
81 latest_directive: Option<TimerDirectiveSnapshot>,
82 latest_requested_delay_ns: Option<u64>,
83 latest_armed_delay_ns: Option<u64>,
84 observability: TimerObservabilitySnapshot,
85}
86
87impl TimerSnapshot {
88 #[allow(clippy::too_many_arguments)] pub(crate) const fn new(
90 identity: TimerIdentity,
91 policy: TimerPolicy,
92 lifetime: DeclarationLifetime,
93 state: TimerRuntimeStateSnapshot,
94 scheduling_mode: TimerSchedulingMode,
95 latest_directive: Option<TimerDirectiveSnapshot>,
96 latest_requested_delay_ns: Option<u64>,
97 latest_armed_delay_ns: Option<u64>,
98 observability: &TimerObservabilitySnapshot,
99 ) -> Self {
100 Self {
101 identity,
102 policy,
103 lifetime,
104 state,
105 scheduling_mode,
106 latest_directive,
107 latest_requested_delay_ns,
108 latest_armed_delay_ns,
109 observability: *observability,
110 }
111 }
112
113 #[must_use]
115 pub const fn identity(&self) -> &TimerIdentity {
116 &self.identity
117 }
118
119 #[must_use]
121 pub const fn policy(&self) -> TimerPolicy {
122 self.policy
123 }
124
125 #[must_use]
127 pub const fn lifetime(&self) -> DeclarationLifetime {
128 self.lifetime
129 }
130
131 #[must_use]
133 pub const fn state(&self) -> TimerRuntimeStateSnapshot {
134 self.state
135 }
136
137 #[must_use]
143 pub const fn scheduling_mode(&self) -> TimerSchedulingMode {
144 self.scheduling_mode
145 }
146
147 #[must_use]
149 pub const fn latest_directive(&self) -> Option<TimerDirectiveSnapshot> {
150 self.latest_directive
151 }
152
153 #[must_use]
155 pub const fn latest_requested_delay_ns(&self) -> Option<u64> {
156 self.latest_requested_delay_ns
157 }
158
159 #[must_use]
161 pub const fn latest_armed_delay_ns(&self) -> Option<u64> {
162 self.latest_armed_delay_ns
163 }
164
165 #[must_use]
167 pub const fn next_deadline_ns(&self) -> Option<u64> {
168 self.state.next_deadline_ns()
169 }
170
171 #[must_use]
173 pub fn registration_status(&self) -> TimerRegistrationStatus {
174 self.state.into()
175 }
176
177 #[must_use]
179 pub const fn process_condition(&self) -> TimerProcessCondition {
180 match self.state {
181 TimerRuntimeStateSnapshot::Inactive {
182 reason: InactiveReason::Cancelled,
183 } => TimerProcessCondition::Disabled,
184 TimerRuntimeStateSnapshot::Inactive {
185 reason: InactiveReason::InvariantFailure | InactiveReason::ControlFailure(_),
186 } => TimerProcessCondition::Failed,
187 TimerRuntimeStateSnapshot::Inactive {
188 reason: InactiveReason::Stopped,
189 } if matches!(
190 self.observability.outcomes().last_outcome(),
191 Some(TimerLastOutcome::Completed(
192 TimerCompletionOutcome::RetryableFailure
193 ))
194 ) =>
195 {
196 TimerProcessCondition::Failed
197 }
198 TimerRuntimeStateSnapshot::Inactive { .. } => TimerProcessCondition::Idle,
199 TimerRuntimeStateSnapshot::Ordinary(_) | TimerRuntimeStateSnapshot::Watchdog(_)
200 if matches!(self.scheduling_mode, TimerSchedulingMode::Retry) =>
201 {
202 TimerProcessCondition::Retrying
203 }
204 TimerRuntimeStateSnapshot::Ordinary(_) | TimerRuntimeStateSnapshot::Watchdog(_) => {
205 TimerProcessCondition::Active
206 }
207 }
208 }
209
210 #[must_use]
212 pub const fn generation(&self) -> Option<u64> {
213 match self.state {
214 TimerRuntimeStateSnapshot::Inactive { .. } => None,
215 TimerRuntimeStateSnapshot::Ordinary(
216 OrdinaryRuntimeStateSnapshot::Scheduled { generation, .. }
217 | OrdinaryRuntimeStateSnapshot::Running { generation },
218 ) => Some(generation),
219 TimerRuntimeStateSnapshot::Watchdog(WatchdogRuntimeStateSnapshot::Scheduled {
220 scheduler_generation,
221 ..
222 }) => Some(scheduler_generation),
223 TimerRuntimeStateSnapshot::Watchdog(WatchdogRuntimeStateSnapshot::AwaitingWork {
224 successor_generation,
225 ..
226 }) => Some(successor_generation),
227 }
228 }
229
230 #[must_use]
232 pub const fn observability(&self) -> TimerObservabilitySnapshot {
233 self.observability
234 }
235}
236
237#[cfg(test)]
238mod tests;