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