Skip to main content

ic_memory/ledger/
error.rs

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