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 fn from_declaration(declaration: &AllocationDeclaration, state: AllocationState) -> Self {
110 Self {
111 stable_key: declaration.stable_key.clone(),
112 slot: declaration.slot.clone(),
113 state,
114 schema: declaration.schema.clone(),
115 }
116 }
117
118 pub(crate) fn active(declaration: &AllocationDeclaration) -> Self {
119 Self::from_declaration(declaration, AllocationState::Active)
120 }
121
122 #[cfg(any(test, feature = "test-support"))]
123 pub(crate) fn reserved(declaration: &AllocationDeclaration) -> Self {
124 Self::from_declaration(declaration, AllocationState::Reserved)
125 }
126
127 #[must_use]
129 pub const fn stable_key(&self) -> &StableKey {
130 &self.stable_key
131 }
132
133 #[must_use]
135 pub const fn slot(&self) -> &MemoryManagerSlot {
136 &self.slot
137 }
138
139 #[must_use]
141 pub const fn state(&self) -> AllocationState {
142 self.state
143 }
144
145 #[must_use]
147 pub const fn schema(&self) -> &SchemaMetadata {
148 &self.schema
149 }
150}
151
152impl AllocationLedger {
153 pub(crate) const fn empty_genesis() -> Self {
154 Self {
155 current_generation: 0,
156 records: Vec::new(),
157 }
158 }
159
160 pub fn new(
163 current_generation: u64,
164 records: Vec<AllocationRecord>,
165 ) -> Result<Self, LedgerIntegrityError> {
166 let ledger = Self {
167 current_generation,
168 records,
169 };
170 ledger.validate_integrity()?;
171 Ok(ledger)
172 }
173
174 #[must_use]
176 pub const fn current_generation(&self) -> u64 {
177 self.current_generation
178 }
179
180 #[must_use]
182 pub fn records(&self) -> &[AllocationRecord] {
183 &self.records
184 }
185
186 pub(crate) fn occupied_slots(&self) -> [bool; crate::constants::MAX_ALLOCATIONS] {
188 let mut occupied = [false; crate::constants::MAX_ALLOCATIONS];
189 for record in &self.records {
190 occupied[usize::from(record.slot.id())] = true;
191 }
192 occupied
193 }
194}