Skip to main content

icydb_core/db/data/
store.rs

1//! Module: data::store
2//! Responsibility: stable BTreeMap-backed row persistence.
3//! Does not own: key/row validation policy beyond type boundaries.
4//! Boundary: commit/executor call into this layer after prevalidation.
5
6use crate::db::data::{CanonicalRow, DataKey, RawDataKey, RawRow};
7use canic_cdk::structures::{BTreeMap, DefaultMemoryImpl, memory::VirtualMemory};
8
9///
10/// DataStore
11///
12/// Thin persistence wrapper over one stable BTreeMap.
13///
14/// Invariant: callers provide already-validated `RawDataKey` and canonical row bytes.
15/// This type intentionally does not enforce commit-phase ordering.
16///
17
18pub struct DataStore {
19    map: BTreeMap<RawDataKey, RawRow, VirtualMemory<DefaultMemoryImpl>>,
20    secondary_covering_authoritative: bool,
21}
22
23impl DataStore {
24    /// Initialize a data store with the provided backing memory.
25    #[must_use]
26    pub fn init(memory: VirtualMemory<DefaultMemoryImpl>) -> Self {
27        Self {
28            map: BTreeMap::init(memory),
29            secondary_covering_authoritative: false,
30        }
31    }
32
33    /// Insert or replace one row by raw key.
34    pub(in crate::db) fn insert(&mut self, key: RawDataKey, row: CanonicalRow) -> Option<RawRow> {
35        let previous = self.map.insert(key, row.into_raw_row());
36        self.invalidate_secondary_covering_authority();
37
38        previous
39    }
40
41    /// Insert one raw row directly for corruption-focused test setup only.
42    #[cfg(test)]
43    pub(crate) fn insert_raw_for_test(&mut self, key: RawDataKey, row: RawRow) -> Option<RawRow> {
44        let previous = self.map.insert(key, row);
45        self.invalidate_secondary_covering_authority();
46
47        previous
48    }
49
50    /// Remove one row by raw key.
51    pub fn remove(&mut self, key: &RawDataKey) -> Option<RawRow> {
52        let previous = self.map.remove(key);
53        self.invalidate_secondary_covering_authority();
54
55        previous
56    }
57
58    /// Load one row by raw key.
59    pub fn get(&self, key: &RawDataKey) -> Option<RawRow> {
60        self.map.get(key)
61    }
62
63    /// Return whether one raw key exists without cloning the row payload.
64    #[must_use]
65    pub fn contains(&self, key: &RawDataKey) -> bool {
66        self.map.contains_key(key)
67    }
68
69    /// Clear all stored rows from the data store.
70    pub fn clear(&mut self) {
71        self.map.clear();
72        self.invalidate_secondary_covering_authority();
73    }
74
75    /// Return whether this row store currently participates in a synchronized
76    /// secondary-covering authority witness.
77    #[must_use]
78    pub(in crate::db) const fn secondary_covering_authoritative(&self) -> bool {
79        self.secondary_covering_authoritative
80    }
81
82    /// Mark this row store as synchronized with its paired secondary index
83    /// store after successful commit or recovery.
84    pub(in crate::db) const fn mark_secondary_covering_authoritative(&mut self) {
85        self.secondary_covering_authoritative = true;
86    }
87
88    /// Sum of bytes used by all stored rows.
89    pub fn memory_bytes(&self) -> u64 {
90        // Report map footprint as key bytes + row bytes per entry.
91        self.iter()
92            .map(|entry| DataKey::STORED_SIZE_BYTES + entry.value().len() as u64)
93            .sum()
94    }
95
96    // Any direct row-store mutation invalidates the secondary covering
97    // authority witness until commit/recovery re-synchronizes the pair.
98    const fn invalidate_secondary_covering_authority(&mut self) {
99        self.secondary_covering_authoritative = false;
100    }
101}
102
103impl std::ops::Deref for DataStore {
104    type Target = BTreeMap<RawDataKey, RawRow, VirtualMemory<DefaultMemoryImpl>>;
105
106    fn deref(&self) -> &Self::Target {
107        &self.map
108    }
109}