Skip to main content

ic_memory/runtime/
default.rs

1use super::{
2    MemoryRuntime, RuntimeBootstrapError, RuntimeConstructionError, RuntimeDiagnosticError,
3    RuntimeOpenError, RuntimeStateError, policy::NoopPolicy,
4};
5use crate::{
6    CommittedAllocations, DiagnosticExport, MemoryRuntimeDoctorReport, RuntimeBootstrapPolicy,
7    physical::CommitStoreDiagnostic, registry::sealed_declaration_snapshot,
8};
9use ic_stable_structures::{DefaultMemoryImpl, memory_manager::VirtualMemory};
10use std::{cell::RefCell, convert::Infallible};
11
12thread_local! {
13    static DEFAULT_RUNTIME:
14        RefCell<Result<MemoryRuntime<DefaultMemoryImpl>, RuntimeConstructionError>> =
15        RefCell::new(MemoryRuntime::new(DefaultMemoryImpl::default()));
16}
17
18fn with_default_runtime<T, E>(
19    operation: impl FnOnce(&MemoryRuntime<DefaultMemoryImpl>) -> Result<T, E>,
20) -> Result<T, E>
21where
22    E: From<RuntimeStateError>,
23{
24    match DEFAULT_RUNTIME.try_with(|runtime| {
25        let runtime = runtime
26            .try_borrow()
27            .map_err(|_| E::from(RuntimeStateError::ReentrantAccess))?;
28        let runtime = runtime
29            .as_ref()
30            .map_err(|error| E::from(RuntimeStateError::Construction(*error)))?;
31        operation(runtime)
32    }) {
33        Ok(result) => result,
34        Err(_) => Err(E::from(RuntimeStateError::Unavailable)),
35    }
36}
37
38fn with_default_runtime_mut<T, E>(
39    operation: impl FnOnce(&mut MemoryRuntime<DefaultMemoryImpl>) -> Result<T, E>,
40) -> Result<T, E>
41where
42    E: From<RuntimeStateError>,
43{
44    match DEFAULT_RUNTIME.try_with(|runtime| {
45        let mut runtime = runtime
46            .try_borrow_mut()
47            .map_err(|_| E::from(RuntimeStateError::ReentrantAccess))?;
48        let runtime = runtime
49            .as_mut()
50            .map_err(|error| E::from(RuntimeStateError::Construction(*error)))?;
51        operation(runtime)
52    }) {
53        Ok(result) => result,
54        Err(_) => Err(E::from(RuntimeStateError::Unavailable)),
55    }
56}
57
58/// Return whether this thread's default runtime has completed bootstrap.
59pub fn is_default_memory_manager_bootstrapped() -> Result<bool, RuntimeStateError> {
60    with_default_runtime(|runtime| Ok(runtime.is_bootstrapped()))
61}
62
63/// Return this thread's default runtime committed allocation capability.
64pub fn committed_allocations() -> Result<CommittedAllocations, RuntimeOpenError> {
65    with_default_runtime(|runtime| runtime.committed_allocations().cloned())
66}
67
68/// Bootstrap this thread's default runtime using generic range policy.
69pub fn bootstrap_default_memory_manager()
70-> Result<CommittedAllocations, RuntimeBootstrapError<Infallible>> {
71    bootstrap_default_memory_manager_with_policy(&NoopPolicy)
72}
73
74/// Bootstrap this thread's default runtime with caller-supplied policy.
75///
76/// Static declarations are sealed once per linked program. Recovery, policy
77/// evaluation, persistence, and capability publication occur once for this
78/// concrete TLS runtime. Repeated calls must supply the policy identity bound
79/// by the successful bootstrap.
80pub fn bootstrap_default_memory_manager_with_policy<P: RuntimeBootstrapPolicy>(
81    policy: &P,
82) -> Result<CommittedAllocations, RuntimeBootstrapError<P::Error>> {
83    let declarations = sealed_declaration_snapshot()?;
84    with_default_runtime_mut(|runtime| runtime.bootstrap(&declarations, policy).cloned())
85}
86
87/// Open a committed memory from this thread's default runtime.
88pub fn open_default_memory_manager_memory(
89    stable_key: &str,
90    id: u8,
91) -> Result<VirtualMemory<DefaultMemoryImpl>, RuntimeOpenError> {
92    with_default_runtime(|runtime| runtime.open_memory(stable_key, id))
93}
94
95/// Export this thread's default runtime ledger and live memory sizes.
96pub fn default_memory_manager_diagnostic_export() -> Result<DiagnosticExport, RuntimeDiagnosticError>
97{
98    with_default_runtime(MemoryRuntime::diagnostic_export)
99}
100
101/// Diagnose protected commit recovery for this thread's default runtime.
102pub fn default_memory_manager_commit_recovery_diagnostic()
103-> Result<CommitStoreDiagnostic, RuntimeDiagnosticError> {
104    with_default_runtime(MemoryRuntime::commit_recovery_diagnostic)
105}
106
107/// Build preflight and lifecycle diagnostics for this thread's default runtime.
108pub fn default_memory_manager_doctor_report()
109-> Result<MemoryRuntimeDoctorReport, RuntimeDiagnosticError> {
110    let declarations = sealed_declaration_snapshot()?;
111    with_default_runtime(|runtime| Ok(runtime.doctor_report(&declarations)))
112}
113
114#[cfg(test)]
115pub(super) fn with_default_runtime_borrowed(
116    operation: impl FnOnce() -> Result<(), RuntimeStateError>,
117) -> Result<(), RuntimeStateError> {
118    DEFAULT_RUNTIME.with(|runtime| {
119        let _borrow = runtime.borrow_mut();
120        operation()
121    })
122}