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