icydb_core/db/diagnostics/
model.rs1use crate::db::index::IndexState;
7use candid::CandidType;
8use serde::Deserialize;
9
10#[cfg_attr(doc, doc = "StorageReport\n\nLive storage snapshot payload.")]
11#[derive(CandidType, Clone, Debug, Default, Deserialize)]
12pub struct StorageReport {
13 pub(crate) storage_data: Vec<DataStoreSnapshot>,
14 pub(crate) storage_index: Vec<IndexStoreSnapshot>,
15 pub(crate) entity_storage: Vec<EntitySnapshot>,
16 pub(crate) corrupted_keys: u64,
17 pub(crate) corrupted_entries: u64,
18}
19
20#[cfg_attr(
21 doc,
22 doc = "IntegrityTotals\n\nAggregated integrity-scan counters across all stores."
23)]
24#[derive(CandidType, Clone, Debug, Default, Deserialize)]
25pub struct IntegrityTotals {
26 pub(crate) data_rows_scanned: u64,
27 pub(crate) index_entries_scanned: u64,
28 pub(crate) corrupted_data_keys: u64,
29 pub(crate) corrupted_data_rows: u64,
30 pub(crate) corrupted_index_keys: u64,
31 pub(crate) corrupted_index_entries: u64,
32 pub(crate) missing_index_entries: u64,
33 pub(crate) divergent_index_entries: u64,
34 pub(crate) orphan_index_references: u64,
35 pub(crate) misuse_findings: u64,
36}
37
38impl IntegrityTotals {
39 pub(super) const fn add_store_snapshot(&mut self, store: &IntegrityStoreSnapshot) {
40 self.data_rows_scanned = self
41 .data_rows_scanned
42 .saturating_add(store.data_rows_scanned);
43 self.index_entries_scanned = self
44 .index_entries_scanned
45 .saturating_add(store.index_entries_scanned);
46 self.corrupted_data_keys = self
47 .corrupted_data_keys
48 .saturating_add(store.corrupted_data_keys);
49 self.corrupted_data_rows = self
50 .corrupted_data_rows
51 .saturating_add(store.corrupted_data_rows);
52 self.corrupted_index_keys = self
53 .corrupted_index_keys
54 .saturating_add(store.corrupted_index_keys);
55 self.corrupted_index_entries = self
56 .corrupted_index_entries
57 .saturating_add(store.corrupted_index_entries);
58 self.missing_index_entries = self
59 .missing_index_entries
60 .saturating_add(store.missing_index_entries);
61 self.divergent_index_entries = self
62 .divergent_index_entries
63 .saturating_add(store.divergent_index_entries);
64 self.orphan_index_references = self
65 .orphan_index_references
66 .saturating_add(store.orphan_index_references);
67 self.misuse_findings = self.misuse_findings.saturating_add(store.misuse_findings);
68 }
69
70 #[must_use]
72 pub const fn data_rows_scanned(&self) -> u64 {
73 self.data_rows_scanned
74 }
75
76 #[must_use]
78 pub const fn index_entries_scanned(&self) -> u64 {
79 self.index_entries_scanned
80 }
81
82 #[must_use]
84 pub const fn corrupted_data_keys(&self) -> u64 {
85 self.corrupted_data_keys
86 }
87
88 #[must_use]
90 pub const fn corrupted_data_rows(&self) -> u64 {
91 self.corrupted_data_rows
92 }
93
94 #[must_use]
96 pub const fn corrupted_index_keys(&self) -> u64 {
97 self.corrupted_index_keys
98 }
99
100 #[must_use]
102 pub const fn corrupted_index_entries(&self) -> u64 {
103 self.corrupted_index_entries
104 }
105
106 #[must_use]
108 pub const fn missing_index_entries(&self) -> u64 {
109 self.missing_index_entries
110 }
111
112 #[must_use]
114 pub const fn divergent_index_entries(&self) -> u64 {
115 self.divergent_index_entries
116 }
117
118 #[must_use]
120 pub const fn orphan_index_references(&self) -> u64 {
121 self.orphan_index_references
122 }
123
124 #[must_use]
126 pub const fn misuse_findings(&self) -> u64 {
127 self.misuse_findings
128 }
129}
130
131#[cfg_attr(
132 doc,
133 doc = "IntegrityStoreSnapshot\n\nPer-store integrity findings and scan counters."
134)]
135#[derive(CandidType, Clone, Debug, Default, Deserialize)]
136pub struct IntegrityStoreSnapshot {
137 pub(crate) path: String,
138 pub(crate) data_rows_scanned: u64,
139 pub(crate) index_entries_scanned: u64,
140 pub(crate) corrupted_data_keys: u64,
141 pub(crate) corrupted_data_rows: u64,
142 pub(crate) corrupted_index_keys: u64,
143 pub(crate) corrupted_index_entries: u64,
144 pub(crate) missing_index_entries: u64,
145 pub(crate) divergent_index_entries: u64,
146 pub(crate) orphan_index_references: u64,
147 pub(crate) misuse_findings: u64,
148}
149
150impl IntegrityStoreSnapshot {
151 #[must_use]
153 pub(crate) fn new(path: String) -> Self {
154 Self {
155 path,
156 ..Self::default()
157 }
158 }
159
160 #[must_use]
162 pub const fn path(&self) -> &str {
163 self.path.as_str()
164 }
165
166 #[must_use]
168 pub const fn data_rows_scanned(&self) -> u64 {
169 self.data_rows_scanned
170 }
171
172 #[must_use]
174 pub const fn index_entries_scanned(&self) -> u64 {
175 self.index_entries_scanned
176 }
177
178 #[must_use]
180 pub const fn corrupted_data_keys(&self) -> u64 {
181 self.corrupted_data_keys
182 }
183
184 #[must_use]
186 pub const fn corrupted_data_rows(&self) -> u64 {
187 self.corrupted_data_rows
188 }
189
190 #[must_use]
192 pub const fn corrupted_index_keys(&self) -> u64 {
193 self.corrupted_index_keys
194 }
195
196 #[must_use]
198 pub const fn corrupted_index_entries(&self) -> u64 {
199 self.corrupted_index_entries
200 }
201
202 #[must_use]
204 pub const fn missing_index_entries(&self) -> u64 {
205 self.missing_index_entries
206 }
207
208 #[must_use]
210 pub const fn divergent_index_entries(&self) -> u64 {
211 self.divergent_index_entries
212 }
213
214 #[must_use]
216 pub const fn orphan_index_references(&self) -> u64 {
217 self.orphan_index_references
218 }
219
220 #[must_use]
222 pub const fn misuse_findings(&self) -> u64 {
223 self.misuse_findings
224 }
225}
226
227#[cfg_attr(
228 doc,
229 doc = "IntegrityReport\n\nFull integrity-scan output across all registered stores."
230)]
231#[derive(CandidType, Clone, Debug, Default, Deserialize)]
232pub struct IntegrityReport {
233 pub(crate) stores: Vec<IntegrityStoreSnapshot>,
234 pub(crate) totals: IntegrityTotals,
235}
236
237impl IntegrityReport {
238 #[must_use]
240 pub(crate) const fn new(stores: Vec<IntegrityStoreSnapshot>, totals: IntegrityTotals) -> Self {
241 Self { stores, totals }
242 }
243
244 #[must_use]
246 pub const fn stores(&self) -> &[IntegrityStoreSnapshot] {
247 self.stores.as_slice()
248 }
249
250 #[must_use]
252 pub const fn totals(&self) -> &IntegrityTotals {
253 &self.totals
254 }
255}
256
257impl StorageReport {
258 #[must_use]
260 pub(crate) const fn new(
261 storage_data: Vec<DataStoreSnapshot>,
262 storage_index: Vec<IndexStoreSnapshot>,
263 entity_storage: Vec<EntitySnapshot>,
264 corrupted_keys: u64,
265 corrupted_entries: u64,
266 ) -> Self {
267 Self {
268 storage_data,
269 storage_index,
270 entity_storage,
271 corrupted_keys,
272 corrupted_entries,
273 }
274 }
275
276 #[must_use]
278 pub const fn storage_data(&self) -> &[DataStoreSnapshot] {
279 self.storage_data.as_slice()
280 }
281
282 #[must_use]
284 pub const fn storage_index(&self) -> &[IndexStoreSnapshot] {
285 self.storage_index.as_slice()
286 }
287
288 #[must_use]
290 pub const fn entity_storage(&self) -> &[EntitySnapshot] {
291 self.entity_storage.as_slice()
292 }
293
294 #[must_use]
296 pub const fn corrupted_keys(&self) -> u64 {
297 self.corrupted_keys
298 }
299
300 #[must_use]
302 pub const fn corrupted_entries(&self) -> u64 {
303 self.corrupted_entries
304 }
305}
306
307#[cfg_attr(doc, doc = "DataStoreSnapshot\n\nData-store snapshot row.")]
308#[derive(CandidType, Clone, Debug, Default, Deserialize)]
309pub struct DataStoreSnapshot {
310 pub(crate) path: String,
311 pub(crate) entries: u64,
312 pub(crate) memory_bytes: u64,
313}
314
315impl DataStoreSnapshot {
316 #[must_use]
318 pub(crate) const fn new(path: String, entries: u64, memory_bytes: u64) -> Self {
319 Self {
320 path,
321 entries,
322 memory_bytes,
323 }
324 }
325
326 #[must_use]
328 pub const fn path(&self) -> &str {
329 self.path.as_str()
330 }
331
332 #[must_use]
334 pub const fn entries(&self) -> u64 {
335 self.entries
336 }
337
338 #[must_use]
340 pub const fn memory_bytes(&self) -> u64 {
341 self.memory_bytes
342 }
343}
344
345#[cfg_attr(doc, doc = "IndexStoreSnapshot\n\nIndex-store snapshot row.")]
346#[derive(CandidType, Clone, Debug, Default, Deserialize)]
347pub struct IndexStoreSnapshot {
348 pub(crate) path: String,
349 pub(crate) entries: u64,
350 pub(crate) user_entries: u64,
351 pub(crate) system_entries: u64,
352 pub(crate) memory_bytes: u64,
353 pub(crate) state: IndexState,
354}
355
356impl IndexStoreSnapshot {
357 #[must_use]
359 pub(crate) const fn new(
360 path: String,
361 entries: u64,
362 user_entries: u64,
363 system_entries: u64,
364 memory_bytes: u64,
365 state: IndexState,
366 ) -> Self {
367 Self {
368 path,
369 entries,
370 user_entries,
371 system_entries,
372 memory_bytes,
373 state,
374 }
375 }
376
377 #[must_use]
379 pub const fn path(&self) -> &str {
380 self.path.as_str()
381 }
382
383 #[must_use]
385 pub const fn entries(&self) -> u64 {
386 self.entries
387 }
388
389 #[must_use]
391 pub const fn user_entries(&self) -> u64 {
392 self.user_entries
393 }
394
395 #[must_use]
397 pub const fn system_entries(&self) -> u64 {
398 self.system_entries
399 }
400
401 #[must_use]
403 pub const fn memory_bytes(&self) -> u64 {
404 self.memory_bytes
405 }
406
407 #[must_use]
410 pub const fn state(&self) -> IndexState {
411 self.state
412 }
413}
414
415#[cfg_attr(doc, doc = "EntitySnapshot\n\nPer-entity storage snapshot row.")]
416#[derive(CandidType, Clone, Debug, Default, Deserialize)]
417pub struct EntitySnapshot {
418 pub(crate) store: String,
419
420 pub(crate) path: String,
421
422 pub(crate) entries: u64,
423
424 pub(crate) memory_bytes: u64,
425}
426
427impl EntitySnapshot {
428 #[must_use]
430 pub(crate) const fn new(store: String, path: String, entries: u64, memory_bytes: u64) -> Self {
431 Self {
432 store,
433 path,
434 entries,
435 memory_bytes,
436 }
437 }
438
439 #[must_use]
441 pub const fn store(&self) -> &str {
442 self.store.as_str()
443 }
444
445 #[must_use]
447 pub const fn path(&self) -> &str {
448 self.path.as_str()
449 }
450
451 #[must_use]
453 pub const fn entries(&self) -> u64 {
454 self.entries
455 }
456
457 #[must_use]
459 pub const fn memory_bytes(&self) -> u64 {
460 self.memory_bytes
461 }
462}