1use crate::db::{
2 data::DataStore,
3 index::{IndexState, IndexStore},
4 schema::SchemaStore,
5};
6use candid::CandidType;
7use serde::Deserialize;
8use std::{cell::RefCell, thread::LocalKey};
9
10#[derive(Clone, Copy, Debug)]
20pub struct StoreHandle {
21 data: &'static LocalKey<RefCell<DataStore>>,
22 index: &'static LocalKey<RefCell<IndexStore>>,
23 schema: &'static LocalKey<RefCell<SchemaStore>>,
24 allocations: StoreAllocationIdentities,
25 capabilities: StoreRuntimeStorageCapabilities,
26}
27
28#[derive(CandidType, Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq)]
32pub enum StoreRuntimeStorageMode {
33 #[default]
35 Stable,
36 Heap,
38}
39
40impl StoreRuntimeStorageMode {
41 #[must_use]
43 pub const fn as_str(self) -> &'static str {
44 match self {
45 Self::Stable => "stable",
46 Self::Heap => "heap",
47 }
48 }
49}
50
51#[derive(CandidType, Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq)]
53pub enum StoreAllocationIdentityCapability {
54 #[default]
56 Present,
57 Absent,
59}
60
61impl StoreAllocationIdentityCapability {
62 #[must_use]
64 pub const fn as_str(self) -> &'static str {
65 match self {
66 Self::Present => "present",
67 Self::Absent => "absent",
68 }
69 }
70}
71
72#[derive(CandidType, Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq)]
74pub enum StoreDurability {
75 #[default]
77 Durable,
78 Volatile,
80}
81
82impl StoreDurability {
83 #[must_use]
85 pub const fn as_str(self) -> &'static str {
86 match self {
87 Self::Durable => "durable",
88 Self::Volatile => "volatile",
89 }
90 }
91}
92
93#[derive(CandidType, Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq)]
95pub enum StoreRecoveryCapability {
96 #[default]
98 StableCommitReplay,
99 None,
101}
102
103impl StoreRecoveryCapability {
104 #[must_use]
106 pub const fn as_str(self) -> &'static str {
107 match self {
108 Self::StableCommitReplay => "stable-replay",
109 Self::None => "none",
110 }
111 }
112}
113
114#[derive(CandidType, Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq)]
116pub enum StoreCommitParticipation {
117 #[default]
119 Durable,
120 LiveOnly,
122}
123
124impl StoreCommitParticipation {
125 #[must_use]
127 pub const fn as_str(self) -> &'static str {
128 match self {
129 Self::Durable => "durable",
130 Self::LiveOnly => "live-only",
131 }
132 }
133}
134
135#[derive(CandidType, Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq)]
137pub enum StoreSchemaMetadataCapability {
138 #[default]
140 DurableAcceptedHistory,
141 LiveRebuiltMetadata,
143}
144
145impl StoreSchemaMetadataCapability {
146 #[must_use]
148 pub const fn as_str(self) -> &'static str {
149 match self {
150 Self::DurableAcceptedHistory => "durable-accepted-history",
151 Self::LiveRebuiltMetadata => "live-rebuilt-metadata",
152 }
153 }
154}
155
156#[derive(CandidType, Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq)]
158pub enum StoreRelationSourceCapability {
159 #[default]
161 DurableSource,
162 LiveSource,
164}
165
166#[derive(CandidType, Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq)]
168pub enum StoreRelationTargetCapability {
169 #[default]
171 DurableTarget,
172 VolatileTarget,
174}
175
176#[derive(CandidType, Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq)]
178pub enum StoreLiveValidationCapability {
179 #[default]
181 Supported,
182}
183
184#[derive(CandidType, Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq)]
188pub struct StoreRuntimeStorageCapabilities {
189 storage_mode: StoreRuntimeStorageMode,
190 allocation_identity: StoreAllocationIdentityCapability,
191 durability: StoreDurability,
192 recovery: StoreRecoveryCapability,
193 commit_participation: StoreCommitParticipation,
194 schema_metadata: StoreSchemaMetadataCapability,
195 relation_source: StoreRelationSourceCapability,
196 relation_target: StoreRelationTargetCapability,
197 live_validation: StoreLiveValidationCapability,
198}
199
200impl StoreRuntimeStorageCapabilities {
201 #[must_use]
203 pub const fn stable() -> Self {
204 Self {
205 storage_mode: StoreRuntimeStorageMode::Stable,
206 allocation_identity: StoreAllocationIdentityCapability::Present,
207 durability: StoreDurability::Durable,
208 recovery: StoreRecoveryCapability::StableCommitReplay,
209 commit_participation: StoreCommitParticipation::Durable,
210 schema_metadata: StoreSchemaMetadataCapability::DurableAcceptedHistory,
211 relation_source: StoreRelationSourceCapability::DurableSource,
212 relation_target: StoreRelationTargetCapability::DurableTarget,
213 live_validation: StoreLiveValidationCapability::Supported,
214 }
215 }
216
217 #[must_use]
219 pub const fn heap() -> Self {
220 Self {
221 storage_mode: StoreRuntimeStorageMode::Heap,
222 allocation_identity: StoreAllocationIdentityCapability::Absent,
223 durability: StoreDurability::Volatile,
224 recovery: StoreRecoveryCapability::None,
225 commit_participation: StoreCommitParticipation::LiveOnly,
226 schema_metadata: StoreSchemaMetadataCapability::LiveRebuiltMetadata,
227 relation_source: StoreRelationSourceCapability::LiveSource,
228 relation_target: StoreRelationTargetCapability::VolatileTarget,
229 live_validation: StoreLiveValidationCapability::Supported,
230 }
231 }
232
233 #[must_use]
235 pub const fn storage_mode(self) -> StoreRuntimeStorageMode {
236 self.storage_mode
237 }
238
239 #[must_use]
241 pub const fn allocation_identity(self) -> StoreAllocationIdentityCapability {
242 self.allocation_identity
243 }
244
245 #[must_use]
247 pub const fn durability(self) -> StoreDurability {
248 self.durability
249 }
250
251 #[must_use]
253 pub const fn recovery(self) -> StoreRecoveryCapability {
254 self.recovery
255 }
256
257 #[must_use]
259 pub const fn commit_participation(self) -> StoreCommitParticipation {
260 self.commit_participation
261 }
262
263 #[must_use]
265 pub const fn schema_metadata(self) -> StoreSchemaMetadataCapability {
266 self.schema_metadata
267 }
268
269 #[must_use]
271 pub const fn relation_source(self) -> StoreRelationSourceCapability {
272 self.relation_source
273 }
274
275 #[must_use]
277 pub const fn relation_target(self) -> StoreRelationTargetCapability {
278 self.relation_target
279 }
280
281 #[must_use]
283 pub const fn live_validation(self) -> StoreLiveValidationCapability {
284 self.live_validation
285 }
286}
287
288#[derive(Clone, Copy, Debug, Eq, PartialEq)]
295pub struct StoreAllocationIdentity {
296 memory_id: u8,
297 stable_key: &'static str,
298}
299
300impl StoreAllocationIdentity {
301 #[must_use]
303 pub const fn new(memory_id: u8, stable_key: &'static str) -> Self {
304 Self {
305 memory_id,
306 stable_key,
307 }
308 }
309
310 #[must_use]
312 pub const fn memory_id(self) -> u8 {
313 self.memory_id
314 }
315
316 #[must_use]
318 pub const fn stable_key(self) -> &'static str {
319 self.stable_key
320 }
321}
322
323#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
331pub struct StoreAllocationIdentities {
332 data: Option<StoreAllocationIdentity>,
333 index: Option<StoreAllocationIdentity>,
334 schema: Option<StoreAllocationIdentity>,
335}
336
337impl StoreAllocationIdentities {
338 #[must_use]
340 pub const fn absent() -> Self {
341 Self {
342 data: None,
343 index: None,
344 schema: None,
345 }
346 }
347
348 #[must_use]
350 pub const fn new(
351 data: StoreAllocationIdentity,
352 index: StoreAllocationIdentity,
353 schema: StoreAllocationIdentity,
354 ) -> Self {
355 Self {
356 data: Some(data),
357 index: Some(index),
358 schema: Some(schema),
359 }
360 }
361
362 #[must_use]
364 pub const fn data(self) -> Option<StoreAllocationIdentity> {
365 self.data
366 }
367
368 #[must_use]
370 pub const fn index(self) -> Option<StoreAllocationIdentity> {
371 self.index
372 }
373
374 #[must_use]
376 pub const fn schema(self) -> Option<StoreAllocationIdentity> {
377 self.schema
378 }
379
380 #[must_use]
383 pub const fn allocation_identity_capability(self) -> Option<StoreAllocationIdentityCapability> {
384 match (self.data, self.index, self.schema) {
385 (Some(_), Some(_), Some(_)) => Some(StoreAllocationIdentityCapability::Present),
386 (None, None, None) => Some(StoreAllocationIdentityCapability::Absent),
387 _ => None,
388 }
389 }
390}
391
392impl StoreHandle {
393 #[must_use]
395 pub const fn new(
396 data: &'static LocalKey<RefCell<DataStore>>,
397 index: &'static LocalKey<RefCell<IndexStore>>,
398 schema: &'static LocalKey<RefCell<SchemaStore>>,
399 allocations: StoreAllocationIdentities,
400 capabilities: StoreRuntimeStorageCapabilities,
401 ) -> Self {
402 Self {
403 data,
404 index,
405 schema,
406 allocations,
407 capabilities,
408 }
409 }
410
411 pub fn with_data<R>(&self, f: impl FnOnce(&DataStore) -> R) -> R {
413 #[cfg(feature = "diagnostics")]
414 {
415 crate::db::physical_access::measure_physical_access_operation(|| {
416 self.data.with_borrow(f)
417 })
418 }
419
420 #[cfg(not(feature = "diagnostics"))]
421 {
422 self.data.with_borrow(f)
423 }
424 }
425
426 pub fn with_data_mut<R>(&self, f: impl FnOnce(&mut DataStore) -> R) -> R {
428 self.data.with_borrow_mut(f)
429 }
430
431 pub fn with_index<R>(&self, f: impl FnOnce(&IndexStore) -> R) -> R {
433 #[cfg(feature = "diagnostics")]
434 {
435 crate::db::physical_access::measure_physical_access_operation(|| {
436 self.index.with_borrow(f)
437 })
438 }
439
440 #[cfg(not(feature = "diagnostics"))]
441 {
442 self.index.with_borrow(f)
443 }
444 }
445
446 pub fn with_index_mut<R>(&self, f: impl FnOnce(&mut IndexStore) -> R) -> R {
448 self.index.with_borrow_mut(f)
449 }
450
451 pub fn with_schema<R>(&self, f: impl FnOnce(&SchemaStore) -> R) -> R {
453 self.schema.with_borrow(f)
454 }
455
456 pub fn with_schema_mut<R>(&self, f: impl FnOnce(&mut SchemaStore) -> R) -> R {
458 self.schema.with_borrow_mut(f)
459 }
460
461 #[must_use]
463 pub(in crate::db) fn index_state(&self) -> IndexState {
464 self.with_index(IndexStore::state)
465 }
466
467 #[must_use]
469 pub(in crate::db) const fn data_is_heap_storage(&self) -> bool {
470 matches!(
471 self.capabilities.storage_mode(),
472 StoreRuntimeStorageMode::Heap
473 )
474 }
475
476 pub(in crate::db) fn mark_index_building(&self) {
478 self.with_index_mut(IndexStore::mark_building);
479 }
480
481 pub(in crate::db) fn mark_index_ready(&self) {
483 self.with_index_mut(IndexStore::mark_ready);
484 }
485
486 #[must_use]
488 pub const fn data_store(&self) -> &'static LocalKey<RefCell<DataStore>> {
489 self.data
490 }
491
492 #[must_use]
494 pub const fn index_store(&self) -> &'static LocalKey<RefCell<IndexStore>> {
495 self.index
496 }
497
498 #[must_use]
500 pub const fn schema_store(&self) -> &'static LocalKey<RefCell<SchemaStore>> {
501 self.schema
502 }
503
504 #[must_use]
507 pub const fn data_allocation(&self) -> Option<StoreAllocationIdentity> {
508 self.allocations.data()
509 }
510
511 #[must_use]
514 pub const fn index_allocation(&self) -> Option<StoreAllocationIdentity> {
515 self.allocations.index()
516 }
517
518 #[must_use]
521 pub const fn schema_allocation(&self) -> Option<StoreAllocationIdentity> {
522 self.allocations.schema()
523 }
524
525 #[must_use]
527 pub const fn storage_capabilities(&self) -> StoreRuntimeStorageCapabilities {
528 self.capabilities
529 }
530}