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