ic_memory/runtime/
admission.rs1use crate::{
2 AllocationDeclaration, AllocationLedger, AllocationRecord, AllocationState,
3 SealedDeclarationSnapshot, StableKey,
4};
5
6#[non_exhaustive]
13#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)]
14pub enum BootstrapAdmissionError {
15 #[error("historical key {0} is unknown")]
16 Unknown(StableKey),
17 #[error("historical key {0} is retired")]
18 Retired(StableKey),
19 #[error("key {0} is already declared or selected")]
20 Duplicate(StableKey),
21 #[error("completed declarations exceed 254 external allocations")]
22 TooManyDeclarations,
23 #[error(transparent)]
24 Pool(#[from] crate::MemoryAllocationPoolError),
25 #[error(transparent)]
26 Declarations(#[from] crate::MemoryDeclarationError),
27}
28
29pub struct BootstrapAdmission<'a> {
40 ledger: &'a AllocationLedger,
41 declarations: &'a SealedDeclarationSnapshot,
42 pool: &'a crate::MemoryAllocationPool,
43 selected: Vec<AllocationDeclaration>,
44 failure: Option<BootstrapAdmissionError>,
45}
46
47impl<'a> BootstrapAdmission<'a> {
48 pub(super) const fn new(
49 ledger: &'a AllocationLedger,
50 declarations: &'a SealedDeclarationSnapshot,
51 pool: &'a crate::MemoryAllocationPool,
52 ) -> Self {
53 Self {
54 ledger,
55 declarations,
56 pool,
57 selected: Vec::new(),
58 failure: None,
59 }
60 }
61
62 #[must_use]
64 pub const fn declarations(&self) -> &SealedDeclarationSnapshot {
65 self.declarations
66 }
67
68 #[must_use = "recovered allocation metadata is inspected only when the iterator is consumed"]
72 pub fn recovered_allocations(&self) -> impl ExactSizeIterator<Item = &AllocationRecord> {
73 self.ledger.records().iter()
74 }
75
76 #[must_use]
78 pub fn is_declared(&self, key: &StableKey) -> bool {
79 key.as_str() == crate::IC_MEMORY_LEDGER_STABLE_KEY
82 || self
83 .declarations
84 .requests()
85 .binary_search_by(|request| request.stable_key().cmp(key))
86 .is_ok()
87 || self
88 .selected
89 .iter()
90 .any(|declaration| declaration.stable_key() == key)
91 }
92
93 pub fn include_historical(
97 &mut self,
98 authority: &str,
99 stable_key: &str,
100 ) -> Result<(), BootstrapAdmissionError> {
101 if let Some(error) = &self.failure {
102 return Err(error.clone());
103 }
104 let result = self.select(authority, stable_key);
105 if let Err(error) = &result {
106 self.failure = Some(error.clone());
107 }
108 result
109 }
110
111 fn select(&mut self, authority: &str, stable_key: &str) -> Result<(), BootstrapAdmissionError> {
112 let key = crate::requests::checked_request_key(authority, stable_key)?;
115 if self.is_declared(&key) {
116 return Err(BootstrapAdmissionError::Duplicate(key));
117 }
118 if self.declarations.requests().len() + self.selected.len() >= 254 {
119 return Err(BootstrapAdmissionError::TooManyDeclarations);
120 }
121 let Some(record) = self
122 .ledger
123 .records()
124 .iter()
125 .find(|r| r.stable_key() == &key)
126 else {
127 return Err(BootstrapAdmissionError::Unknown(key));
128 };
129 if matches!(record.state(), AllocationState::Retired) {
130 return Err(BootstrapAdmissionError::Retired(key));
131 }
132 self.pool.validate_authority(&key, authority)?;
133 self.pool.validate_id(record.slot().id())?;
134 self.selected.push(AllocationDeclaration {
135 stable_key: key,
136 slot: record.slot().clone(),
137 schema: record.schema().clone(),
138 });
139 Ok(())
140 }
141
142 pub(super) fn complete(self) -> Result<Vec<AllocationDeclaration>, BootstrapAdmissionError> {
143 if let Some(error) = self.failure {
144 return Err(error);
145 }
146 Ok(self.selected)
147 }
148}