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