Skip to main content

icydb_core/db/diagnostics/
model.rs

1//! Module: diagnostics::model
2//! Responsibility: diagnostics report DTO contracts and simple accessors.
3//! Does not own: store traversal, integrity scanning, or execution trace policy.
4//! Boundary: report assembly modules construct these DTOs; public callers read them.
5
6use crate::db::{
7    index::IndexState,
8    registry::{
9        StoreAllocationIdentityCapability, StoreCommitParticipation, StoreDurability,
10        StoreRecoveryCapability, StoreRuntimeStorageCapabilities, StoreSchemaMetadataCapability,
11    },
12};
13use candid::CandidType;
14use serde::Deserialize;
15
16#[cfg_attr(doc, doc = "StorageReport\n\nLive storage snapshot payload.")]
17#[derive(CandidType, Clone, Debug, Default, Deserialize)]
18pub struct StorageReport {
19    pub(crate) storage_data: Vec<DataStoreSnapshot>,
20    pub(crate) storage_index: Vec<IndexStoreSnapshot>,
21    pub(crate) schema_storage: Vec<SchemaStoreSnapshot>,
22    pub(crate) entity_storage: Vec<EntitySnapshot>,
23    pub(crate) corrupted_keys: u64,
24    pub(crate) corrupted_entries: u64,
25}
26
27#[cfg_attr(
28    doc,
29    doc = "IntegrityTotals\n\nAggregated integrity-scan counters across all stores."
30)]
31#[derive(CandidType, Clone, Debug, Default, Deserialize)]
32pub struct IntegrityTotals {
33    pub(crate) data_rows_scanned: u64,
34    pub(crate) index_entries_scanned: u64,
35    pub(crate) corrupted_data_keys: u64,
36    pub(crate) corrupted_data_rows: u64,
37    pub(crate) corrupted_index_keys: u64,
38    pub(crate) corrupted_index_entries: u64,
39    pub(crate) missing_index_entries: u64,
40    pub(crate) divergent_index_entries: u64,
41    pub(crate) orphan_index_references: u64,
42    pub(crate) misuse_findings: u64,
43}
44
45impl IntegrityTotals {
46    pub(super) const fn add_store_snapshot(&mut self, store: &IntegrityStoreSnapshot) {
47        self.data_rows_scanned = self
48            .data_rows_scanned
49            .saturating_add(store.data_rows_scanned);
50        self.index_entries_scanned = self
51            .index_entries_scanned
52            .saturating_add(store.index_entries_scanned);
53        self.corrupted_data_keys = self
54            .corrupted_data_keys
55            .saturating_add(store.corrupted_data_keys);
56        self.corrupted_data_rows = self
57            .corrupted_data_rows
58            .saturating_add(store.corrupted_data_rows);
59        self.corrupted_index_keys = self
60            .corrupted_index_keys
61            .saturating_add(store.corrupted_index_keys);
62        self.corrupted_index_entries = self
63            .corrupted_index_entries
64            .saturating_add(store.corrupted_index_entries);
65        self.missing_index_entries = self
66            .missing_index_entries
67            .saturating_add(store.missing_index_entries);
68        self.divergent_index_entries = self
69            .divergent_index_entries
70            .saturating_add(store.divergent_index_entries);
71        self.orphan_index_references = self
72            .orphan_index_references
73            .saturating_add(store.orphan_index_references);
74        self.misuse_findings = self.misuse_findings.saturating_add(store.misuse_findings);
75    }
76
77    /// Return total number of data rows scanned.
78    #[must_use]
79    pub const fn data_rows_scanned(&self) -> u64 {
80        self.data_rows_scanned
81    }
82
83    /// Return total number of index entries scanned.
84    #[must_use]
85    pub const fn index_entries_scanned(&self) -> u64 {
86        self.index_entries_scanned
87    }
88
89    /// Return total number of corrupted data-key findings.
90    #[must_use]
91    pub const fn corrupted_data_keys(&self) -> u64 {
92        self.corrupted_data_keys
93    }
94
95    /// Return total number of corrupted data-row findings.
96    #[must_use]
97    pub const fn corrupted_data_rows(&self) -> u64 {
98        self.corrupted_data_rows
99    }
100
101    /// Return total number of corrupted index-key findings.
102    #[must_use]
103    pub const fn corrupted_index_keys(&self) -> u64 {
104        self.corrupted_index_keys
105    }
106
107    /// Return total number of corrupted index-entry findings.
108    #[must_use]
109    pub const fn corrupted_index_entries(&self) -> u64 {
110        self.corrupted_index_entries
111    }
112
113    /// Return total number of missing index-entry findings.
114    #[must_use]
115    pub const fn missing_index_entries(&self) -> u64 {
116        self.missing_index_entries
117    }
118
119    /// Return total number of divergent index-entry findings.
120    #[must_use]
121    pub const fn divergent_index_entries(&self) -> u64 {
122        self.divergent_index_entries
123    }
124
125    /// Return total number of orphan index-reference findings.
126    #[must_use]
127    pub const fn orphan_index_references(&self) -> u64 {
128        self.orphan_index_references
129    }
130
131    /// Return total number of misuse findings.
132    #[must_use]
133    pub const fn misuse_findings(&self) -> u64 {
134        self.misuse_findings
135    }
136}
137
138#[cfg_attr(
139    doc,
140    doc = "IntegrityStoreSnapshot\n\nPer-store integrity findings and scan counters."
141)]
142#[derive(CandidType, Clone, Debug, Default, Deserialize)]
143pub struct IntegrityStoreSnapshot {
144    pub(crate) path: String,
145    pub(crate) data_rows_scanned: u64,
146    pub(crate) index_entries_scanned: u64,
147    pub(crate) corrupted_data_keys: u64,
148    pub(crate) corrupted_data_rows: u64,
149    pub(crate) corrupted_index_keys: u64,
150    pub(crate) corrupted_index_entries: u64,
151    pub(crate) missing_index_entries: u64,
152    pub(crate) divergent_index_entries: u64,
153    pub(crate) orphan_index_references: u64,
154    pub(crate) misuse_findings: u64,
155}
156
157impl IntegrityStoreSnapshot {
158    /// Construct one empty store-level integrity snapshot.
159    #[must_use]
160    pub(super) fn new(path: String) -> Self {
161        Self {
162            path,
163            ..Self::default()
164        }
165    }
166
167    /// Borrow store path.
168    #[must_use]
169    pub const fn path(&self) -> &str {
170        self.path.as_str()
171    }
172
173    /// Return number of scanned data rows.
174    #[must_use]
175    pub const fn data_rows_scanned(&self) -> u64 {
176        self.data_rows_scanned
177    }
178
179    /// Return number of scanned index entries.
180    #[must_use]
181    pub const fn index_entries_scanned(&self) -> u64 {
182        self.index_entries_scanned
183    }
184
185    /// Return number of corrupted data-key findings.
186    #[must_use]
187    pub const fn corrupted_data_keys(&self) -> u64 {
188        self.corrupted_data_keys
189    }
190
191    /// Return number of corrupted data-row findings.
192    #[must_use]
193    pub const fn corrupted_data_rows(&self) -> u64 {
194        self.corrupted_data_rows
195    }
196
197    /// Return number of corrupted index-key findings.
198    #[must_use]
199    pub const fn corrupted_index_keys(&self) -> u64 {
200        self.corrupted_index_keys
201    }
202
203    /// Return number of corrupted index-entry findings.
204    #[must_use]
205    pub const fn corrupted_index_entries(&self) -> u64 {
206        self.corrupted_index_entries
207    }
208
209    /// Return number of missing index-entry findings.
210    #[must_use]
211    pub const fn missing_index_entries(&self) -> u64 {
212        self.missing_index_entries
213    }
214
215    /// Return number of divergent index-entry findings.
216    #[must_use]
217    pub const fn divergent_index_entries(&self) -> u64 {
218        self.divergent_index_entries
219    }
220
221    /// Return number of orphan index-reference findings.
222    #[must_use]
223    pub const fn orphan_index_references(&self) -> u64 {
224        self.orphan_index_references
225    }
226
227    /// Return number of misuse findings.
228    #[must_use]
229    pub const fn misuse_findings(&self) -> u64 {
230        self.misuse_findings
231    }
232}
233
234#[cfg_attr(
235    doc,
236    doc = "IntegrityReport\n\nFull integrity-scan output across all registered stores."
237)]
238#[derive(CandidType, Clone, Debug, Default, Deserialize)]
239pub struct IntegrityReport {
240    pub(crate) stores: Vec<IntegrityStoreSnapshot>,
241    pub(crate) totals: IntegrityTotals,
242}
243
244impl IntegrityReport {
245    /// Construct one integrity report payload.
246    #[must_use]
247    pub(super) const fn new(stores: Vec<IntegrityStoreSnapshot>, totals: IntegrityTotals) -> Self {
248        Self { stores, totals }
249    }
250
251    /// Borrow per-store integrity snapshots.
252    #[must_use]
253    pub const fn stores(&self) -> &[IntegrityStoreSnapshot] {
254        self.stores.as_slice()
255    }
256
257    /// Borrow aggregated integrity totals.
258    #[must_use]
259    pub const fn totals(&self) -> &IntegrityTotals {
260        &self.totals
261    }
262}
263
264impl StorageReport {
265    /// Construct one storage report payload.
266    #[must_use]
267    pub(super) const fn new(
268        storage_data: Vec<DataStoreSnapshot>,
269        storage_index: Vec<IndexStoreSnapshot>,
270        schema_storage: Vec<SchemaStoreSnapshot>,
271        entity_storage: Vec<EntitySnapshot>,
272        corrupted_keys: u64,
273        corrupted_entries: u64,
274    ) -> Self {
275        Self {
276            storage_data,
277            storage_index,
278            schema_storage,
279            entity_storage,
280            corrupted_keys,
281            corrupted_entries,
282        }
283    }
284
285    /// Borrow data-store snapshots.
286    #[must_use]
287    pub const fn storage_data(&self) -> &[DataStoreSnapshot] {
288        self.storage_data.as_slice()
289    }
290
291    /// Borrow index-store snapshots.
292    #[must_use]
293    pub const fn storage_index(&self) -> &[IndexStoreSnapshot] {
294        self.storage_index.as_slice()
295    }
296
297    /// Borrow schema-store snapshots.
298    #[must_use]
299    pub const fn schema_storage(&self) -> &[SchemaStoreSnapshot] {
300        self.schema_storage.as_slice()
301    }
302
303    /// Borrow entity-level storage snapshots.
304    #[must_use]
305    pub const fn entity_storage(&self) -> &[EntitySnapshot] {
306        self.entity_storage.as_slice()
307    }
308
309    /// Return count of corrupted decoded data keys.
310    #[must_use]
311    pub const fn corrupted_keys(&self) -> u64 {
312        self.corrupted_keys
313    }
314
315    /// Return count of corrupted index entries.
316    #[must_use]
317    pub const fn corrupted_entries(&self) -> u64 {
318        self.corrupted_entries
319    }
320}
321
322#[cfg_attr(doc, doc = "SchemaStoreSnapshot\n\nSchema-store diagnostic row.")]
323#[derive(CandidType, Clone, Debug, Default, Deserialize)]
324pub struct SchemaStoreSnapshot {
325    pub(crate) path: String,
326    pub(crate) storage: StoreSnapshotStorageMode,
327    pub(crate) allocation: StoreAllocationIdentityCapability,
328    pub(crate) durability: StoreDurability,
329    pub(crate) commit: StoreCommitParticipation,
330    pub(crate) recovery: StoreRecoveryCapability,
331    pub(crate) schema_metadata: StoreSchemaMetadataCapability,
332    pub(crate) memory_id: Option<u8>,
333    pub(crate) stable_key: Option<String>,
334    pub(crate) schema_version: Option<u32>,
335    pub(crate) schema_fingerprint_method_version: Option<u8>,
336    pub(crate) schema_fingerprint: Option<String>,
337    pub(crate) entity_count: u64,
338}
339
340/// Diagnostic storage mode reported for one store-role snapshot.
341///
342/// This is observability metadata only. It does not participate in allocation
343/// identity, stable-key generation, or durable row/index/schema storage ABI.
344#[derive(CandidType, Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq)]
345pub enum StoreSnapshotStorageMode {
346    Heap,
347    #[default]
348    Journaled,
349}
350
351impl StoreSnapshotStorageMode {
352    /// Return the user-facing storage mode label.
353    #[must_use]
354    pub const fn as_str(self) -> &'static str {
355        match self {
356            Self::Heap => "heap",
357            Self::Journaled => "journaled",
358        }
359    }
360}
361
362#[derive(Clone, Debug, Eq, PartialEq)]
363pub(super) struct StoreSnapshotAllocationIdentity {
364    memory_id: u8,
365    stable_key: String,
366}
367
368impl StoreSnapshotAllocationIdentity {
369    pub(super) const fn new(memory_id: u8, stable_key: String) -> Self {
370        Self {
371            memory_id,
372            stable_key,
373        }
374    }
375
376    const fn memory_id(&self) -> u8 {
377        self.memory_id
378    }
379}
380
381#[derive(Clone, Debug, Default, Eq, PartialEq)]
382pub(super) struct StoreSnapshotSchemaMetadata {
383    version: Option<u32>,
384    fingerprint_method_version: Option<u8>,
385    fingerprint: Option<String>,
386}
387
388impl StoreSnapshotSchemaMetadata {
389    pub(super) const fn absent() -> Self {
390        Self {
391            version: None,
392            fingerprint_method_version: None,
393            fingerprint: None,
394        }
395    }
396
397    pub(super) const fn new(
398        schema_version: u32,
399        schema_fingerprint_method_version: u8,
400        schema_fingerprint: String,
401    ) -> Self {
402        Self {
403            version: Some(schema_version),
404            fingerprint_method_version: Some(schema_fingerprint_method_version),
405            fingerprint: Some(schema_fingerprint),
406        }
407    }
408
409    const fn schema_version(&self) -> Option<u32> {
410        self.version
411    }
412
413    const fn schema_fingerprint_method_version(&self) -> Option<u8> {
414        self.fingerprint_method_version
415    }
416
417    fn schema_fingerprint(&self) -> Option<String> {
418        self.fingerprint.clone()
419    }
420}
421
422#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
423pub(super) struct IndexStoreSnapshotStats {
424    entries: u64,
425    user_entries: u64,
426    system_entries: u64,
427    memory_bytes: u64,
428    state: IndexState,
429}
430
431impl IndexStoreSnapshotStats {
432    pub(super) const fn new(
433        entries: u64,
434        user_entries: u64,
435        system_entries: u64,
436        memory_bytes: u64,
437        state: IndexState,
438    ) -> Self {
439        Self {
440            entries,
441            user_entries,
442            system_entries,
443            memory_bytes,
444            state,
445        }
446    }
447}
448
449impl SchemaStoreSnapshot {
450    /// Construct one schema-store diagnostic row.
451    #[must_use]
452    pub(super) fn new(
453        path: String,
454        storage: StoreSnapshotStorageMode,
455        capabilities: StoreRuntimeStorageCapabilities,
456        allocation: Option<StoreSnapshotAllocationIdentity>,
457        schema_metadata: StoreSnapshotSchemaMetadata,
458        entity_count: u64,
459    ) -> Self {
460        let memory_id = allocation
461            .as_ref()
462            .map(StoreSnapshotAllocationIdentity::memory_id);
463        let stable_key = match allocation {
464            Some(allocation) => Some(allocation.stable_key),
465            None => None,
466        };
467        Self {
468            path,
469            storage,
470            allocation: capabilities.allocation_identity(),
471            durability: capabilities.durability(),
472            commit: capabilities.commit_participation(),
473            recovery: capabilities.recovery(),
474            schema_metadata: capabilities.schema_metadata(),
475            memory_id,
476            stable_key,
477            schema_version: schema_metadata.schema_version(),
478            schema_fingerprint_method_version: schema_metadata.schema_fingerprint_method_version(),
479            schema_fingerprint: schema_metadata.schema_fingerprint(),
480            entity_count,
481        }
482    }
483
484    /// Borrow store path.
485    #[must_use]
486    pub const fn path(&self) -> &str {
487        self.path.as_str()
488    }
489
490    /// Return diagnostic storage mode.
491    #[must_use]
492    pub const fn storage(&self) -> StoreSnapshotStorageMode {
493        self.storage
494    }
495
496    /// Return allocation-identity capability metadata.
497    #[must_use]
498    pub const fn allocation(&self) -> StoreAllocationIdentityCapability {
499        self.allocation
500    }
501
502    /// Return durability capability metadata.
503    #[must_use]
504    pub const fn durability(&self) -> StoreDurability {
505        self.durability
506    }
507
508    /// Return commit participation capability metadata.
509    #[must_use]
510    pub const fn commit(&self) -> StoreCommitParticipation {
511        self.commit
512    }
513
514    /// Return recovery capability metadata.
515    #[must_use]
516    pub const fn recovery(&self) -> StoreRecoveryCapability {
517        self.recovery
518    }
519
520    /// Return schema-metadata persistence capability metadata.
521    #[must_use]
522    pub const fn schema_metadata(&self) -> StoreSchemaMetadataCapability {
523        self.schema_metadata
524    }
525
526    /// Return stable-memory manager ID, when generated wiring supplied it.
527    #[must_use]
528    pub const fn memory_id(&self) -> Option<u8> {
529        self.memory_id
530    }
531
532    /// Return durable stable-memory key, when generated wiring supplied it.
533    #[must_use]
534    pub const fn stable_key(&self) -> Option<&str> {
535        match &self.stable_key {
536            Some(value) => Some(value.as_str()),
537            None => None,
538        }
539    }
540
541    /// Return accepted schema/catalog version, when known.
542    #[must_use]
543    pub const fn schema_version(&self) -> Option<u32> {
544        self.schema_version
545    }
546
547    /// Return accepted schema/catalog fingerprint method version, when known.
548    #[must_use]
549    pub const fn schema_fingerprint_method_version(&self) -> Option<u8> {
550        self.schema_fingerprint_method_version
551    }
552
553    /// Return accepted schema/catalog fingerprint, when known.
554    #[must_use]
555    pub const fn schema_fingerprint(&self) -> Option<&str> {
556        match &self.schema_fingerprint {
557            Some(value) => Some(value.as_str()),
558            None => None,
559        }
560    }
561
562    /// Return number of entity schemas represented in this schema catalog.
563    #[must_use]
564    pub const fn entity_count(&self) -> u64 {
565        self.entity_count
566    }
567}
568
569#[cfg_attr(doc, doc = "DataStoreSnapshot\n\nData-store snapshot row.")]
570#[derive(CandidType, Clone, Debug, Default, Deserialize)]
571pub struct DataStoreSnapshot {
572    pub(crate) path: String,
573    pub(crate) storage: StoreSnapshotStorageMode,
574    pub(crate) allocation: StoreAllocationIdentityCapability,
575    pub(crate) durability: StoreDurability,
576    pub(crate) commit: StoreCommitParticipation,
577    pub(crate) recovery: StoreRecoveryCapability,
578    pub(crate) schema_metadata: StoreSchemaMetadataCapability,
579    pub(crate) memory_id: Option<u8>,
580    pub(crate) stable_key: Option<String>,
581    pub(crate) schema_version: Option<u32>,
582    pub(crate) schema_fingerprint_method_version: Option<u8>,
583    pub(crate) schema_fingerprint: Option<String>,
584    pub(crate) entries: u64,
585    pub(crate) memory_bytes: u64,
586}
587
588impl DataStoreSnapshot {
589    /// Construct one data-store snapshot row.
590    #[must_use]
591    pub(super) fn new(
592        path: String,
593        storage: StoreSnapshotStorageMode,
594        capabilities: StoreRuntimeStorageCapabilities,
595        allocation: Option<StoreSnapshotAllocationIdentity>,
596        schema_metadata: StoreSnapshotSchemaMetadata,
597        entries: u64,
598        memory_bytes: u64,
599    ) -> Self {
600        let memory_id = allocation
601            .as_ref()
602            .map(StoreSnapshotAllocationIdentity::memory_id);
603        let stable_key = match allocation {
604            Some(allocation) => Some(allocation.stable_key),
605            None => None,
606        };
607        Self {
608            path,
609            storage,
610            allocation: capabilities.allocation_identity(),
611            durability: capabilities.durability(),
612            commit: capabilities.commit_participation(),
613            recovery: capabilities.recovery(),
614            schema_metadata: capabilities.schema_metadata(),
615            memory_id,
616            stable_key,
617            schema_version: schema_metadata.schema_version(),
618            schema_fingerprint_method_version: schema_metadata.schema_fingerprint_method_version(),
619            schema_fingerprint: schema_metadata.schema_fingerprint(),
620            entries,
621            memory_bytes,
622        }
623    }
624
625    /// Borrow store path.
626    #[must_use]
627    pub const fn path(&self) -> &str {
628        self.path.as_str()
629    }
630
631    /// Return diagnostic storage mode.
632    #[must_use]
633    pub const fn storage(&self) -> StoreSnapshotStorageMode {
634        self.storage
635    }
636
637    /// Return allocation-identity capability metadata.
638    #[must_use]
639    pub const fn allocation(&self) -> StoreAllocationIdentityCapability {
640        self.allocation
641    }
642
643    /// Return durability capability metadata.
644    #[must_use]
645    pub const fn durability(&self) -> StoreDurability {
646        self.durability
647    }
648
649    /// Return commit participation capability metadata.
650    #[must_use]
651    pub const fn commit(&self) -> StoreCommitParticipation {
652        self.commit
653    }
654
655    /// Return recovery capability metadata.
656    #[must_use]
657    pub const fn recovery(&self) -> StoreRecoveryCapability {
658        self.recovery
659    }
660
661    /// Return schema-metadata persistence capability metadata.
662    #[must_use]
663    pub const fn schema_metadata(&self) -> StoreSchemaMetadataCapability {
664        self.schema_metadata
665    }
666
667    /// Return stable-memory manager ID, when generated wiring supplied it.
668    #[must_use]
669    pub const fn memory_id(&self) -> Option<u8> {
670        self.memory_id
671    }
672
673    /// Return durable stable-memory key, when generated wiring supplied it.
674    #[must_use]
675    pub const fn stable_key(&self) -> Option<&str> {
676        match &self.stable_key {
677            Some(value) => Some(value.as_str()),
678            None => None,
679        }
680    }
681
682    /// Return accepted schema/catalog version, when known.
683    #[must_use]
684    pub const fn schema_version(&self) -> Option<u32> {
685        self.schema_version
686    }
687
688    /// Return accepted schema/catalog fingerprint method version, when known.
689    #[must_use]
690    pub const fn schema_fingerprint_method_version(&self) -> Option<u8> {
691        self.schema_fingerprint_method_version
692    }
693
694    /// Return accepted schema/catalog fingerprint, when known.
695    #[must_use]
696    pub const fn schema_fingerprint(&self) -> Option<&str> {
697        match &self.schema_fingerprint {
698            Some(value) => Some(value.as_str()),
699            None => None,
700        }
701    }
702
703    /// Return row count.
704    #[must_use]
705    pub const fn entries(&self) -> u64 {
706        self.entries
707    }
708
709    /// Return memory usage in bytes.
710    #[must_use]
711    pub const fn memory_bytes(&self) -> u64 {
712        self.memory_bytes
713    }
714}
715
716#[cfg_attr(doc, doc = "IndexStoreSnapshot\n\nIndex-store snapshot row.")]
717#[derive(CandidType, Clone, Debug, Default, Deserialize)]
718pub struct IndexStoreSnapshot {
719    pub(crate) path: String,
720    pub(crate) storage: StoreSnapshotStorageMode,
721    pub(crate) allocation: StoreAllocationIdentityCapability,
722    pub(crate) durability: StoreDurability,
723    pub(crate) commit: StoreCommitParticipation,
724    pub(crate) recovery: StoreRecoveryCapability,
725    pub(crate) schema_metadata: StoreSchemaMetadataCapability,
726    pub(crate) memory_id: Option<u8>,
727    pub(crate) stable_key: Option<String>,
728    pub(crate) schema_version: Option<u32>,
729    pub(crate) schema_fingerprint_method_version: Option<u8>,
730    pub(crate) schema_fingerprint: Option<String>,
731    pub(crate) entries: u64,
732    pub(crate) user_entries: u64,
733    pub(crate) system_entries: u64,
734    pub(crate) memory_bytes: u64,
735    pub(crate) state: IndexState,
736}
737
738impl IndexStoreSnapshot {
739    /// Construct one index-store snapshot row.
740    #[must_use]
741    pub(super) fn new(
742        path: String,
743        storage: StoreSnapshotStorageMode,
744        capabilities: StoreRuntimeStorageCapabilities,
745        allocation: Option<StoreSnapshotAllocationIdentity>,
746        schema_metadata: StoreSnapshotSchemaMetadata,
747        stats: IndexStoreSnapshotStats,
748    ) -> Self {
749        let memory_id = allocation
750            .as_ref()
751            .map(StoreSnapshotAllocationIdentity::memory_id);
752        let stable_key = match allocation {
753            Some(allocation) => Some(allocation.stable_key),
754            None => None,
755        };
756        Self {
757            path,
758            storage,
759            allocation: capabilities.allocation_identity(),
760            durability: capabilities.durability(),
761            commit: capabilities.commit_participation(),
762            recovery: capabilities.recovery(),
763            schema_metadata: capabilities.schema_metadata(),
764            memory_id,
765            stable_key,
766            schema_version: schema_metadata.schema_version(),
767            schema_fingerprint_method_version: schema_metadata.schema_fingerprint_method_version(),
768            schema_fingerprint: schema_metadata.schema_fingerprint(),
769            entries: stats.entries,
770            user_entries: stats.user_entries,
771            system_entries: stats.system_entries,
772            memory_bytes: stats.memory_bytes,
773            state: stats.state,
774        }
775    }
776
777    /// Borrow store path.
778    #[must_use]
779    pub const fn path(&self) -> &str {
780        self.path.as_str()
781    }
782
783    /// Return diagnostic storage mode.
784    #[must_use]
785    pub const fn storage(&self) -> StoreSnapshotStorageMode {
786        self.storage
787    }
788
789    /// Return allocation-identity capability metadata.
790    #[must_use]
791    pub const fn allocation(&self) -> StoreAllocationIdentityCapability {
792        self.allocation
793    }
794
795    /// Return durability capability metadata.
796    #[must_use]
797    pub const fn durability(&self) -> StoreDurability {
798        self.durability
799    }
800
801    /// Return commit participation capability metadata.
802    #[must_use]
803    pub const fn commit(&self) -> StoreCommitParticipation {
804        self.commit
805    }
806
807    /// Return recovery capability metadata.
808    #[must_use]
809    pub const fn recovery(&self) -> StoreRecoveryCapability {
810        self.recovery
811    }
812
813    /// Return schema-metadata persistence capability metadata.
814    #[must_use]
815    pub const fn schema_metadata(&self) -> StoreSchemaMetadataCapability {
816        self.schema_metadata
817    }
818
819    /// Return stable-memory manager ID, when generated wiring supplied it.
820    #[must_use]
821    pub const fn memory_id(&self) -> Option<u8> {
822        self.memory_id
823    }
824
825    /// Return durable stable-memory key, when generated wiring supplied it.
826    #[must_use]
827    pub const fn stable_key(&self) -> Option<&str> {
828        match &self.stable_key {
829            Some(value) => Some(value.as_str()),
830            None => None,
831        }
832    }
833
834    /// Return accepted schema/catalog version, when known.
835    #[must_use]
836    pub const fn schema_version(&self) -> Option<u32> {
837        self.schema_version
838    }
839
840    /// Return accepted schema/catalog fingerprint method version, when known.
841    #[must_use]
842    pub const fn schema_fingerprint_method_version(&self) -> Option<u8> {
843        self.schema_fingerprint_method_version
844    }
845
846    /// Return accepted schema/catalog fingerprint, when known.
847    #[must_use]
848    pub const fn schema_fingerprint(&self) -> Option<&str> {
849        match &self.schema_fingerprint {
850            Some(value) => Some(value.as_str()),
851            None => None,
852        }
853    }
854
855    /// Return total entry count.
856    #[must_use]
857    pub const fn entries(&self) -> u64 {
858        self.entries
859    }
860
861    /// Return user-namespace entry count.
862    #[must_use]
863    pub const fn user_entries(&self) -> u64 {
864        self.user_entries
865    }
866
867    /// Return system-namespace entry count.
868    #[must_use]
869    pub const fn system_entries(&self) -> u64 {
870        self.system_entries
871    }
872
873    /// Return memory usage in bytes.
874    #[must_use]
875    pub const fn memory_bytes(&self) -> u64 {
876        self.memory_bytes
877    }
878
879    /// Return the current explicit runtime lifecycle state for this index
880    /// store snapshot.
881    #[must_use]
882    pub const fn state(&self) -> IndexState {
883        self.state
884    }
885}
886
887#[cfg_attr(doc, doc = "EntitySnapshot\n\nPer-entity storage snapshot row.")]
888#[derive(CandidType, Clone, Debug, Default, Deserialize)]
889pub struct EntitySnapshot {
890    pub(crate) store: String,
891
892    pub(crate) path: String,
893
894    pub(crate) entries: u64,
895
896    pub(crate) memory_bytes: u64,
897}
898
899impl EntitySnapshot {
900    /// Construct one entity-storage snapshot row.
901    #[must_use]
902    pub(super) const fn new(store: String, path: String, entries: u64, memory_bytes: u64) -> Self {
903        Self {
904            store,
905            path,
906            entries,
907            memory_bytes,
908        }
909    }
910
911    /// Borrow store path.
912    #[must_use]
913    pub const fn store(&self) -> &str {
914        self.store.as_str()
915    }
916
917    /// Borrow entity path.
918    #[must_use]
919    pub const fn path(&self) -> &str {
920        self.path.as_str()
921    }
922
923    /// Return row count.
924    #[must_use]
925    pub const fn entries(&self) -> u64 {
926        self.entries
927    }
928
929    /// Return memory usage in bytes.
930    #[must_use]
931    pub const fn memory_bytes(&self) -> u64 {
932        self.memory_bytes
933    }
934}