ic_memory/ledger/
record.rs1use super::LedgerIntegrityError;
2use crate::{
3 declaration::AllocationDeclaration, key::StableKey, schema::SchemaMetadata,
4 slot::MemoryManagerSlot,
5};
6use serde::{Deserialize, Serialize};
7
8#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
20#[serde(deny_unknown_fields)]
21pub struct AllocationLedger {
22 pub(crate) current_generation: u64,
23 #[serde(deserialize_with = "crate::cbor::deserialize_records")]
24 pub(crate) records: Vec<AllocationRecord>,
25}
26
27#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
36#[serde(deny_unknown_fields)]
37pub struct AllocationRecord {
38 pub(crate) stable_key: StableKey,
39 pub(crate) slot: MemoryManagerSlot,
40 pub(crate) state: AllocationState,
41 pub(crate) schema: SchemaMetadata,
42}
43
44#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
52#[serde(deny_unknown_fields)]
53pub enum AllocationState {
54 Reserved,
56 Active,
58 Retired,
60}
61
62#[derive(Clone, Debug, Eq, PartialEq)]
72pub struct RecoveredLedger {
73 ledger: AllocationLedger,
74}
75
76impl RecoveredLedger {
77 pub(crate) fn genesis_for_absent_snapshot(error: &super::LedgerCommitError) -> Option<Self> {
80 matches!(
81 error,
82 super::LedgerCommitError::Recovery(crate::CommitRecoveryError::NoValidGeneration)
83 )
84 .then(|| Self::from_trusted_ledger(AllocationLedger::empty_genesis()))
85 }
86
87 pub(crate) const fn from_trusted_ledger(ledger: AllocationLedger) -> Self {
88 Self { ledger }
89 }
90
91 #[must_use]
93 pub const fn ledger(&self) -> &AllocationLedger {
94 &self.ledger
95 }
96
97 #[must_use]
99 pub const fn current_generation(&self) -> u64 {
100 self.ledger.current_generation
101 }
102
103 pub(crate) fn into_ledger(self) -> AllocationLedger {
104 self.ledger
105 }
106}
107
108impl AllocationRecord {
109 pub(crate) fn from_declaration(
110 declaration: &AllocationDeclaration,
111 state: AllocationState,
112 ) -> Self {
113 Self {
114 stable_key: declaration.stable_key.clone(),
115 slot: declaration.slot.clone(),
116 state,
117 schema: declaration.schema.clone(),
118 }
119 }
120
121 pub(crate) fn active(declaration: &AllocationDeclaration) -> Self {
122 Self::from_declaration(declaration, AllocationState::Active)
123 }
124
125 #[cfg(test)]
126 pub(crate) fn reserved(declaration: &AllocationDeclaration) -> Self {
127 Self::from_declaration(declaration, AllocationState::Reserved)
128 }
129
130 #[must_use]
132 pub const fn stable_key(&self) -> &StableKey {
133 &self.stable_key
134 }
135
136 #[must_use]
138 pub const fn slot(&self) -> &MemoryManagerSlot {
139 &self.slot
140 }
141
142 #[must_use]
144 pub const fn state(&self) -> AllocationState {
145 self.state
146 }
147
148 #[must_use]
150 pub const fn schema(&self) -> &SchemaMetadata {
151 &self.schema
152 }
153}
154
155impl AllocationLedger {
156 pub(crate) const fn empty_genesis() -> Self {
157 Self {
158 current_generation: 0,
159 records: Vec::new(),
160 }
161 }
162
163 pub fn new(
166 current_generation: u64,
167 records: Vec<AllocationRecord>,
168 ) -> Result<Self, LedgerIntegrityError> {
169 let ledger = Self {
170 current_generation,
171 records,
172 };
173 ledger.validate_integrity()?;
174 Ok(ledger)
175 }
176
177 #[must_use]
179 pub const fn current_generation(&self) -> u64 {
180 self.current_generation
181 }
182
183 #[must_use]
185 pub fn records(&self) -> &[AllocationRecord] {
186 &self.records
187 }
188
189 pub(crate) fn occupied_slots(&self) -> [bool; crate::constants::MAX_ALLOCATIONS] {
191 let mut occupied = [false; crate::constants::MAX_ALLOCATIONS];
192 for record in &self.records {
193 occupied[usize::from(record.slot.id())] = true;
194 }
195 occupied
196 }
197}