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