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