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(crate) 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(crate) 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(crate) 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    #[default]
347    Stable,
348    Heap,
349    Journaled,
350}
351
352impl StoreSnapshotStorageMode {
353    /// Return the user-facing storage mode label.
354    #[must_use]
355    pub const fn as_str(self) -> &'static str {
356        match self {
357            Self::Stable => "stable",
358            Self::Heap => "heap",
359            Self::Journaled => "journaled",
360        }
361    }
362}
363
364#[derive(Clone, Debug, Eq, PartialEq)]
365pub(crate) struct StoreSnapshotAllocationIdentity {
366    memory_id: u8,
367    stable_key: String,
368}
369
370impl StoreSnapshotAllocationIdentity {
371    pub(crate) const fn new(memory_id: u8, stable_key: String) -> Self {
372        Self {
373            memory_id,
374            stable_key,
375        }
376    }
377
378    const fn memory_id(&self) -> u8 {
379        self.memory_id
380    }
381}
382
383#[derive(Clone, Debug, Default, Eq, PartialEq)]
384pub(crate) struct StoreSnapshotSchemaMetadata {
385    version: Option<u32>,
386    fingerprint_method_version: Option<u8>,
387    fingerprint: Option<String>,
388}
389
390impl StoreSnapshotSchemaMetadata {
391    pub(crate) const fn absent() -> Self {
392        Self {
393            version: None,
394            fingerprint_method_version: None,
395            fingerprint: None,
396        }
397    }
398
399    pub(crate) const fn new(
400        schema_version: u32,
401        schema_fingerprint_method_version: u8,
402        schema_fingerprint: String,
403    ) -> Self {
404        Self {
405            version: Some(schema_version),
406            fingerprint_method_version: Some(schema_fingerprint_method_version),
407            fingerprint: Some(schema_fingerprint),
408        }
409    }
410
411    const fn schema_version(&self) -> Option<u32> {
412        self.version
413    }
414
415    const fn schema_fingerprint_method_version(&self) -> Option<u8> {
416        self.fingerprint_method_version
417    }
418
419    fn schema_fingerprint(&self) -> Option<String> {
420        self.fingerprint.clone()
421    }
422}
423
424#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
425pub(crate) struct IndexStoreSnapshotStats {
426    entries: u64,
427    user_entries: u64,
428    system_entries: u64,
429    memory_bytes: u64,
430    state: IndexState,
431}
432
433impl IndexStoreSnapshotStats {
434    pub(crate) const fn new(
435        entries: u64,
436        user_entries: u64,
437        system_entries: u64,
438        memory_bytes: u64,
439        state: IndexState,
440    ) -> Self {
441        Self {
442            entries,
443            user_entries,
444            system_entries,
445            memory_bytes,
446            state,
447        }
448    }
449}
450
451impl SchemaStoreSnapshot {
452    /// Construct one schema-store diagnostic row.
453    #[must_use]
454    pub(crate) fn new(
455        path: String,
456        storage: StoreSnapshotStorageMode,
457        capabilities: StoreRuntimeStorageCapabilities,
458        allocation: Option<StoreSnapshotAllocationIdentity>,
459        schema_metadata: StoreSnapshotSchemaMetadata,
460        entity_count: u64,
461    ) -> Self {
462        let memory_id = allocation
463            .as_ref()
464            .map(StoreSnapshotAllocationIdentity::memory_id);
465        let stable_key = match allocation {
466            Some(allocation) => Some(allocation.stable_key),
467            None => None,
468        };
469        Self {
470            path,
471            storage,
472            allocation: capabilities.allocation_identity(),
473            durability: capabilities.durability(),
474            commit: capabilities.commit_participation(),
475            recovery: capabilities.recovery(),
476            schema_metadata: capabilities.schema_metadata(),
477            memory_id,
478            stable_key,
479            schema_version: schema_metadata.schema_version(),
480            schema_fingerprint_method_version: schema_metadata.schema_fingerprint_method_version(),
481            schema_fingerprint: schema_metadata.schema_fingerprint(),
482            entity_count,
483        }
484    }
485
486    /// Borrow store path.
487    #[must_use]
488    pub const fn path(&self) -> &str {
489        self.path.as_str()
490    }
491
492    /// Return diagnostic storage mode.
493    #[must_use]
494    pub const fn storage(&self) -> StoreSnapshotStorageMode {
495        self.storage
496    }
497
498    /// Return allocation-identity capability metadata.
499    #[must_use]
500    pub const fn allocation(&self) -> StoreAllocationIdentityCapability {
501        self.allocation
502    }
503
504    /// Return durability capability metadata.
505    #[must_use]
506    pub const fn durability(&self) -> StoreDurability {
507        self.durability
508    }
509
510    /// Return commit participation capability metadata.
511    #[must_use]
512    pub const fn commit(&self) -> StoreCommitParticipation {
513        self.commit
514    }
515
516    /// Return recovery capability metadata.
517    #[must_use]
518    pub const fn recovery(&self) -> StoreRecoveryCapability {
519        self.recovery
520    }
521
522    /// Return schema-metadata persistence capability metadata.
523    #[must_use]
524    pub const fn schema_metadata(&self) -> StoreSchemaMetadataCapability {
525        self.schema_metadata
526    }
527
528    /// Return stable-memory manager ID, when generated wiring supplied it.
529    #[must_use]
530    pub const fn memory_id(&self) -> Option<u8> {
531        self.memory_id
532    }
533
534    /// Return durable stable-memory key, when generated wiring supplied it.
535    #[must_use]
536    pub const fn stable_key(&self) -> Option<&str> {
537        match &self.stable_key {
538            Some(value) => Some(value.as_str()),
539            None => None,
540        }
541    }
542
543    /// Return accepted schema/catalog version, when known.
544    #[must_use]
545    pub const fn schema_version(&self) -> Option<u32> {
546        self.schema_version
547    }
548
549    /// Return accepted schema/catalog fingerprint method version, when known.
550    #[must_use]
551    pub const fn schema_fingerprint_method_version(&self) -> Option<u8> {
552        self.schema_fingerprint_method_version
553    }
554
555    /// Return accepted schema/catalog fingerprint, when known.
556    #[must_use]
557    pub const fn schema_fingerprint(&self) -> Option<&str> {
558        match &self.schema_fingerprint {
559            Some(value) => Some(value.as_str()),
560            None => None,
561        }
562    }
563
564    /// Return number of entity schemas represented in this schema catalog.
565    #[must_use]
566    pub const fn entity_count(&self) -> u64 {
567        self.entity_count
568    }
569}
570
571#[cfg_attr(doc, doc = "DataStoreSnapshot\n\nData-store snapshot row.")]
572#[derive(CandidType, Clone, Debug, Default, Deserialize)]
573pub struct DataStoreSnapshot {
574    pub(crate) path: String,
575    pub(crate) storage: StoreSnapshotStorageMode,
576    pub(crate) allocation: StoreAllocationIdentityCapability,
577    pub(crate) durability: StoreDurability,
578    pub(crate) commit: StoreCommitParticipation,
579    pub(crate) recovery: StoreRecoveryCapability,
580    pub(crate) schema_metadata: StoreSchemaMetadataCapability,
581    pub(crate) memory_id: Option<u8>,
582    pub(crate) stable_key: Option<String>,
583    pub(crate) schema_version: Option<u32>,
584    pub(crate) schema_fingerprint_method_version: Option<u8>,
585    pub(crate) schema_fingerprint: Option<String>,
586    pub(crate) entries: u64,
587    pub(crate) memory_bytes: u64,
588}
589
590impl DataStoreSnapshot {
591    /// Construct one data-store snapshot row.
592    #[must_use]
593    pub(crate) fn new(
594        path: String,
595        storage: StoreSnapshotStorageMode,
596        capabilities: StoreRuntimeStorageCapabilities,
597        allocation: Option<StoreSnapshotAllocationIdentity>,
598        schema_metadata: StoreSnapshotSchemaMetadata,
599        entries: u64,
600        memory_bytes: u64,
601    ) -> Self {
602        let memory_id = allocation
603            .as_ref()
604            .map(StoreSnapshotAllocationIdentity::memory_id);
605        let stable_key = match allocation {
606            Some(allocation) => Some(allocation.stable_key),
607            None => None,
608        };
609        Self {
610            path,
611            storage,
612            allocation: capabilities.allocation_identity(),
613            durability: capabilities.durability(),
614            commit: capabilities.commit_participation(),
615            recovery: capabilities.recovery(),
616            schema_metadata: capabilities.schema_metadata(),
617            memory_id,
618            stable_key,
619            schema_version: schema_metadata.schema_version(),
620            schema_fingerprint_method_version: schema_metadata.schema_fingerprint_method_version(),
621            schema_fingerprint: schema_metadata.schema_fingerprint(),
622            entries,
623            memory_bytes,
624        }
625    }
626
627    /// Borrow store path.
628    #[must_use]
629    pub const fn path(&self) -> &str {
630        self.path.as_str()
631    }
632
633    /// Return diagnostic storage mode.
634    #[must_use]
635    pub const fn storage(&self) -> StoreSnapshotStorageMode {
636        self.storage
637    }
638
639    /// Return allocation-identity capability metadata.
640    #[must_use]
641    pub const fn allocation(&self) -> StoreAllocationIdentityCapability {
642        self.allocation
643    }
644
645    /// Return durability capability metadata.
646    #[must_use]
647    pub const fn durability(&self) -> StoreDurability {
648        self.durability
649    }
650
651    /// Return commit participation capability metadata.
652    #[must_use]
653    pub const fn commit(&self) -> StoreCommitParticipation {
654        self.commit
655    }
656
657    /// Return recovery capability metadata.
658    #[must_use]
659    pub const fn recovery(&self) -> StoreRecoveryCapability {
660        self.recovery
661    }
662
663    /// Return schema-metadata persistence capability metadata.
664    #[must_use]
665    pub const fn schema_metadata(&self) -> StoreSchemaMetadataCapability {
666        self.schema_metadata
667    }
668
669    /// Return stable-memory manager ID, when generated wiring supplied it.
670    #[must_use]
671    pub const fn memory_id(&self) -> Option<u8> {
672        self.memory_id
673    }
674
675    /// Return durable stable-memory key, when generated wiring supplied it.
676    #[must_use]
677    pub const fn stable_key(&self) -> Option<&str> {
678        match &self.stable_key {
679            Some(value) => Some(value.as_str()),
680            None => None,
681        }
682    }
683
684    /// Return accepted schema/catalog version, when known.
685    #[must_use]
686    pub const fn schema_version(&self) -> Option<u32> {
687        self.schema_version
688    }
689
690    /// Return accepted schema/catalog fingerprint method version, when known.
691    #[must_use]
692    pub const fn schema_fingerprint_method_version(&self) -> Option<u8> {
693        self.schema_fingerprint_method_version
694    }
695
696    /// Return accepted schema/catalog fingerprint, when known.
697    #[must_use]
698    pub const fn schema_fingerprint(&self) -> Option<&str> {
699        match &self.schema_fingerprint {
700            Some(value) => Some(value.as_str()),
701            None => None,
702        }
703    }
704
705    /// Return row count.
706    #[must_use]
707    pub const fn entries(&self) -> u64 {
708        self.entries
709    }
710
711    /// Return memory usage in bytes.
712    #[must_use]
713    pub const fn memory_bytes(&self) -> u64 {
714        self.memory_bytes
715    }
716}
717
718#[cfg_attr(doc, doc = "IndexStoreSnapshot\n\nIndex-store snapshot row.")]
719#[derive(CandidType, Clone, Debug, Default, Deserialize)]
720pub struct IndexStoreSnapshot {
721    pub(crate) path: String,
722    pub(crate) storage: StoreSnapshotStorageMode,
723    pub(crate) allocation: StoreAllocationIdentityCapability,
724    pub(crate) durability: StoreDurability,
725    pub(crate) commit: StoreCommitParticipation,
726    pub(crate) recovery: StoreRecoveryCapability,
727    pub(crate) schema_metadata: StoreSchemaMetadataCapability,
728    pub(crate) memory_id: Option<u8>,
729    pub(crate) stable_key: Option<String>,
730    pub(crate) schema_version: Option<u32>,
731    pub(crate) schema_fingerprint_method_version: Option<u8>,
732    pub(crate) schema_fingerprint: Option<String>,
733    pub(crate) entries: u64,
734    pub(crate) user_entries: u64,
735    pub(crate) system_entries: u64,
736    pub(crate) memory_bytes: u64,
737    pub(crate) state: IndexState,
738}
739
740impl IndexStoreSnapshot {
741    /// Construct one index-store snapshot row.
742    #[must_use]
743    pub(crate) fn new(
744        path: String,
745        storage: StoreSnapshotStorageMode,
746        capabilities: StoreRuntimeStorageCapabilities,
747        allocation: Option<StoreSnapshotAllocationIdentity>,
748        schema_metadata: StoreSnapshotSchemaMetadata,
749        stats: IndexStoreSnapshotStats,
750    ) -> Self {
751        let memory_id = allocation
752            .as_ref()
753            .map(StoreSnapshotAllocationIdentity::memory_id);
754        let stable_key = match allocation {
755            Some(allocation) => Some(allocation.stable_key),
756            None => None,
757        };
758        Self {
759            path,
760            storage,
761            allocation: capabilities.allocation_identity(),
762            durability: capabilities.durability(),
763            commit: capabilities.commit_participation(),
764            recovery: capabilities.recovery(),
765            schema_metadata: capabilities.schema_metadata(),
766            memory_id,
767            stable_key,
768            schema_version: schema_metadata.schema_version(),
769            schema_fingerprint_method_version: schema_metadata.schema_fingerprint_method_version(),
770            schema_fingerprint: schema_metadata.schema_fingerprint(),
771            entries: stats.entries,
772            user_entries: stats.user_entries,
773            system_entries: stats.system_entries,
774            memory_bytes: stats.memory_bytes,
775            state: stats.state,
776        }
777    }
778
779    /// Borrow store path.
780    #[must_use]
781    pub const fn path(&self) -> &str {
782        self.path.as_str()
783    }
784
785    /// Return diagnostic storage mode.
786    #[must_use]
787    pub const fn storage(&self) -> StoreSnapshotStorageMode {
788        self.storage
789    }
790
791    /// Return allocation-identity capability metadata.
792    #[must_use]
793    pub const fn allocation(&self) -> StoreAllocationIdentityCapability {
794        self.allocation
795    }
796
797    /// Return durability capability metadata.
798    #[must_use]
799    pub const fn durability(&self) -> StoreDurability {
800        self.durability
801    }
802
803    /// Return commit participation capability metadata.
804    #[must_use]
805    pub const fn commit(&self) -> StoreCommitParticipation {
806        self.commit
807    }
808
809    /// Return recovery capability metadata.
810    #[must_use]
811    pub const fn recovery(&self) -> StoreRecoveryCapability {
812        self.recovery
813    }
814
815    /// Return schema-metadata persistence capability metadata.
816    #[must_use]
817    pub const fn schema_metadata(&self) -> StoreSchemaMetadataCapability {
818        self.schema_metadata
819    }
820
821    /// Return stable-memory manager ID, when generated wiring supplied it.
822    #[must_use]
823    pub const fn memory_id(&self) -> Option<u8> {
824        self.memory_id
825    }
826
827    /// Return durable stable-memory key, when generated wiring supplied it.
828    #[must_use]
829    pub const fn stable_key(&self) -> Option<&str> {
830        match &self.stable_key {
831            Some(value) => Some(value.as_str()),
832            None => None,
833        }
834    }
835
836    /// Return accepted schema/catalog version, when known.
837    #[must_use]
838    pub const fn schema_version(&self) -> Option<u32> {
839        self.schema_version
840    }
841
842    /// Return accepted schema/catalog fingerprint method version, when known.
843    #[must_use]
844    pub const fn schema_fingerprint_method_version(&self) -> Option<u8> {
845        self.schema_fingerprint_method_version
846    }
847
848    /// Return accepted schema/catalog fingerprint, when known.
849    #[must_use]
850    pub const fn schema_fingerprint(&self) -> Option<&str> {
851        match &self.schema_fingerprint {
852            Some(value) => Some(value.as_str()),
853            None => None,
854        }
855    }
856
857    /// Return total entry count.
858    #[must_use]
859    pub const fn entries(&self) -> u64 {
860        self.entries
861    }
862
863    /// Return user-namespace entry count.
864    #[must_use]
865    pub const fn user_entries(&self) -> u64 {
866        self.user_entries
867    }
868
869    /// Return system-namespace entry count.
870    #[must_use]
871    pub const fn system_entries(&self) -> u64 {
872        self.system_entries
873    }
874
875    /// Return memory usage in bytes.
876    #[must_use]
877    pub const fn memory_bytes(&self) -> u64 {
878        self.memory_bytes
879    }
880
881    /// Return the current explicit runtime lifecycle state for this index
882    /// store snapshot.
883    #[must_use]
884    pub const fn state(&self) -> IndexState {
885        self.state
886    }
887}
888
889#[cfg_attr(doc, doc = "EntitySnapshot\n\nPer-entity storage snapshot row.")]
890#[derive(CandidType, Clone, Debug, Default, Deserialize)]
891pub struct EntitySnapshot {
892    pub(crate) store: String,
893
894    pub(crate) path: String,
895
896    pub(crate) entries: u64,
897
898    pub(crate) memory_bytes: u64,
899}
900
901impl EntitySnapshot {
902    /// Construct one entity-storage snapshot row.
903    #[must_use]
904    pub(crate) const fn new(store: String, path: String, entries: u64, memory_bytes: u64) -> Self {
905        Self {
906            store,
907            path,
908            entries,
909            memory_bytes,
910        }
911    }
912
913    /// Borrow store path.
914    #[must_use]
915    pub const fn store(&self) -> &str {
916        self.store.as_str()
917    }
918
919    /// Borrow entity path.
920    #[must_use]
921    pub const fn path(&self) -> &str {
922        self.path.as_str()
923    }
924
925    /// Return row count.
926    #[must_use]
927    pub const fn entries(&self) -> u64 {
928        self.entries
929    }
930
931    /// Return memory usage in bytes.
932    #[must_use]
933    pub const fn memory_bytes(&self) -> u64 {
934        self.memory_bytes
935    }
936}