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: {0}")]
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 exceeds the usable allocation-slot domain.
253    #[error("generation contains {count} declarations, exceeding the 255-allocation 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}
295
296///
297/// AllocationReservationError
298///
299/// Failure to stage a reservation generation.
300#[non_exhaustive]
301#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
302pub enum AllocationReservationError {
303    #[error(transparent)]
304    Integrity(#[from] LedgerIntegrityError),
305    /// Ledger generation cannot be advanced without overflow.
306    #[error("ledger generation {generation} cannot be advanced without overflow")]
307    GenerationOverflow {
308        /// Current ledger generation.
309        generation: u64,
310    },
311    /// Reservation count exceeds the usable allocation-slot domain.
312    #[error("generation contains {count} reservations, exceeding the 255-allocation limit")]
313    TooManyReservations {
314        /// Number of reservations in the staged generation.
315        count: usize,
316    },
317    /// A staged reservation carries invalid schema metadata.
318    #[error("stable key '{stable_key}' has invalid schema metadata")]
319    InvalidSchemaMetadata {
320        /// Stable key whose schema metadata is invalid.
321        stable_key: StableKey,
322        /// Schema metadata validation error.
323        error: SchemaMetadataError,
324    },
325    /// A staged reservation declaration violates declaration invariants.
326    #[error("reservation declaration is invalid")]
327    InvalidDeclaration(#[source] DeclarationSnapshotError),
328    /// Stable key was historically bound to a different slot.
329    #[error("stable key '{stable_key}' was historically bound to a different allocation slot")]
330    StableKeySlotConflict {
331        /// Stable key being reserved.
332        stable_key: StableKey,
333        /// Historical slot for the stable key.
334        historical_slot: Box<AllocationSlotDescriptor>,
335        /// Slot claimed by the reservation.
336        reserved_slot: Box<AllocationSlotDescriptor>,
337    },
338    /// Slot was historically bound to a different stable key.
339    #[error("allocation slot '{slot:?}' was historically bound to stable key '{historical_key}'")]
340    SlotStableKeyConflict {
341        /// Slot being reserved.
342        slot: Box<AllocationSlotDescriptor>,
343        /// Historical stable key for the slot.
344        historical_key: StableKey,
345        /// Stable key claimed by the reservation.
346        reserved_key: StableKey,
347    },
348    /// Allocation already exists as an active record.
349    #[error("stable key '{stable_key}' is already active and cannot be reserved")]
350    ActiveAllocation {
351        /// Active stable key.
352        stable_key: StableKey,
353        /// Active allocation slot.
354        slot: Box<AllocationSlotDescriptor>,
355    },
356    /// Allocation was already retired and cannot be reserved.
357    #[error("stable key '{stable_key}' was explicitly retired and cannot be reserved")]
358    RetiredAllocation {
359        /// Retired stable key.
360        stable_key: StableKey,
361        /// Retired allocation slot.
362        slot: Box<AllocationSlotDescriptor>,
363    },
364}
365
366///
367/// AllocationRetirementError
368///
369/// Failure to stage an explicit retirement generation.
370#[non_exhaustive]
371#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
372pub enum AllocationRetirementError {
373    #[error(transparent)]
374    Integrity(#[from] LedgerIntegrityError),
375    /// Stable-key grammar failure.
376    #[error(transparent)]
377    Key(StableKeyError),
378    /// Allocation slot validation failure.
379    #[error(transparent)]
380    MemoryManagerSlot(MemoryManagerSlotError),
381    /// Ledger generation cannot be advanced without overflow.
382    #[error("ledger generation {generation} cannot be advanced without overflow")]
383    GenerationOverflow {
384        /// Current ledger generation.
385        generation: u64,
386    },
387    /// Stable key has no historical allocation record.
388    #[error("stable key '{0}' has no allocation record to retire")]
389    UnknownStableKey(StableKey),
390    /// Stable key was historically bound to a different slot.
391    #[error("stable key '{stable_key}' cannot be retired for a different allocation slot")]
392    SlotMismatch {
393        /// Stable key being retired.
394        stable_key: StableKey,
395        /// Historical slot for the stable key.
396        historical_slot: Box<AllocationSlotDescriptor>,
397        /// Slot named by the retirement request.
398        retired_slot: Box<AllocationSlotDescriptor>,
399    },
400    /// Allocation was already retired.
401    #[error("stable key '{stable_key}' was already retired")]
402    AlreadyRetired {
403        /// Retired stable key.
404        stable_key: StableKey,
405        /// Retired allocation slot.
406        slot: Box<AllocationSlotDescriptor>,
407    },
408}