Skip to main content

icydb_core/db/memory_runtime/
mod.rs

1//! Bind IcyDB storage to one host-owned, bootstrapped memory runtime.
2//! The runtime owns allocation policy, persistence and opening authority.
3
4///
5/// TESTS
6///
7#[cfg(test)]
8mod tests;
9
10use ic_memory::{DefaultMemoryImpl, MemoryRuntime, RuntimeMemory, RuntimeOpenError};
11use std::{cell::OnceCell, rc::Rc};
12
13thread_local! {
14    static MEMORY_RUNTIME: OnceCell<Rc<MemoryRuntime<DefaultMemoryImpl>>> = const { OnceCell::new() };
15}
16
17/// Failure to bind the host's committed memory authority to IcyDB.
18#[derive(Clone, Copy, Debug, Eq, thiserror::Error, PartialEq)]
19pub enum MemoryRuntimeBindingError {
20    /// Allocation bootstrap must succeed before publishing the runtime.
21    #[error("memory runtime has not completed bootstrap")]
22    NotBootstrapped,
23    /// Another runtime already supplies IcyDB's storage authority.
24    #[error("IcyDB is already bound to a different memory runtime")]
25    AlreadyBound,
26}
27
28/// Bind a bootstrapped host runtime before opening IcyDB stores.
29///
30/// Composed hosts bootstrap their complete declarations and retain the same
31/// `Rc` for their other consumers. Rebinding that exact instance is idempotent;
32/// replacing it is rejected so existing handles cannot acquire another authority.
33pub fn bind_memory_runtime(
34    runtime: Rc<MemoryRuntime<DefaultMemoryImpl>>,
35) -> Result<(), MemoryRuntimeBindingError> {
36    if !runtime.is_bootstrapped() {
37        return Err(MemoryRuntimeBindingError::NotBootstrapped);
38    }
39    MEMORY_RUNTIME.with(|bound| {
40        if let Some(existing) = bound.get() {
41            return if Rc::ptr_eq(existing, &runtime) {
42                Ok(())
43            } else {
44                Err(MemoryRuntimeBindingError::AlreadyBound)
45            };
46        }
47        bound
48            .set(runtime)
49            .map_err(|_| MemoryRuntimeBindingError::AlreadyBound)
50    })
51}
52
53/// Return the bound host runtime without constructing or bootstrapping memory.
54#[must_use]
55pub fn memory_runtime() -> Option<Rc<MemoryRuntime<DefaultMemoryImpl>>> {
56    MEMORY_RUNTIME.with(|bound| bound.get().cloned())
57}
58
59/// Open a declared key through IcyDB's bound host runtime.
60#[doc(hidden)]
61pub fn open_memory(stable_key: &str) -> Result<RuntimeMemory<DefaultMemoryImpl>, RuntimeOpenError> {
62    memory_runtime()
63        .ok_or(RuntimeOpenError::NotBootstrapped)?
64        .open_memory(stable_key)
65}