1#![doc = include_str!("resumable.md")]
2use super::{CancelToken, EvalResult};
3use std::time::Duration;
4
5#[derive(Clone, Debug, Default)]
7#[non_exhaustive]
8pub struct EvaluationStop {
9 pub soft_deadline: Option<Duration>,
11 pub cancel: Option<CancelToken>,
13}
14impl EvaluationStop {
15 pub fn after(duration: Duration) -> Self {
17 Self {
18 soft_deadline: Some(duration),
19 cancel: None,
20 }
21 }
22 pub fn cancel(token: CancelToken) -> Self {
24 Self::none().with_cancel(token)
25 }
26 pub fn none() -> Self {
28 Self::default()
29 }
30 pub fn with_cancel(mut self, token: CancelToken) -> Self {
32 self.cancel = Some(token);
33 self
34 }
35}
36#[derive(Debug)]
37#[non_exhaustive]
38pub enum EvaluationProgress {
40 Complete(EvalResult),
42 Incomplete(IncompleteEvaluation),
44}
45#[derive(Debug)]
46#[non_exhaustive]
47pub struct IncompleteEvaluation {
49 pub reason: StopReason,
51 pub computed_vertices: usize,
53}
54#[derive(Clone, Copy, Debug, PartialEq, Eq)]
55#[non_exhaustive]
56pub enum StopReason {
58 Deadline,
60 Cancelled,
62}
63
64#[derive(Debug)]
66#[non_exhaustive]
67pub enum RecalcJobError {
68 Poisoned,
70 NoActiveJob,
72 AlreadyPending {
74 explicit: bool,
76 },
77 Evaluation(formualizer_common::ExcelError),
79}
80impl std::fmt::Display for RecalcJobError {
81 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82 match self {
83 Self::Poisoned => f.write_str(super::poison::POISON_MESSAGE),
84 Self::NoActiveJob => f.write_str("no active recalculation job"),
85 Self::AlreadyPending { explicit } => {
86 write!(f, "recalculation already pending (explicit: {explicit})")
87 }
88 Self::Evaluation(error) => write!(f, "recalculation failed: {error}"),
89 }
90 }
91}
92impl std::error::Error for RecalcJobError {
93 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
94 match self {
95 Self::Evaluation(error) => Some(error),
96 _ => None,
97 }
98 }
99}
100impl From<formualizer_common::ExcelError> for RecalcJobError {
101 fn from(error: formualizer_common::ExcelError) -> Self {
102 Self::Evaluation(error)
103 }
104}
105
106#[derive(Debug)]
108#[non_exhaustive]
109pub enum RecalcOutcome {
110 Finished(EvalResult),
112 Cancelled,
114 Paused,
116}
117
118#[derive(Clone, Debug)]
120#[non_exhaustive]
121pub struct RecalcJobOptions {
122 pub collect_deltas: bool,
124 pub max_delta_records: usize,
127 pub initial_priority: Vec<super::EvaluationTarget>,
129}
130impl Default for RecalcJobOptions {
131 fn default() -> Self {
132 Self {
133 collect_deltas: true,
134 max_delta_records: 1024,
135 initial_priority: Vec::new(),
136 }
137 }
138}
139#[derive(Clone, Copy, Debug, PartialEq, Eq)]
140#[non_exhaustive]
141pub enum StepPhase {
143 BuildingGraph,
145 Scheduling,
147 Evaluating,
149 Finished,
151 Cancelled,
153}
154#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
155#[non_exhaustive]
156pub struct StepProgress {
158 pub pass: u32,
160 pub completed_in_pass: usize,
162 pub scheduled_in_pass: usize,
164 pub cumulative_computed_vertices: usize,
166 pub total_exact: bool,
169 pub staged_formulas_remaining: usize,
171 pub priority_pending: bool,
173}
174#[derive(Clone, Debug, Default, PartialEq, Eq)]
175#[non_exhaustive]
176pub struct StepDelta {
178 pub delta: super::TargetEvalDelta,
181 pub overflow_sheets: Vec<formualizer_common::SheetId>,
183}
184#[derive(Clone, Copy, Debug, PartialEq, Eq)]
185#[non_exhaustive]
186pub enum SlowUnitKind {
188 GraphBuild,
190 ScheduleBuild,
192 SingleCell,
194 FamilyRun,
196 Cycle,
198}
199#[derive(Clone, Debug, PartialEq, Eq)]
200#[non_exhaustive]
201pub struct SlowUnitReport {
203 pub kind: SlowUnitKind,
205 pub representative_cell: Option<formualizer_common::PackedSheetCell>,
207 pub vertex_count: usize,
209 pub elapsed: Duration,
211}
212#[derive(Debug)]
213#[non_exhaustive]
214pub struct StepReport {
218 pub phase: StepPhase,
220 pub progress: StepProgress,
222 pub step_computed_vertices: usize,
224 pub step_elapsed: Duration,
226 pub changed: StepDelta,
228 pub longest_unit: Option<SlowUnitReport>,
230 pub result: Option<EvalResult>,
232}
233
234#[derive(Default)]
236pub(super) struct LogicalRecalculation {
237 pub held: Option<super::eval::HeldRecalcSchedule>,
238 pub pass: u32,
239 pub pass_completed: usize,
240 pub pass_scheduled: usize,
241 pub pass_exact: bool,
242 pub priority_targets: Vec<super::EvaluationTarget>,
243 pub priority_deferred: bool,
244 pub work_units: u64,
245 pub active_elapsed: Duration,
246 pub seed_retained_bytes: u64,
247 pub topology_epoch: u64,
248 pub authority_revision: (u64, u64),
249 pub computed_vertices: usize,
250 pub cycle_errors: usize,
251 pub elapsed: Duration,
252 pub replans: usize,
253 pub function_epoch: u64,
256 pub provider_revision: Option<u64>,
257 pub mutation_revision: u64,
258 pub source_mutation_generation: u64,
259 pub installed: super::idset::DenseIdSet,
261 pub cycle_seeds: rustc_hash::FxHashMap<
264 Vec<super::VertexId>,
265 rustc_hash::FxHashMap<super::VertexId, formualizer_common::LiteralValue>,
266 >,
267 pub original_cycles: rustc_hash::FxHashSet<Vec<super::VertexId>>,
268 pub original_cycles_recorded: bool,
269 pub new_cycle_members: super::idset::DenseIdSet,
272}
273
274impl LogicalRecalculation {
275 pub fn refresh_seed_retained_bytes(&mut self) {
276 use formualizer_common::LiteralValue;
277 use std::mem::size_of;
278 fn payload(value: &LiteralValue) -> usize {
279 match value {
280 LiteralValue::Text(s) => s.capacity(),
281 LiteralValue::Array(rows) => {
282 rows.capacity() * size_of::<Vec<LiteralValue>>()
283 + rows
284 .iter()
285 .map(|r| {
286 r.capacity() * size_of::<LiteralValue>()
287 + r.iter().map(payload).sum::<usize>()
288 })
289 .sum::<usize>()
290 }
291 _ => 0,
292 }
293 }
294 self.seed_retained_bytes = (self.cycle_seeds.capacity()
295 * size_of::<(
296 Vec<super::VertexId>,
297 rustc_hash::FxHashMap<super::VertexId, LiteralValue>,
298 )>()
299 + self
300 .cycle_seeds
301 .iter()
302 .map(|(key, values)| {
303 key.capacity() * size_of::<super::VertexId>()
304 + values.capacity() * size_of::<(super::VertexId, LiteralValue)>()
305 + values.values().map(payload).sum::<usize>()
306 })
307 .sum::<usize>()
308 + self.original_cycles.capacity() * size_of::<Vec<super::VertexId>>()
309 + self
310 .original_cycles
311 .iter()
312 .map(|k| k.capacity() * size_of::<super::VertexId>())
313 .sum::<usize>()) as u64;
314 }
315 pub fn forget_dissolved_new_cycles(&mut self, vertices: &[super::VertexId]) {
316 if self.new_cycle_members.is_empty()
317 || !vertices.iter().any(|v| self.new_cycle_members.contains(v))
318 {
319 return;
320 }
321 let before = self.cycle_seeds.len();
324 self.cycle_seeds.retain(|key, _| {
325 self.original_cycles.contains(key)
326 || !vertices.iter().any(|v| key.binary_search(v).is_ok())
327 });
328 if before != self.cycle_seeds.len() {
329 self.refresh_seed_retained_bytes();
330 }
331 }
332}