ic_memory/runtime/
admission.rs1use crate::{
2 AllocationLedger, AllocationState, MemoryManagerSlot, MemoryRequest, SchemaMetadata,
3 SealedDeclarationSnapshot, StableKey,
4};
5
6#[derive(Clone, Copy, Debug)]
15pub struct RecoveredAllocationMetadata<'a> {
16 pub stable_key: &'a StableKey,
18 pub slot: &'a MemoryManagerSlot,
20 pub state: AllocationState,
22 pub schema: &'a SchemaMetadata,
24}
25
26#[non_exhaustive]
33#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)]
34pub enum BootstrapAdmissionError {
35 #[error("historical key {0} is unknown")]
36 Unknown(StableKey),
37 #[error("historical key {0} is retired")]
38 Retired(StableKey),
39 #[error("key {0} is already declared or selected")]
40 Duplicate(StableKey),
41 #[error("completed declarations exceed 254 external allocations")]
42 TooManyDeclarations,
43 #[error(transparent)]
44 Pool(#[from] crate::MemoryAllocationPoolError),
45 #[error(transparent)]
46 Registry(#[from] crate::StaticMemoryDeclarationError),
47}
48
49pub struct BootstrapAdmission<'a> {
60 ledger: &'a AllocationLedger,
61 declarations: &'a SealedDeclarationSnapshot,
62 pool: &'a crate::MemoryAllocationPool,
63 selected: Vec<MemoryRequest>,
64 failure: Option<BootstrapAdmissionError>,
65}
66
67impl<'a> BootstrapAdmission<'a> {
68 pub(super) const fn new(
69 ledger: &'a AllocationLedger,
70 declarations: &'a SealedDeclarationSnapshot,
71 pool: &'a crate::MemoryAllocationPool,
72 ) -> Self {
73 Self {
74 ledger,
75 declarations,
76 pool,
77 selected: Vec::new(),
78 failure: None,
79 }
80 }
81
82 #[must_use]
84 pub const fn declarations(&self) -> &SealedDeclarationSnapshot {
85 self.declarations
86 }
87
88 #[must_use = "recovered allocation metadata is inspected only when the iterator is consumed"]
94 pub fn recovered_allocations(
95 &self,
96 ) -> impl ExactSizeIterator<Item = RecoveredAllocationMetadata<'_>> {
97 self.ledger
98 .records()
99 .iter()
100 .map(|record| RecoveredAllocationMetadata {
101 stable_key: record.stable_key(),
102 slot: record.slot(),
103 state: record.state(),
104 schema: record.schema(),
105 })
106 }
107
108 #[must_use]
110 pub fn is_declared(&self, key: &StableKey) -> bool {
111 key.as_str() == crate::IC_MEMORY_LEDGER_STABLE_KEY
114 || self
115 .declarations
116 .requests()
117 .binary_search_by(|request| request.stable_key().cmp(key))
118 .is_ok()
119 || self
120 .selected
121 .iter()
122 .any(|request| request.stable_key() == key)
123 }
124
125 pub fn include_historical(
129 &mut self,
130 authority: &str,
131 stable_key: &str,
132 ) -> Result<(), BootstrapAdmissionError> {
133 if let Some(error) = &self.failure {
134 return Err(error.clone());
135 }
136 let result = self.select(authority, stable_key);
137 if let Err(error) = &result {
138 self.failure = Some(error.clone());
139 }
140 result
141 }
142
143 fn select(&mut self, authority: &str, stable_key: &str) -> Result<(), BootstrapAdmissionError> {
144 let request = MemoryRequest::new(authority, stable_key, SchemaMetadata::default())?;
146 let key = request.stable_key();
147 if self.is_declared(key) {
148 return Err(BootstrapAdmissionError::Duplicate(key.clone()));
149 }
150 if self.declarations.requests().len() + self.selected.len() >= 254 {
151 return Err(BootstrapAdmissionError::TooManyDeclarations);
152 }
153 let record = self
154 .ledger
155 .records()
156 .iter()
157 .find(|r| r.stable_key() == key)
158 .ok_or_else(|| BootstrapAdmissionError::Unknown(key.clone()))?;
159 if matches!(record.state(), AllocationState::Retired) {
160 return Err(BootstrapAdmissionError::Retired(key.clone()));
161 }
162 self.pool.validate_authority(key, authority)?;
163 self.pool.validate_id(record.slot().id())?;
164 self.selected
165 .push(request.with_schema(record.schema().clone()));
166 Ok(())
167 }
168
169 pub(super) fn complete(self) -> Result<Vec<MemoryRequest>, BootstrapAdmissionError> {
170 if let Some(error) = self.failure {
171 return Err(error);
172 }
173 Ok(self.selected)
174 }
175}