icydb_core/db/index/
store.rs1use crate::{
7 db::{
8 data::StorageKey,
9 index::{entry::RawIndexEntry, key::RawIndexKey},
10 },
11 error::InternalError,
12};
13
14use candid::CandidType;
15use canic_cdk::structures::{BTreeMap, DefaultMemoryImpl, memory::VirtualMemory};
16use serde::Deserialize;
17
18#[derive(CandidType, Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq)]
26pub enum IndexState {
27 Building,
28 #[default]
29 Valid,
30 Dropping,
31}
32
33impl IndexState {
34 #[must_use]
36 pub const fn as_str(self) -> &'static str {
37 match self {
38 Self::Building => "building",
39 Self::Valid => "valid",
40 Self::Dropping => "dropping",
41 }
42 }
43}
44
45pub struct IndexStore {
54 pub(super) map: BTreeMap<RawIndexKey, RawIndexEntry, VirtualMemory<DefaultMemoryImpl>>,
55 generation: u64,
56 state: IndexState,
57 secondary_covering_authoritative: bool,
58 secondary_existence_witness_authoritative: bool,
59}
60
61impl IndexStore {
62 #[must_use]
63 pub fn init(memory: VirtualMemory<DefaultMemoryImpl>) -> Self {
64 Self {
65 map: BTreeMap::init(memory),
66 generation: 0,
67 state: IndexState::Valid,
71 secondary_covering_authoritative: false,
72 secondary_existence_witness_authoritative: false,
73 }
74 }
75
76 #[allow(clippy::redundant_closure_for_method_calls)]
78 pub(crate) fn entries(&self) -> Vec<(RawIndexKey, RawIndexEntry)> {
79 self.map.iter().map(|entry| entry.into_pair()).collect()
80 }
81
82 pub(in crate::db) fn get(&self, key: &RawIndexKey) -> Option<RawIndexEntry> {
83 self.map.get(key)
84 }
85
86 pub fn len(&self) -> u64 {
87 self.map.len()
88 }
89
90 pub fn is_empty(&self) -> bool {
91 self.map.is_empty()
92 }
93
94 #[must_use]
95 pub(in crate::db) const fn generation(&self) -> u64 {
96 self.generation
97 }
98
99 #[must_use]
101 pub(in crate::db) const fn state(&self) -> IndexState {
102 self.state
103 }
104
105 #[must_use]
107 pub(in crate::db) const fn is_valid(&self) -> bool {
108 matches!(self.state, IndexState::Valid)
109 }
110
111 pub(in crate::db) const fn mark_building(&mut self) {
114 self.state = IndexState::Building;
115 self.invalidate_secondary_covering_authority();
116 self.invalidate_secondary_existence_witness_authority();
117 }
118
119 pub(in crate::db) const fn mark_valid(&mut self) {
122 self.state = IndexState::Valid;
123 }
124
125 pub(in crate::db) const fn mark_dropping(&mut self) {
128 self.state = IndexState::Dropping;
129 self.invalidate_secondary_covering_authority();
130 self.invalidate_secondary_existence_witness_authority();
131 }
132
133 pub(crate) fn insert(
134 &mut self,
135 key: RawIndexKey,
136 entry: RawIndexEntry,
137 ) -> Option<RawIndexEntry> {
138 let previous = self.map.insert(key, entry);
139 self.bump_generation();
140 self.invalidate_secondary_covering_authority();
141 self.invalidate_secondary_existence_witness_authority();
142 previous
143 }
144
145 pub(crate) fn remove(&mut self, key: &RawIndexKey) -> Option<RawIndexEntry> {
146 let previous = self.map.remove(key);
147 self.bump_generation();
148 self.invalidate_secondary_covering_authority();
149 self.invalidate_secondary_existence_witness_authority();
150 previous
151 }
152
153 pub fn clear(&mut self) {
154 self.map.clear();
155 self.bump_generation();
156 self.invalidate_secondary_covering_authority();
157 self.invalidate_secondary_existence_witness_authority();
158 }
159
160 #[must_use]
163 pub(in crate::db) const fn secondary_covering_authoritative(&self) -> bool {
164 self.secondary_covering_authoritative
165 }
166
167 pub(in crate::db) fn mark_secondary_covering_authoritative(&mut self) {
170 debug_assert!(
171 self.is_valid(),
172 "secondary covering authority must not be restored while the index is Building or Dropping",
173 );
174 self.secondary_covering_authoritative = true;
175 }
176
177 #[must_use]
180 pub(in crate::db) const fn secondary_existence_witness_authoritative(&self) -> bool {
181 self.secondary_existence_witness_authoritative
182 }
183
184 pub(in crate::db) fn mark_secondary_existence_witness_authoritative(&mut self) {
187 debug_assert!(
188 self.is_valid(),
189 "storage existence witness authority must not be restored while the index is Building or Dropping",
190 );
191 self.secondary_existence_witness_authoritative = true;
192 }
193
194 pub(in crate::db) fn mark_memberships_missing_for_storage_key(
197 &mut self,
198 storage_key: StorageKey,
199 ) -> Result<usize, InternalError> {
200 let mut entries = Vec::new();
201
202 for entry in self.map.iter() {
203 entries.push(entry.into_pair());
204 }
205
206 let mut marked = 0usize;
207
208 for (raw_key, mut raw_entry) in entries {
209 if raw_entry
210 .mark_key_missing(storage_key)
211 .map_err(InternalError::index_entry_decode_failed)?
212 {
213 self.map.insert(raw_key, raw_entry);
214 marked = marked.saturating_add(1);
215 }
216 }
217
218 if marked > 0 {
219 self.bump_generation();
220 self.invalidate_secondary_covering_authority();
221 self.invalidate_secondary_existence_witness_authority();
222 }
223
224 Ok(marked)
225 }
226
227 pub fn memory_bytes(&self) -> u64 {
229 self.map
230 .iter()
231 .map(|entry| entry.key().as_bytes().len() as u64 + entry.value().len() as u64)
232 .sum()
233 }
234
235 const fn bump_generation(&mut self) {
236 self.generation = self.generation.saturating_add(1);
237 }
238
239 const fn invalidate_secondary_covering_authority(&mut self) {
240 self.secondary_covering_authoritative = false;
241 }
242
243 const fn invalidate_secondary_existence_witness_authority(&mut self) {
244 self.secondary_existence_witness_authoritative = false;
245 }
246}