1use std::collections::BTreeMap;
2use std::sync::Arc;
3
4use super::FormulaPlaneMode;
5use super::arena::AstNodeId;
6use super::formula_source::{SourceFamilyId, SourceFormulaOrder};
7
8#[derive(Clone, Debug)]
9pub struct FormulaIngestRecord {
10 pub row: u32,
11 pub col: u32,
12 pub ast_id: AstNodeId,
13 pub formula_text: Option<Arc<str>>,
14 pub(crate) source_order: Option<SourceFormulaOrder>,
15 pub(crate) source_family: Option<SourceFamilyId>,
16 pub(crate) partition_owner: Option<SourceFamilyId>,
17}
18
19impl FormulaIngestRecord {
20 pub fn new(row: u32, col: u32, ast_id: AstNodeId, formula_text: Option<Arc<str>>) -> Self {
21 Self {
22 row,
23 col,
24 ast_id,
25 formula_text,
26 source_order: None,
27 source_family: None,
28 partition_owner: None,
29 }
30 }
31
32 pub(crate) fn with_source_proof(
33 mut self,
34 source_order: SourceFormulaOrder,
35 source_family: Option<SourceFamilyId>,
36 partition_owner: Option<SourceFamilyId>,
37 ) -> Self {
38 self.source_order = Some(source_order);
39 self.source_family = source_family;
40 self.partition_owner = partition_owner;
41 self
42 }
43}
44
45#[derive(Clone, Debug)]
46pub struct FormulaIngestBatch {
47 pub sheet_name: String,
48 pub formulas: Vec<FormulaIngestRecord>,
49}
50
51impl FormulaIngestBatch {
52 pub fn new(sheet_name: impl Into<String>, formulas: Vec<FormulaIngestRecord>) -> Self {
53 Self {
54 sheet_name: sheet_name.into(),
55 formulas,
56 }
57 }
58
59 pub fn len(&self) -> usize {
60 self.formulas.len()
61 }
62
63 pub fn is_empty(&self) -> bool {
64 self.formulas.is_empty()
65 }
66}
67
68#[derive(Debug, Clone, PartialEq, Eq)]
69pub struct FormulaIngestReport {
70 pub mode: FormulaPlaneMode,
71 pub formula_cells_seen: u64,
72 pub graph_formula_cells_materialized: u64,
73
74 pub shadow_candidate_cells: u64,
75 pub shadow_accepted_span_cells: u64,
76 pub shadow_fallback_cells: u64,
77 pub shadow_templates_interned: u64,
78 pub shadow_spans_created: u64,
79
80 pub graph_formula_vertices_avoided_shadow: u64,
81 pub ast_roots_avoided_shadow: u64,
82 pub edge_rows_avoided_shadow: u64,
83
84 pub graph_vertices_created: u64,
85 pub graph_edges_created: u64,
86
87 pub source_formula_events: u64,
88 pub source_formula_records_spooled: u64,
89 pub source_spool_encoded_bytes: u64,
90 pub source_spool_peak_memory_bytes: u64,
91 pub source_spool_spilled_bytes: u64,
92 pub source_spool_spill_files: u64,
93 pub source_spool_replays: u64,
94 pub source_ordinary_events: u64,
95 pub source_shared_anchor_events: u64,
96 pub source_shared_descendant_events: u64,
97 pub source_unknown_events: u64,
98 pub source_families_seen: u64,
99 pub source_family_cells_seen: u64,
100 pub source_family_shadow_eligible: u64,
101 pub source_family_shadow_eligible_cells: u64,
102 pub source_family_promoted: u64,
103 pub source_family_promoted_cells: u64,
104 pub source_family_fallback: u64,
105 pub source_family_fallback_cells: u64,
106 pub source_forward_descendants: u64,
107 pub source_evidence_limit_fallbacks: u64,
108 pub source_evidence_peak_bytes: u64,
109 pub source_anchor_parses: u64,
110 pub source_anchor_asts: u64,
111 pub source_anchor_analyses: u64,
112 pub source_descendant_strings_avoided: u64,
113 pub source_descendant_events_avoided: u64,
114 pub source_descendant_analyses_avoided: u64,
115 pub source_compressed_families_prepared: u64,
116 pub source_compressed_cells_prepared: u64,
117 pub source_partitioned_families_seen: u64,
118 pub source_partitioned_families_prepared: u64,
119 pub source_partitioned_families_rejected: u64,
120 pub source_partition_fragments_prepared: u64,
121 pub source_partition_span_cells_prepared: u64,
122 pub source_partition_fallback_cells: u64,
123 pub source_partition_analyses_reused: u64,
124 pub source_partition_function_semantics: u64,
125 pub source_partition_holes: u64,
126 pub source_partition_ordinary_exceptions: u64,
127 pub source_partition_failures: u64,
128 pub source_partition_surviving_cells: u64,
129
130 pub fallback_reasons: BTreeMap<String, u64>,
131}
132
133impl Default for FormulaIngestReport {
134 fn default() -> Self {
135 Self {
136 mode: FormulaPlaneMode::Off,
137 formula_cells_seen: 0,
138 graph_formula_cells_materialized: 0,
139 shadow_candidate_cells: 0,
140 shadow_accepted_span_cells: 0,
141 shadow_fallback_cells: 0,
142 shadow_templates_interned: 0,
143 shadow_spans_created: 0,
144 graph_formula_vertices_avoided_shadow: 0,
145 ast_roots_avoided_shadow: 0,
146 edge_rows_avoided_shadow: 0,
147 graph_vertices_created: 0,
148 graph_edges_created: 0,
149 source_formula_events: 0,
150 source_formula_records_spooled: 0,
151 source_spool_encoded_bytes: 0,
152 source_spool_peak_memory_bytes: 0,
153 source_spool_spilled_bytes: 0,
154 source_spool_spill_files: 0,
155 source_spool_replays: 0,
156 source_ordinary_events: 0,
157 source_shared_anchor_events: 0,
158 source_shared_descendant_events: 0,
159 source_unknown_events: 0,
160 source_families_seen: 0,
161 source_family_cells_seen: 0,
162 source_family_shadow_eligible: 0,
163 source_family_shadow_eligible_cells: 0,
164 source_family_promoted: 0,
165 source_family_promoted_cells: 0,
166 source_family_fallback: 0,
167 source_family_fallback_cells: 0,
168 source_forward_descendants: 0,
169 source_evidence_limit_fallbacks: 0,
170 source_evidence_peak_bytes: 0,
171 source_anchor_parses: 0,
172 source_anchor_asts: 0,
173 source_anchor_analyses: 0,
174 source_descendant_strings_avoided: 0,
175 source_descendant_events_avoided: 0,
176 source_descendant_analyses_avoided: 0,
177 source_compressed_families_prepared: 0,
178 source_compressed_cells_prepared: 0,
179 source_partitioned_families_seen: 0,
180 source_partitioned_families_prepared: 0,
181 source_partitioned_families_rejected: 0,
182 source_partition_fragments_prepared: 0,
183 source_partition_span_cells_prepared: 0,
184 source_partition_fallback_cells: 0,
185 source_partition_analyses_reused: 0,
186 source_partition_function_semantics: 0,
187 source_partition_holes: 0,
188 source_partition_ordinary_exceptions: 0,
189 source_partition_failures: 0,
190 source_partition_surviving_cells: 0,
191 fallback_reasons: BTreeMap::new(),
192 }
193 }
194}
195
196impl FormulaIngestReport {
197 pub(crate) fn with_mode(mode: FormulaPlaneMode) -> Self {
198 Self {
199 mode,
200 ..Self::default()
201 }
202 }
203
204 pub(crate) fn accumulate(&mut self, other: &Self) {
205 self.formula_cells_seen = self
206 .formula_cells_seen
207 .saturating_add(other.formula_cells_seen);
208 self.graph_formula_cells_materialized = self
209 .graph_formula_cells_materialized
210 .saturating_add(other.graph_formula_cells_materialized);
211 self.shadow_candidate_cells = self
212 .shadow_candidate_cells
213 .saturating_add(other.shadow_candidate_cells);
214 self.shadow_accepted_span_cells = self
215 .shadow_accepted_span_cells
216 .saturating_add(other.shadow_accepted_span_cells);
217 self.shadow_fallback_cells = self
218 .shadow_fallback_cells
219 .saturating_add(other.shadow_fallback_cells);
220 self.shadow_templates_interned = self
221 .shadow_templates_interned
222 .saturating_add(other.shadow_templates_interned);
223 self.shadow_spans_created = self
224 .shadow_spans_created
225 .saturating_add(other.shadow_spans_created);
226 self.graph_formula_vertices_avoided_shadow = self
227 .graph_formula_vertices_avoided_shadow
228 .saturating_add(other.graph_formula_vertices_avoided_shadow);
229 self.ast_roots_avoided_shadow = self
230 .ast_roots_avoided_shadow
231 .saturating_add(other.ast_roots_avoided_shadow);
232 self.edge_rows_avoided_shadow = self
233 .edge_rows_avoided_shadow
234 .saturating_add(other.edge_rows_avoided_shadow);
235 self.graph_vertices_created = self
236 .graph_vertices_created
237 .saturating_add(other.graph_vertices_created);
238 self.graph_edges_created = self
239 .graph_edges_created
240 .saturating_add(other.graph_edges_created);
241 self.source_formula_events = self
242 .source_formula_events
243 .saturating_add(other.source_formula_events);
244 self.source_formula_records_spooled = self
245 .source_formula_records_spooled
246 .saturating_add(other.source_formula_records_spooled);
247 self.source_spool_encoded_bytes = self
248 .source_spool_encoded_bytes
249 .saturating_add(other.source_spool_encoded_bytes);
250 self.source_spool_peak_memory_bytes = self
251 .source_spool_peak_memory_bytes
252 .max(other.source_spool_peak_memory_bytes);
253 self.source_spool_spilled_bytes = self
254 .source_spool_spilled_bytes
255 .saturating_add(other.source_spool_spilled_bytes);
256 self.source_spool_spill_files = self
257 .source_spool_spill_files
258 .saturating_add(other.source_spool_spill_files);
259 self.source_spool_replays = self
260 .source_spool_replays
261 .saturating_add(other.source_spool_replays);
262 self.source_ordinary_events = self
263 .source_ordinary_events
264 .saturating_add(other.source_ordinary_events);
265 self.source_shared_anchor_events = self
266 .source_shared_anchor_events
267 .saturating_add(other.source_shared_anchor_events);
268 self.source_shared_descendant_events = self
269 .source_shared_descendant_events
270 .saturating_add(other.source_shared_descendant_events);
271 self.source_unknown_events = self
272 .source_unknown_events
273 .saturating_add(other.source_unknown_events);
274 self.source_families_seen = self
275 .source_families_seen
276 .saturating_add(other.source_families_seen);
277 self.source_family_cells_seen = self
278 .source_family_cells_seen
279 .saturating_add(other.source_family_cells_seen);
280 self.source_family_shadow_eligible = self
281 .source_family_shadow_eligible
282 .saturating_add(other.source_family_shadow_eligible);
283 self.source_family_shadow_eligible_cells = self
284 .source_family_shadow_eligible_cells
285 .saturating_add(other.source_family_shadow_eligible_cells);
286 self.source_family_promoted = self
287 .source_family_promoted
288 .saturating_add(other.source_family_promoted);
289 self.source_family_promoted_cells = self
290 .source_family_promoted_cells
291 .saturating_add(other.source_family_promoted_cells);
292 self.source_family_fallback = self
293 .source_family_fallback
294 .saturating_add(other.source_family_fallback);
295 self.source_family_fallback_cells = self
296 .source_family_fallback_cells
297 .saturating_add(other.source_family_fallback_cells);
298 self.source_forward_descendants = self
299 .source_forward_descendants
300 .saturating_add(other.source_forward_descendants);
301 self.source_evidence_limit_fallbacks = self
302 .source_evidence_limit_fallbacks
303 .saturating_add(other.source_evidence_limit_fallbacks);
304 self.source_evidence_peak_bytes = self
305 .source_evidence_peak_bytes
306 .max(other.source_evidence_peak_bytes);
307 self.source_anchor_parses = self
308 .source_anchor_parses
309 .saturating_add(other.source_anchor_parses);
310 self.source_anchor_asts = self
311 .source_anchor_asts
312 .saturating_add(other.source_anchor_asts);
313 self.source_anchor_analyses = self
314 .source_anchor_analyses
315 .saturating_add(other.source_anchor_analyses);
316 self.source_descendant_strings_avoided = self
317 .source_descendant_strings_avoided
318 .saturating_add(other.source_descendant_strings_avoided);
319 self.source_descendant_events_avoided = self
320 .source_descendant_events_avoided
321 .saturating_add(other.source_descendant_events_avoided);
322 self.source_descendant_analyses_avoided = self
323 .source_descendant_analyses_avoided
324 .saturating_add(other.source_descendant_analyses_avoided);
325 self.source_compressed_families_prepared = self
326 .source_compressed_families_prepared
327 .saturating_add(other.source_compressed_families_prepared);
328 self.source_compressed_cells_prepared = self
329 .source_compressed_cells_prepared
330 .saturating_add(other.source_compressed_cells_prepared);
331 self.source_partitioned_families_seen = self
332 .source_partitioned_families_seen
333 .saturating_add(other.source_partitioned_families_seen);
334 self.source_partitioned_families_prepared = self
335 .source_partitioned_families_prepared
336 .saturating_add(other.source_partitioned_families_prepared);
337 self.source_partitioned_families_rejected = self
338 .source_partitioned_families_rejected
339 .saturating_add(other.source_partitioned_families_rejected);
340 self.source_partition_fragments_prepared = self
341 .source_partition_fragments_prepared
342 .saturating_add(other.source_partition_fragments_prepared);
343 self.source_partition_span_cells_prepared = self
344 .source_partition_span_cells_prepared
345 .saturating_add(other.source_partition_span_cells_prepared);
346 self.source_partition_fallback_cells = self
347 .source_partition_fallback_cells
348 .saturating_add(other.source_partition_fallback_cells);
349 self.source_partition_analyses_reused = self
350 .source_partition_analyses_reused
351 .saturating_add(other.source_partition_analyses_reused);
352 self.source_partition_function_semantics = self
353 .source_partition_function_semantics
354 .saturating_add(other.source_partition_function_semantics);
355 self.source_partition_holes = self
356 .source_partition_holes
357 .saturating_add(other.source_partition_holes);
358 self.source_partition_ordinary_exceptions = self
359 .source_partition_ordinary_exceptions
360 .saturating_add(other.source_partition_ordinary_exceptions);
361 self.source_partition_failures = self
362 .source_partition_failures
363 .saturating_add(other.source_partition_failures);
364 self.source_partition_surviving_cells = self
365 .source_partition_surviving_cells
366 .saturating_add(other.source_partition_surviving_cells);
367 for (reason, count) in &other.fallback_reasons {
368 let total = self.fallback_reasons.entry(reason.clone()).or_default();
369 *total = total.saturating_add(*count);
370 }
371 }
372}