1use crate::{
2 declaration::{AllocationDeclaration, DeclarationSnapshot},
3 schema::SchemaMetadata,
4 slot::{
5 IC_MEMORY_AUTHORITY_OWNER, IC_MEMORY_LEDGER_STABLE_KEY, MEMORY_MANAGER_LEDGER_ID,
6 is_ic_memory_stable_key,
7 },
8 text::validate_diagnostic_text,
9};
10use serde::{Deserialize, Serialize};
11use std::sync::Arc;
12
13#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
21pub struct MemoryRequest {
22 authority: String,
23 stable_key: crate::StableKey,
24 schema: SchemaMetadata,
25}
26
27impl<'de> Deserialize<'de> for MemoryRequest {
28 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
29 use serde::de::Error as _;
30 #[derive(Deserialize)]
31 #[serde(deny_unknown_fields)]
32 struct Request {
33 authority: String,
34 stable_key: crate::StableKey,
35 schema: SchemaMetadata,
36 }
37 let request = Request::deserialize(deserializer)?;
38 validate_external_authority(&request.authority).map_err(D::Error::custom)?;
39 validate_external_key(&request.stable_key).map_err(D::Error::custom)?;
40 Ok(Self {
41 authority: request.authority,
42 stable_key: request.stable_key,
43 schema: request.schema,
44 })
45 }
46}
47
48impl MemoryRequest {
49 pub fn new(
51 authority: impl Into<String>,
52 stable_key: &str,
53 schema: SchemaMetadata,
54 ) -> Result<Self, MemoryDeclarationError> {
55 let authority = authority.into();
56 let stable_key = checked_request_key(&authority, stable_key)?;
57 Ok(Self {
58 authority,
59 stable_key,
60 schema,
61 })
62 }
63
64 #[must_use]
66 pub const fn stable_key(&self) -> &crate::StableKey {
67 &self.stable_key
68 }
69
70 #[must_use]
72 pub const fn schema(&self) -> &SchemaMetadata {
73 &self.schema
74 }
75
76 #[must_use]
78 pub fn authority(&self) -> &str {
79 &self.authority
80 }
81}
82
83#[non_exhaustive]
90#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
91pub enum MemoryDeclarationError {
92 #[error("at most 254 external requests are supported")]
93 TooManyDeclarations,
94 #[error("duplicate requested stable key {stable_key}")]
95 DuplicateRequest { stable_key: crate::StableKey },
96 #[error(transparent)]
98 Declaration(#[from] crate::DeclarationSnapshotError),
99 #[error("authority {reason}")]
101 InvalidAuthority {
102 reason: &'static str,
104 },
105 #[error("authority '{authority}' is reserved for ic-memory runtime internals")]
107 ReservedAuthority {
108 authority: String,
110 },
111 #[error("stable key '{stable_key}' is reserved for ic-memory runtime internals")]
113 ReservedStableKey {
114 stable_key: String,
116 },
117}
118
119#[derive(Clone, Debug, Eq, PartialEq)]
131pub struct SealedDeclarationSnapshot {
132 inner: Arc<Vec<MemoryRequest>>,
133}
134
135impl SealedDeclarationSnapshot {
136 pub fn new(mut requests: Vec<MemoryRequest>) -> Result<Self, MemoryDeclarationError> {
139 if requests.len() > 254 {
140 return Err(MemoryDeclarationError::TooManyDeclarations);
141 }
142 crate::sort::sort_unstable_by(&mut requests, |a, b| a.stable_key.cmp(&b.stable_key));
143 for pair in requests.windows(2) {
144 if pair[0].stable_key == pair[1].stable_key {
145 return Err(MemoryDeclarationError::DuplicateRequest {
146 stable_key: pair[1].stable_key.clone(),
147 });
148 }
149 }
150 Ok(Self {
151 inner: Arc::new(requests),
152 })
153 }
154
155 #[must_use]
157 pub fn requests(&self) -> &[MemoryRequest] {
158 &self.inner
159 }
160
161 pub(crate) fn resolve(
162 &self,
163 ledger: &crate::AllocationLedger,
164 occupied: &[bool; crate::constants::MAX_ALLOCATIONS],
165 historical: Vec<AllocationDeclaration>,
166 pool: &crate::MemoryAllocationPool,
167 ) -> Result<DeclarationSnapshot, crate::MemoryResolutionError> {
168 if self.requests().len() + historical.len() > 254 {
169 return Err(MemoryDeclarationError::TooManyDeclarations.into());
170 }
171 let mut declarations = Vec::with_capacity(self.requests().len() + historical.len() + 1);
172 declarations.push(internal_ledger_declaration());
173 let mut available_ids = 0..crate::MEMORY_MANAGER_INVALID_ID;
176 for request in self.requests() {
179 let historical = ledger
180 .records()
181 .iter()
182 .find(|record| record.stable_key() == &request.stable_key);
183 pool.validate_authority(&request.stable_key, &request.authority)?;
184 let id = if let Some(record) = historical {
185 pool.validate_id(record.slot().id())?;
188 record.slot().id()
189 } else {
190 available_ids
191 .find(|id| pool.contains(*id) && !occupied[usize::from(*id)])
192 .ok_or_else(|| crate::MemoryResolutionError::Exhausted {
193 stable_key: request.stable_key.clone(),
194 authority: request.authority.clone(),
195 })?
196 };
197 let slot = crate::MemoryManagerSlot::new(id).expect("usable id");
198 declarations.push(AllocationDeclaration {
202 stable_key: request.stable_key.clone(),
203 slot,
204 schema: request.schema.clone(),
205 });
206 }
207 declarations.extend(historical);
208 Ok(
209 DeclarationSnapshot::canonicalize(declarations)
210 .map_err(MemoryDeclarationError::from)?,
211 )
212 }
213
214 #[cfg(test)]
215 pub(crate) fn shares_storage_with(&self, other: &Self) -> bool {
216 Arc::ptr_eq(&self.inner, &other.inner)
217 }
218}
219
220pub fn checked_request_key(
222 authority: &str,
223 stable_key: &str,
224) -> Result<crate::StableKey, MemoryDeclarationError> {
225 validate_external_authority(authority)?;
226 let stable_key =
227 crate::StableKey::parse(stable_key).map_err(crate::DeclarationSnapshotError::Key)?;
228 validate_external_key(&stable_key)?;
229 Ok(stable_key)
230}
231
232fn validate_external_key(stable_key: &crate::StableKey) -> Result<(), MemoryDeclarationError> {
233 if is_ic_memory_stable_key(stable_key.as_str()) {
234 return Err(MemoryDeclarationError::ReservedStableKey {
235 stable_key: stable_key.as_str().to_string(),
236 });
237 }
238 Ok(())
239}
240
241fn validate_external_authority(value: &str) -> Result<(), MemoryDeclarationError> {
242 reject_internal_authority(value)?;
243 validate_diagnostic_text(value).map_err(|error| MemoryDeclarationError::InvalidAuthority {
244 reason: error.reason(),
245 })
246}
247
248fn reject_internal_authority(value: &str) -> Result<(), MemoryDeclarationError> {
249 if value == IC_MEMORY_AUTHORITY_OWNER {
250 return Err(MemoryDeclarationError::ReservedAuthority {
251 authority: value.to_string(),
252 });
253 }
254 Ok(())
255}
256
257fn internal_ledger_declaration() -> AllocationDeclaration {
258 AllocationDeclaration::memory_manager(IC_MEMORY_LEDGER_STABLE_KEY, MEMORY_MANAGER_LEDGER_ID)
259 .unwrap_or_else(|_| unreachable!("built-in ledger declaration constants are valid"))
260}
261
262#[cfg(test)]
263mod tests;