Skip to main content

ic_memory/ledger/
error.rs

1use crate::{
2    declaration::DeclarationSnapshotError,
3    key::{StableKey, StableKeyError},
4    ledger::LedgerPayloadEnvelopeError,
5    physical::CommitRecoveryError,
6    schema::SchemaMetadataError,
7    slot::{AllocationSlotDescriptor, MemoryManagerSlotError},
8};
9
10///
11/// LedgerIntegrityError
12///
13/// Decoded ledger violates structural allocation-history invariants.
14#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
15pub enum LedgerIntegrityError {
16    /// Stable-key grammar was invalid after durable decode.
17    #[error(transparent)]
18    InvalidStableKey(StableKeyError),
19    /// Allocation slot descriptor was invalid after durable decode.
20    #[error(transparent)]
21    InvalidSlotDescriptor(MemoryManagerSlotError),
22    /// Stable key appears in more than one allocation record.
23    #[error("stable key '{stable_key}' appears in more than one allocation record")]
24    DuplicateStableKey {
25        /// Duplicate stable key.
26        stable_key: StableKey,
27    },
28    /// Allocation slot appears in more than one allocation record.
29    #[error("allocation slot '{slot:?}' appears in more than one allocation record")]
30    DuplicateSlot {
31        /// Duplicate allocation slot.
32        slot: Box<AllocationSlotDescriptor>,
33    },
34    /// Allocation record generation ordering is invalid.
35    #[error("stable key '{stable_key}' has first_generation after last_seen_generation")]
36    InvalidRecordGenerationOrder {
37        /// Stable key whose record is invalid.
38        stable_key: StableKey,
39        /// First generation in the record.
40        first_generation: u64,
41        /// Last seen generation in the record.
42        last_seen_generation: u64,
43    },
44    /// Allocation record points past the current generation.
45    #[error(
46        "stable key '{stable_key}' references generation {generation} after current generation {current_generation}"
47    )]
48    FutureRecordGeneration {
49        /// Stable key whose record is invalid.
50        stable_key: StableKey,
51        /// Generation referenced by the record.
52        generation: u64,
53        /// Current ledger generation.
54        current_generation: u64,
55    },
56    /// Non-retired allocation carries retired metadata.
57    #[error("stable key '{stable_key}' is not retired but has retired_generation metadata")]
58    UnexpectedRetiredGeneration {
59        /// Stable key whose record is invalid.
60        stable_key: StableKey,
61    },
62    /// Retired allocation is missing retired metadata.
63    #[error("stable key '{stable_key}' is retired but retired_generation is missing")]
64    MissingRetiredGeneration {
65        /// Stable key whose record is invalid.
66        stable_key: StableKey,
67    },
68    /// Retired generation predates the allocation record.
69    #[error("stable key '{stable_key}' has retired_generation before first_generation")]
70    RetiredBeforeFirstGeneration {
71        /// Stable key whose record is invalid.
72        stable_key: StableKey,
73        /// First generation in the record.
74        first_generation: u64,
75        /// Retired generation in the record.
76        retired_generation: u64,
77    },
78    /// Allocation record has no schema metadata history.
79    #[error("stable key '{stable_key}' has empty schema metadata history")]
80    EmptySchemaHistory {
81        /// Stable key whose record is invalid.
82        stable_key: StableKey,
83    },
84    /// Schema metadata generation history is not strictly increasing.
85    #[error("stable key '{stable_key}' has non-increasing schema metadata generation history")]
86    NonIncreasingSchemaHistory {
87        /// Stable key whose record is invalid.
88        stable_key: StableKey,
89    },
90    /// Schema metadata generation is outside the allocation record lifetime.
91    #[error("stable key '{stable_key}' has schema metadata generation outside the ledger bounds")]
92    SchemaHistoryOutOfBounds {
93        /// Stable key whose record is invalid.
94        stable_key: StableKey,
95        /// Schema metadata generation.
96        generation: u64,
97    },
98    /// Schema metadata in committed allocation history is invalid.
99    #[error("stable key '{stable_key}' has invalid schema metadata at generation {generation}")]
100    InvalidSchemaMetadata {
101        /// Stable key whose schema metadata is invalid.
102        stable_key: StableKey,
103        /// Generation that recorded the invalid schema metadata.
104        generation: u64,
105        /// Schema metadata validation error.
106        error: SchemaMetadataError,
107    },
108    /// Generation record appears more than once.
109    #[error("generation {generation} appears more than once")]
110    DuplicateGeneration {
111        /// Duplicate generation.
112        generation: u64,
113    },
114    /// Generation record points past the current generation.
115    #[error("generation {generation} is after current generation {current_generation}")]
116    FutureGeneration {
117        /// Generation record value.
118        generation: u64,
119        /// Current ledger generation.
120        current_generation: u64,
121    },
122    /// Generation parent does not precede the child generation.
123    #[error("generation {generation} has invalid parent generation {parent_generation}")]
124    InvalidParentGeneration {
125        /// Generation record value.
126        generation: u64,
127        /// Invalid parent generation.
128        parent_generation: u64,
129    },
130    /// Current ledger generation has no committed generation record.
131    #[error("current generation {current_generation} has no committed generation record")]
132    MissingCurrentGenerationRecord {
133        /// Current ledger generation.
134        current_generation: u64,
135    },
136    /// Generation records are not strictly increasing in durable order.
137    #[error("generation records are not strictly increasing at generation {generation}")]
138    NonIncreasingGenerationRecords {
139        /// Non-increasing generation.
140        generation: u64,
141    },
142    /// Generation record parent does not match the previous committed generation.
143    #[error(
144        "generation {generation} does not link to previous committed generation {expected_parent}"
145    )]
146    BrokenGenerationChain {
147        /// Generation whose parent link is invalid.
148        generation: u64,
149        /// Expected parent generation.
150        expected_parent: u64,
151        /// Actual parent generation.
152        actual_parent: u64,
153    },
154    /// Allocation record refers to a generation absent from committed history.
155    #[error("stable key '{stable_key}' references unknown generation {generation}")]
156    UnknownRecordGeneration {
157        /// Stable key whose record is invalid.
158        stable_key: StableKey,
159        /// Unknown generation.
160        generation: u64,
161    },
162    /// Generation diagnostic metadata is invalid.
163    #[error(transparent)]
164    DiagnosticMetadata(DeclarationSnapshotError),
165}
166
167///
168/// LedgerCommitError
169///
170/// Failure to recover or commit a logical allocation ledger.
171#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
172pub enum LedgerCommitError {
173    /// Protected physical commit recovery failed.
174    #[error(transparent)]
175    Recovery(CommitRecoveryError),
176    /// Logical ledger payload envelope could not be decoded.
177    #[error(transparent)]
178    PayloadEnvelope(LedgerPayloadEnvelopeError),
179    /// Physical slot generation and decoded logical ledger generation disagree.
180    #[error(
181        "physical generation {physical_generation} does not match logical ledger generation {logical_generation}"
182    )]
183    PhysicalLogicalGenerationMismatch {
184        /// Generation encoded in the physical commit slot.
185        physical_generation: u64,
186        /// Generation decoded from the logical allocation ledger.
187        logical_generation: u64,
188    },
189    /// Built-in ledger codec failed.
190    #[error("allocation ledger codec failed")]
191    Codec(String),
192    /// Decoded ledger violates structural allocation-history invariants.
193    #[error(transparent)]
194    Integrity(LedgerIntegrityError),
195}
196
197///
198/// AllocationStageError
199///
200/// Failure to stage a validated allocation generation.
201#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
202pub enum AllocationStageError {
203    /// Validated declarations were produced against a different ledger generation.
204    #[error(
205        "validated allocations were produced at generation {validated_generation}, but ledger is at generation {ledger_generation}"
206    )]
207    StaleValidatedAllocations {
208        /// Generation carried by the validated allocation session.
209        validated_generation: u64,
210        /// Current ledger generation.
211        ledger_generation: u64,
212    },
213    /// Ledger generation cannot be advanced without overflow.
214    #[error("ledger generation {generation} cannot be advanced without overflow")]
215    GenerationOverflow {
216        /// Current ledger generation.
217        generation: u64,
218    },
219    /// Declaration count does not fit in durable generation diagnostics.
220    #[error("generation contains {count} declarations, exceeding the durable u32 diagnostic limit")]
221    TooManyDeclarations {
222        /// Number of declarations in the staged generation.
223        count: usize,
224    },
225    /// A staged declaration carries invalid schema metadata.
226    #[error("stable key '{stable_key}' has invalid schema metadata")]
227    InvalidSchemaMetadata {
228        /// Stable key whose schema metadata is invalid.
229        stable_key: StableKey,
230        /// Schema metadata validation error.
231        error: SchemaMetadataError,
232    },
233    /// Stable key was historically bound to a different slot.
234    #[error("stable key '{stable_key}' was historically bound to a different allocation slot")]
235    StableKeySlotConflict {
236        /// Stable key being declared.
237        stable_key: StableKey,
238        /// Historical slot for the stable key.
239        historical_slot: Box<AllocationSlotDescriptor>,
240        /// Slot claimed by the declaration.
241        declared_slot: Box<AllocationSlotDescriptor>,
242    },
243    /// Slot was historically bound to a different stable key.
244    #[error("allocation slot '{slot:?}' was historically bound to stable key '{historical_key}'")]
245    SlotStableKeyConflict {
246        /// Slot being declared.
247        slot: Box<AllocationSlotDescriptor>,
248        /// Historical stable key for the slot.
249        historical_key: StableKey,
250        /// Stable key claimed by the declaration.
251        declared_key: StableKey,
252    },
253    /// Current declaration attempted to revive a retired allocation.
254    #[error("stable key '{stable_key}' was explicitly retired and cannot be redeclared")]
255    RetiredAllocation {
256        /// Retired stable key.
257        stable_key: StableKey,
258        /// Retired allocation slot.
259        slot: Box<AllocationSlotDescriptor>,
260    },
261}
262
263///
264/// AllocationReservationError
265///
266/// Failure to stage a reservation generation.
267#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
268pub enum AllocationReservationError {
269    /// Ledger generation cannot be advanced without overflow.
270    #[error("ledger generation {generation} cannot be advanced without overflow")]
271    GenerationOverflow {
272        /// Current ledger generation.
273        generation: u64,
274    },
275    /// Declaration count does not fit in durable generation diagnostics.
276    #[error("generation contains {count} reservations, exceeding the durable u32 diagnostic limit")]
277    TooManyReservations {
278        /// Number of reservations in the staged generation.
279        count: usize,
280    },
281    /// A staged reservation carries invalid schema metadata.
282    #[error("stable key '{stable_key}' has invalid schema metadata")]
283    InvalidSchemaMetadata {
284        /// Stable key whose schema metadata is invalid.
285        stable_key: StableKey,
286        /// Schema metadata validation error.
287        error: SchemaMetadataError,
288    },
289    /// Stable key was historically bound to a different slot.
290    #[error("stable key '{stable_key}' was historically bound to a different allocation slot")]
291    StableKeySlotConflict {
292        /// Stable key being reserved.
293        stable_key: StableKey,
294        /// Historical slot for the stable key.
295        historical_slot: Box<AllocationSlotDescriptor>,
296        /// Slot claimed by the reservation.
297        reserved_slot: Box<AllocationSlotDescriptor>,
298    },
299    /// Slot was historically bound to a different stable key.
300    #[error("allocation slot '{slot:?}' was historically bound to stable key '{historical_key}'")]
301    SlotStableKeyConflict {
302        /// Slot being reserved.
303        slot: Box<AllocationSlotDescriptor>,
304        /// Historical stable key for the slot.
305        historical_key: StableKey,
306        /// Stable key claimed by the reservation.
307        reserved_key: StableKey,
308    },
309    /// Allocation already exists as an active record.
310    #[error("stable key '{stable_key}' is already active and cannot be reserved")]
311    ActiveAllocation {
312        /// Active stable key.
313        stable_key: StableKey,
314        /// Active allocation slot.
315        slot: Box<AllocationSlotDescriptor>,
316    },
317    /// Allocation was already retired and cannot be reserved.
318    #[error("stable key '{stable_key}' was explicitly retired and cannot be reserved")]
319    RetiredAllocation {
320        /// Retired stable key.
321        stable_key: StableKey,
322        /// Retired allocation slot.
323        slot: Box<AllocationSlotDescriptor>,
324    },
325}
326
327///
328/// AllocationRetirementError
329///
330/// Failure to stage an explicit retirement generation.
331#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
332pub enum AllocationRetirementError {
333    /// Stable-key grammar failure.
334    #[error(transparent)]
335    Key(StableKeyError),
336    /// Ledger generation cannot be advanced without overflow.
337    #[error("ledger generation {generation} cannot be advanced without overflow")]
338    GenerationOverflow {
339        /// Current ledger generation.
340        generation: u64,
341    },
342    /// Stable key has no historical allocation record.
343    #[error("stable key '{0}' has no allocation record to retire")]
344    UnknownStableKey(StableKey),
345    /// Stable key was historically bound to a different slot.
346    #[error("stable key '{stable_key}' cannot be retired for a different allocation slot")]
347    SlotMismatch {
348        /// Stable key being retired.
349        stable_key: StableKey,
350        /// Historical slot for the stable key.
351        historical_slot: Box<AllocationSlotDescriptor>,
352        /// Slot named by the retirement request.
353        retired_slot: Box<AllocationSlotDescriptor>,
354    },
355    /// Allocation was already retired.
356    #[error("stable key '{stable_key}' was already retired")]
357    AlreadyRetired {
358        /// Retired stable key.
359        stable_key: StableKey,
360        /// Retired allocation slot.
361        slot: Box<AllocationSlotDescriptor>,
362    },
363}